实现类WhatsApp图片多选功能:相册列表与选中照片追踪需求咨询
Hey there! Let's tackle your two photo gallery features—accessing all albums with photo previews, and building a WhatsApp-style multi-select image picker. I'll walk you through the core implementation steps with code snippets to make this concrete.
First, you'll need to handle media permissions to access the user's photos. On Android 13+, request the READ_MEDIA_IMAGES permission; for older versions, use READ_EXTERNAL_STORAGE.
Step 1: Fetch all albums
Use the ContentResolver to query the media store and group images by album (bucket name). Here's a Kotlin snippet for that:
fun fetchAlbums(context: Context): List<Album> { val albums = mutableListOf<Album>() val projection = arrayOf( MediaStore.Images.Media.BUCKET_DISPLAY_NAME, MediaStore.Images.Media.BUCKET_ID, MediaStore.Images.Media._ID // For album thumbnail ) val selection = "${MediaStore.Images.Media.MIME_TYPE} IN ('image/jpeg', 'image/png')" val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC" context.contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, null, sortOrder )?.use { cursor -> val bucketNameCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_DISPLAY_NAME) val bucketIdCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.BUCKET_ID) val idCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) val albumMap = mutableMapOf<String, Album>() while (cursor.moveToNext()) { val bucketName = cursor.getString(bucketNameCol) val bucketId = cursor.getString(bucketIdCol) val thumbnailUri = ContentUris.withAppendedId( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(idCol) ) albumMap.getOrPut(bucketId) { Album(bucketId, bucketName, thumbnailUri, 0) }.photoCount++ } albums.addAll(albumMap.values) } return albums } data class Album( val id: String, val name: String, val thumbnailUri: Uri, var photoCount: Int )
Step 2: Load photos when an album is clicked
When the user taps an album, query all images in that specific bucket:
fun fetchPhotosInAlbum(context: Context, bucketId: String): List<Uri> { val photos = mutableListOf<Uri>() val projection = arrayOf(MediaStore.Images.Media._ID) val selection = "${MediaStore.Images.Media.BUCKET_ID} = ? AND ${MediaStore.Images.Media.MIME_TYPE} IN ('image/jpeg', 'image/png')" val selectionArgs = arrayOf(bucketId) val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC" context.contentResolver.query( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, selection, selectionArgs, sortOrder )?.use { cursor -> val idCol = cursor.getColumnIndexOrThrow(MediaStore.Images.Media._ID) while (cursor.moveToNext()) { val photoUri = ContentUris.withAppendedId( MediaStore.Images.Media.EXTERNAL_CONTENT_URI, cursor.getLong(idCol) ) photos.add(photoUri) } } return photos }
Then display these URIs in a RecyclerView or GridView using image loading libraries like Glide or Coil for smooth previews.
This builds on the album/photo fetch logic, but adds multi-select tracking and interactive UI state.
Step 1: Track selected photos
Create a mutable collection to hold selected photo URIs (or custom Photo objects if you need more metadata):
private val selectedPhotos = mutableListOf<Uri>()
Step 2: Update UI for selection state
In your photo list item layout, add a selection indicator (like WhatsApp's circular checkmark). When an item is clicked, toggle its selection status:
fun onPhotoClicked(photoUri: Uri, itemView: View) { if (selectedPhotos.contains(photoUri)) { selectedPhotos.remove(photoUri) itemView.selectionIndicator.isVisible = false itemView.photoOverlay.alpha = 0f // Remove semi-transparent overlay } else { selectedPhotos.add(photoUri) itemView.selectionIndicator.isVisible = true itemView.photoOverlay.alpha = 0.3f // Add overlay to mark selection } // Update toolbar counter (e.g., "3 selected") updateSelectionCounter(selectedPhotos.size) }
Step 3: Handle batch actions
Add a toolbar or bottom sheet to let users confirm their selection. For example, a "Done" button that passes the selected photos to the next screen:
binding.btnDone.setOnClickListener { val resultIntent = Intent().apply { putParcelableArrayListExtra("SELECTED_PHOTOS", ArrayList(selectedPhotos)) } setResult(Activity.RESULT_OK, resultIntent) finish() }
Bonus: Optimize selection UI
- Match WhatsApp's style: Use a circular checkmark with a filled background for selected items
- Add a maximum selection limit (WhatsApp allows up to 30 photos/videos)
- Include a "Select All" option for albums with large numbers of photos
- Persist selection state if the user navigates back to the album list
Quick note for iOS developers
On iOS, use PHAsset and PHAssetCollection to fetch albums and photos. For multi-select, initialize PHPickerViewController with PHPickerConfiguration(selectionLimit: 0) (unlimited selection) and track selected assets via the delegate method picker(_:didFinishPicking:).
内容的提问来源于stack exchange,提问作者VIJAY SINGH RAGHAV

