如何为RecyclerView中的TextView添加点击事件并修改选中TextView的背景
Hey there! Let me walk you through exactly how to set up click events for TextViews in your RecyclerView and toggle their background styles when selected. This is a super common pattern, so I’ll break it down into easy-to-follow steps.
Step 1: Create Background Drawables for Selected/Unselected States
First, you’ll want to define two drawable resources to represent the selected and unselected backgrounds—this makes styling clean and reusable.
Create res/drawable/tv_selected_bg.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#2196F3" /> <!-- Blue background for selected --> <corners android:radius="4dp" /> </shape>
Create res/drawable/tv_unselected_bg.xml:
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#FFFFFF" /> <!-- White background for unselected --> <stroke android:color="#E0E0E0" android:width="1dp"/> <corners android:radius="4dp" /> </shape>
Step 2: Modify Your RecyclerView Adapter
Next, we’ll update the Adapter to handle click events and track the selected position. Here’s how to do it:
Key Changes:
- Add a variable to track the currently selected position
- Attach a click listener to the TextView in your ViewHolder
- Update the selected position and refresh the UI when clicked
- Set the correct background in
onBindViewHolderbased on the selected state
Full Adapter Example (Java):
public class YourAdapter extends RecyclerView.Adapter<YourAdapter.ViewHolder> { private List<String> itemList; private int selectedPosition = -1; // -1 means no item selected initially public YourAdapter(List<String> itemList) { this.itemList = itemList; } @NonNull @Override public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.your_item_layout, parent, false); return new ViewHolder(view); } @Override public void onBindViewHolder(@NonNull ViewHolder holder, int position) { String item = itemList.get(position); holder.tvItem.setText(item); // Set background based on selected state if (selectedPosition == position) { holder.tvItem.setBackgroundResource(R.drawable.tv_selected_bg); holder.tvItem.setTextColor(Color.WHITE); // Optional: Change text color too } else { holder.tvItem.setBackgroundResource(R.drawable.tv_unselected_bg); holder.tvItem.setTextColor(Color.BLACK); } } @Override public int getItemCount() { return itemList.size(); } public class ViewHolder extends RecyclerView.ViewHolder { TextView tvItem; public ViewHolder(@NonNull View itemView) { super(itemView); tvItem = itemView.findViewById(R.id.tv_item); // Set click listener on the TextView tvItem.setOnClickListener(v -> { // Update selected position int previousPosition = selectedPosition; selectedPosition = getAdapterPosition(); // Notify both previous and current positions to refresh UI notifyItemChanged(previousPosition); notifyItemChanged(selectedPosition); // Optional: Handle any additional logic when the item is clicked // Toast.makeText(v.getContext(), "Selected: " + itemList.get(selectedPosition), Toast.LENGTH_SHORT).show(); }); } } }
Full Adapter Example (Kotlin):
class YourAdapter(private val itemList: List<String>) : RecyclerView.Adapter<YourAdapter.ViewHolder>() { private var selectedPosition = -1 override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder { val view = LayoutInflater.from(parent.context) .inflate(R.layout.your_item_layout, parent, false) return ViewHolder(view) } override fun onBindViewHolder(holder: ViewHolder, position: Int) { val item = itemList[position] holder.tvItem.text = item holder.tvItem.setBackgroundResource( if (selectedPosition == position) R.drawable.tv_selected_bg else R.drawable.tv_unselected_bg ) holder.tvItem.setTextColor( if (selectedPosition == position) Color.WHITE else Color.BLACK ) } override fun getItemCount() = itemList.size inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) { val tvItem: TextView = itemView.findViewById(R.id.tv_item) init { tvItem.setOnClickListener { val previousPosition = selectedPosition selectedPosition = adapterPosition notifyItemChanged(previousPosition) notifyItemChanged(selectedPosition) // Optional: Add your click logic here // Toast.makeText(itemView.context, "Selected: ${itemList[selectedPosition]}", Toast.LENGTH_SHORT).show() } } } }
Step 3: Verify Your Item Layout
Make sure your item layout (your_item_layout.xml) includes the TextView with a matching ID (adjust the ID in the Adapter if yours is different):
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="16dp"> <TextView android:id="@+id/tv_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textSize="16sp" android:padding="8dp"/> </LinearLayout>
Extra Tips
- Multi-selection: If you need to allow selecting multiple items, replace the
selectedPositionint with aMutableSet<Int>to track all selected positions. Then inonBindViewHolder, check if the current position is in the set. - Performance: Using
notifyItemChanged(previousPosition)andnotifyItemChanged(selectedPosition)is more efficient than callingnotifyDataSetChanged(), since it only refreshes the affected items. - Accessibility: Consider adding focus states to your drawables to improve accessibility for users navigating with a keyboard or screen reader.
内容的提问来源于stack exchange,提问作者Suryansh Singh Rajput

