实现RecyclerView点击选图(相机/图库)及自定义列表项功能
Got it, let's work through these two RecyclerView image tasks together—they're pretty straightforward once you break them down. I'll share code snippets and explanations that you can adapt directly to your project.
Requirement 1: Pick Image from Camera/Gallery on RecyclerView Item Click
First, we need to handle item clicks, show a selection dialog, then process the chosen image to update the list item.
Step 1: Set Up Permissions & File Provider (for Camera)
For Android 7.0+, you need a file provider to safely capture camera images. Add these to your AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" /> <uses-permission android:name="android.permission.READ_MEDIA_IMAGES" /> <!-- For API 33+ --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32" /> <application ...> <provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
Create res/xml/file_paths.xml to define where camera images are stored:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-files-path name="camera_images" path="Pictures" /> </paths>
Step 2: Handle Item Clicks & Selection Dialog
In your activity/fragment, set up the RecyclerView click listener and show a dialog for camera/gallery selection:
// Inside your Activity/Fragment private val REQUEST_CAMERA = 100 private val REQUEST_GALLERY = 200 private var cameraImageUri: Uri? = null private var clickedItemPosition = 0 // Set up RecyclerView adapter with click listener myRecyclerView.adapter = ImageAdapter(imageList) { position -> clickedItemPosition = position val options = arrayOf("Take Photo", "Choose from Gallery") AlertDialog.Builder(this) .setTitle("Select Image Source") .setItems(options) { _, which -> when (which) { 0 -> openCamera() 1 -> openGallery() } } .show() } // Open camera to capture image private fun openCamera() { val imageFile = File(externalMediaDirs[0], "camera_${System.currentTimeMillis()}.jpg") cameraImageUri = FileProvider.getUriForFile(this, "${packageName}.fileprovider", imageFile) val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE).apply { putExtra(MediaStore.EXTRA_OUTPUT, cameraImageUri) addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION) } startActivityForResult(intent, REQUEST_CAMERA) } // Open gallery to pick image private fun openGallery() { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) startActivityForResult(intent, REQUEST_GALLERY) } // Handle image selection result (use ActivityResultContracts for API 33+) override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == RESULT_OK) { when (requestCode) { REQUEST_CAMERA -> { cameraImageUri?.let { uri -> imageList[clickedItemPosition] = uri.toString() myRecyclerView.adapter?.notifyItemChanged(clickedItemPosition) } } REQUEST_GALLERY -> { data?.data?.let { uri -> imageList[clickedItemPosition] = uri.toString() myRecyclerView.adapter?.notifyItemChanged(clickedItemPosition) } } } } }
Step 3: Adapter to Display Images
Create a basic adapter to load images (replace setImageURI with Glide/Picasso for better performance):
class ImageAdapter( private val imageList: MutableList<String>, private val onItemClick: (Int) -> Unit ) : RecyclerView.Adapter<ImageAdapter.ImageViewHolder>() { inner class ImageViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val itemImage: ImageView = itemView.findViewById(R.id.item_image) } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ImageViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.recycler_item_image, parent, false) return ImageViewHolder(view) } override fun onBindViewHolder(holder: ImageViewHolder, position: Int) { val imageUri = imageList[position] if (imageUri.isNotEmpty()) { holder.itemImage.setImageURI(Uri.parse(imageUri)) } else { holder.itemImage.setImageResource(R.drawable.ic_default_placeholder) } holder.itemView.setOnClickListener { onItemClick(position) } } override fun getItemCount(): Int = imageList.size }
Requirement 2: Special First & Second List Items
We’ll tweak the adapter to handle position-specific behavior for the first two items:
Step 1: Update Adapter Logic
Modify onBindViewHolder to make the first item a gallery-only add button, and set the second item’s default background to the add icon:
override fun onBindViewHolder(holder: ImageViewHolder, position: Int) { when (position) { 0 -> { // First item: Show add icon until image is selected if (imageList[position].isEmpty()) { holder.itemImage.setImageResource(R.drawable.ic_add_image) } else { holder.itemImage.setImageURI(Uri.parse(imageList[position])) } // First item click: Only open gallery holder.itemView.setOnClickListener { val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI) (holder.itemView.context as YourActivity).startActivityForResult(intent, REQUEST_GALLERY_FIRST_ITEM) } } 1 -> { // Second item: Default to add icon, use regular click logic when tapped if (imageList[position].isEmpty()) { holder.itemImage.setImageResource(R.drawable.ic_add_image) } else { holder.itemImage.setImageURI(Uri.parse(imageList[position])) } holder.itemView.setOnClickListener { onItemClick(position) } } else -> { // Regular items: Use default placeholder if (imageList[position].isEmpty()) { holder.itemImage.setImageResource(R.drawable.ic_default_placeholder) } else { holder.itemImage.setImageURI(Uri.parse(imageList[position])) } holder.itemView.setOnClickListener { onItemClick(position) } } } }
Step 2: Handle First Item’s Gallery Result
Add a new request code in your activity to update the first item:
private val REQUEST_GALLERY_FIRST_ITEM = 300 override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { super.onActivityResult(requestCode, resultCode, data) if (resultCode == RESULT_OK) { when (requestCode) { // ... existing cases ... REQUEST_GALLERY_FIRST_ITEM -> { data?.data?.let { uri -> imageList[0] = uri.toString() myRecyclerView.adapter?.notifyItemChanged(0) } } } } }
Quick Tips
- Replace
R.drawable.ic_add_imageandR.drawable.ic_default_placeholderwith your actual drawables. - Use Glide for smoother image loading (replace
setImageURI):Glide.with(holder.itemImage.context) .load(imageUri) .placeholder(R.drawable.ic_add_image) .into(holder.itemImage) - Don’t forget to request runtime permissions for camera and storage on API 23+.
内容的提问来源于stack exchange,提问作者Malek Alzein

