如何突出显示Recycler View的选定项目?

从内部存储器加载的图像中有一个Recycler View。 我想单击时突出显示所选项目。 我尝试了很多东西,但没有成功。 其实我需要的是,当我点击Recycler View中的任何项目,项目必须在我的ArrayList中,它也应该突出显示,当我点击或说取消select它必须再次成为正常。 这是我的代码:

public class Images extends Fragment { private List<ImageHolder> imageList; Cursor imageCursor; RecyclerView recyclerView; MyImageAdapter adapter; ActionButton clickButton; List<String> listofImages; List<Integer> pos; int columnIndex; StringBuilder stringBuilder; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View rootlayout = inflater.inflate(R.layout.image, container, false); listofImages=new ArrayList<String>(); pos=new ArrayList<Integer>(); stringBuilder=new StringBuilder(); ContentResolver imageResolver = getActivity().getContentResolver(); Uri imageUri = android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI; String projection[]={MediaStore.Images.Thumbnails._ID,MediaStore.Images.Media.TITLE}; imageCursor = getActivity().managedQuery(imageUri, projection, null, null, null); clickButton= (ActionButton) rootlayout.findViewById(R.id.action_button); recyclerView = (RecyclerView) rootlayout.findViewById(R.id.recycler_view_image); adapter = new MyImageAdapter(getActivity(), getImageList()); recyclerView.setAdapter(adapter); recyclerView.setLayoutManager(new LinearLayoutManager(getActivity())); recyclerView.addOnItemTouchListener(new RecyclerTouchListener(getActivity(),recyclerView,new RecyclerTouchListener.ClickListener() { @Override public void onClick(View view, int position) { TextView tv= (TextView) view.findViewById(R.id.list_text_all); int flag=0; String[] projection = {MediaStore.Images.Media.DATA}; imageCursor = getActivity().managedQuery(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null, null); columnIndex = imageCursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA); imageCursor.moveToPosition(position); // Get image filename String imagePath = imageCursor.getString(columnIndex); if (listofImages.contains(imagePath)){ Log.d("Contains Test","Yes"); listofImages.remove(imagePath); pos.remove(position); } else { listofImages.add(imagePath); pos.add(position); Log.d("Contains Test","No"); } String s=listofImages.size()+" "+imagePath; Log.d("Inserted",s); } @Override public void onLongClick(View view, int position) {} })); clickButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { for (int i=0;i<listofImages.size();i++){ stringBuilder.append(listofImages.get(i)+"\n"); } Toast.makeText(getActivity(),stringBuilder,Toast.LENGTH_LONG).show(); } }); return rootlayout; } public List<ImageHolder> getImageList() { imageList=new ArrayList<ImageHolder>(); if(imageCursor!=null && imageCursor.moveToFirst()){ int titleColumn = imageCursor.getColumnIndex (android.provider.MediaStore.Images.Media.TITLE); int idColumn = imageCursor.getColumnIndex (android.provider.MediaStore.Images.Media._ID); do { ImageHolder img=new ImageHolder(); img.id=imageCursor.getLong(idColumn); img.title=imageCursor.getString(titleColumn); img.iconid= imageCursor.getInt(idColumn); imageList.add(img); } while (imageCursor.moveToNext()); } return imageList; } } 

这是我的适配器类:

 public class MyImageAdapter extends RecyclerView.Adapter<MyImageAdapter.MyViewHolder> { Context context; private LayoutInflater inflater; List<ImageHolder> data= Collections.emptyList(); private ClickListener clickListener; int width,height; public MyImageAdapter(Context context, List<ImageHolder> data1) { inflater = LayoutInflater.from(context); this.data=data1; this.context=context; } @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = inflater.inflate(R.layout.all_row, parent, false); MyViewHolder holder=new MyViewHolder(view); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { try{ ImageHolder current=data.get(position); holder.title.setText(current.title); Log.d("Imageid:"+current.iconid,""); Uri IMAGE_URI = Uri.withAppendedPath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "" + current.iconid); Bitmap bitmap = Bitmap.createScaledBitmap(decodeUri(IMAGE_URI), 200, 200, true); holder.img.setImageBitmap(bitmap); } catch(Exception e){} } public void deleteRecyclerData(int position){ data.remove(position); notifyItemRemoved(position); } private Bitmap decodeUri(Uri selectedImage) throws FileNotFoundException { BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream( context.getContentResolver().openInputStream(selectedImage), null, o); final int REQUIRED_SIZE = 100; int width_tmp = o.outWidth, height_tmp = o.outHeight; int scale = 1; while (true) { if (width_tmp / 2 < REQUIRED_SIZE || height_tmp / 2 < REQUIRED_SIZE) { break; } width_tmp /= 2; height_tmp /= 2; scale *= 2; } BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize = scale; return BitmapFactory.decodeStream( context.getContentResolver().openInputStream(selectedImage), null, o2); } @Override public int getItemCount() { return data.size(); } public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ TextView title; // TextView artist; ImageView img; CheckBox checkBox; public MyViewHolder(View itemView) { super(itemView); title= (TextView) itemView.findViewById(R.id.list_text_all); img= (ImageView) itemView.findViewById(R.id.list_image_all); img.setOnClickListener(this); } @Override public void onClick(View v) {} } public interface ClickListener{ public void itemClicked(View view, int position); } } 

您可以使用StateListDrawable来达到预期的效果。

使用以下内容在drawable目录中创build一个新的Drawable资源文件

selector_row.xml

 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <!-- Color when the row is selected --> <item android:drawable="@android:color/darker_gray" android:state_pressed="false" android:state_selected="true" /> <!-- Standard background color --> <item android:drawable="@android:color/white" android:state_selected="false" /> </selector> 

现在只需使用这个StateListDrawable作为您的RecyclerView的行布局的背景

row_recyclerview.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/selector_row"> <!-- row content --> </RelativeLayout> 

现在,只要您的适配器中的onClick()方法被调用,您只需执行以下操作:

 // myBackground is the RelativeLayout root of your row myBackground.setSelected(true); 

只要您调用myBackground.setSelected(false) ,行的背景将具有颜色(在本例中为myBackground.setSelected(false) 。 当然,你应该创build一个SparseBooleanArray ,例如为了知道哪一行被选中,哪一行不是,因为这些行将在滚​​动时被重用。

编辑:记住选定的项目
SparseBooleanArray背后的想法是记住被选中的项目。 以下是关于如何使用它的示例:

 public class MyImageAdapter extends RecyclerView.Adapter<MyImageAdapter.MyViewHolder> { private SparseBooleanArray selectedItems; // Other stuff [...] @Override public void onBindViewHolder(MyViewHolder holder, int position) { // Set the selected state of the row depending on the position holder.myBackground.setSelected(selectedItems.get(position, false)); } public class MyViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{ @Override public void onClick(View v) { // Save the selected positions to the SparseBooleanArray if (selectedItems.get(getAdapterPosition(), false)) { selectedItems.delete(getAdapterPosition()); myBackground.setSelected(false); } else { selectedItems.put(getAdapterPosition(), true); myBackground.setSelected(true); } } } } 

在RecyclerView中没有像ListView和GridView那样的select器,但是你可以在下面试试它为我工作的东西

创build一个如下所示的select器

 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true"> <shape> <solid android:color="@color/blue" /> </shape> </item> <item android:state_pressed="false"> <shape> <solid android:color="@android:color/transparent" /> </shape> </item> </selector> 

然后将此可绘制设置为您的RecyclerView行布局的背景

 android:background="@drawable/selector" 

你可以添加到你的row_item.xml

 android:clickable="true" android:background="?attr/selectableItemBackground" 

例如:

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:clickable="true" android:background="?attr/selectableItemBackground" <!-- row content --> 

如果Android版本是Lolipop或更大,select器带有波纹。 而其他版本的亮点。 希望能帮助到你

我已经尝试了几个小时的方法,这是我提出的两个解决scheme。 两种解决scheme都假定我已经声明了我的RecyclerView ,如下所示:

activity.xml

 <android.support.v7.widget.RecyclerView android:id="@+id/list" android:layout_height="match_parent" android:layout_width="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 

这里没什么特别的,只是一个普通的RecyclerView声明。 现在让我们看看其他文件,从最简单和可行的解决scheme开始。

第一个解决scheme(仅限XML)

布局/ item.xml

项目根ViewGroup中的两个重要属性是backgroundclickable

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:background="@drawable/selector_item" android:clickable="true" android:gravity="center" android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="horizontal" android:padding="16dp"> ... </LinearLayout> 

绘制/ selector_item.xml

 <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/background_item_pressed" android:state_pressed="true" /> <item android:drawable="@drawable/background_item" /> </selector> 

第二个解决scheme(XML + Java)

item.xml

此处没有backgroundclickable属性。

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:gravity="center" android:layout_height="wrap_content" android:layout_width="match_parent" android:orientation="horizontal" android:padding="16dp"> ... </LinearLayout> 

Adapter.java

 public class Adapter extends RecyclerView.Adapter<Adapter.ViewHolder> { public class ViewHolder extends RecyclerView.ViewHolder { public ViewHolder(View itemView) { super(itemView); itemView.setOnTouchListener(itemTouchListener); } } ... private View.OnTouchListener itemTouchListener = new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: v.setBackgroundResource(R.drawable.background_item_event_pressed); break; case MotionEvent.ACTION_CANCEL: // CANCEL triggers when you press the view for too long // It prevents UP to trigger which makes the 'pressed' background permanent which isn't what we want case MotionEvent.ACTION_OUTSIDE: // OUTSIDE triggers when the user's finger moves out of the view case MotionEvent.ACTION_UP: v.setBackgroundResource(R.drawable.background_item_event); break; default: break; } return true; } }; ... } 

我强烈build议使用第一个解决scheme,因为它更容易维护,function也更强大,因为它还允许添加涟漪效应(在drawable/background_item... XML文件中),我认为解决scheme2是无法实现的。

如果您设法使用可观察的模式风格,如Otto或AndroidRx,您可以按照如上所述的方式来突出显示背景,并且对于每个viewHolder的itemView,您可以订阅observable并取消订阅,如同我在此处从recyclerview分离:

https://github.com/juanmendez/jm_android_dev/blob/master/01.fragments/06.fragments_with_rx/app/src/main/java/info/juanmendez/android/recyclerview/ui/listing/recyclerview/CountryHolder.java# L49

顺便说一下,我的itemView使用linearLayout进行快速演示,所以很容易将背景颜色设置为黄色。

在这里输入图像说明

这个解决scheme更像是IOS中的tableView的交互式外观。 它会突出显示然后不注意细胞。

 @Override public void onBindViewHolder(Cell holder, final int position) { if(requests != null) { holder.setView(requests.get(position), context); holder.itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(final View v) { Logs.print("In OnClickListener", position + " selected"); } }); holder.itemView.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View v, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: Logs.print("In Touch Handler", "A press has started"); v.setSelected(true); break; case MotionEvent.ACTION_UP: Logs.print("In Touch Handler", "A press has been completed"); v.setSelected(false); break; case MotionEvent.ACTION_CANCEL: Logs.print("In Touch Handler", "gesture aborted"); v.setSelected(false); break; } return true; } }); } }