[英]how to highlight the selected Item of Recycler View?
I have a Recycler View with the Images loaded from the Internal Storage. 我有一个Recycler View,其中包含从内部存储加载的图像。 I want to Highlight the selected item when clicked. 我想点击时突出显示所选项目。 I tried a lot of thing but it was not working. 我尝试了很多东西,但它没有用。 Actually what I need is when I click any item in Recycler View that Item must go in My ArrayList and it should also get highlighted and again when I click or say unselect it must again become normal. 实际上我需要的是当我点击Recycler View中的任何项目时,Item必须进入My ArrayList,它也应该突出显示,当我点击或说取消选择时它必须再次变为正常。 Here is my Code: 这是我的代码:
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;
}
}
This is my Adapter Class: 这是我的适配器类:
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);
}
}
You can use a StateListDrawable to achieve the desired effect. 您可以使用StateListDrawable来实现所需的效果。
Example 例
Create a new Drawable resource file in your drawable
directory with the following content: 使用以下内容在drawable
目录中创建一个新的Drawable资源文件 :
selector_row.xml 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>
Now simply use this StateListDrawable
as the background in the row-layout of your RecyclerView
现在只需使用此StateListDrawable
作为RecyclerView
的行布局中的背景
row_recyclerview.xml 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>
Now as soon as the onClick()
method in your adapter is called you simply need to do the following: 现在,只要调用适配器中的onClick()
方法,您只需执行以下操作:
// myBackground is the RelativeLayout root of your row
myBackground.setSelected(true);
The rows' background will have the color (in this case darker_gray ) as long as you call myBackground.setSelected(false)
. 该行的背景将有颜色(在这种情况下darker_gray),只要您拨打myBackground.setSelected(false)
。 Of course you should create a SparseBooleanArray for example in order to know which row is selected and which isn't since the rows will be reused when scrolling. 当然,您应该创建一个SparseBooleanArray ,以便知道哪个行被选中,哪个不行,因为滚动时将重复使用这些行。
Edit: Remember selected items 编辑:记住所选项目
The idea behind the SparseBooleanArray is to remember the items which are selected. SparseBooleanArray背后的想法是记住所选的项目。 Following a sample on how to use it: 下面是如何使用它的示例:
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);
}
}
}
}
there is no selector in RecyclerView like ListView and GridView but you try below thing it worked for me 在RecyclerView中没有像ListView和GridView那样的选择器,但你尝试下面对我有用的东西
create a selector drawable as below 创建一个drawable选择器,如下所示
<?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>
then set this drawable as background of your RecyclerView row layout as 然后将此drawable设置为RecyclerView行布局的背景
android:background="@drawable/selector"
You can add this to your row_item.xml 您可以将其添加到row_item.xml
android:clickable="true"
android:background="?attr/selectableItemBackground"
For example: 例如:
<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 -->
If android version is Lolipop or greater, selector comes with ripple. 如果Android版本是Lolipop或更高版本,选择器带有涟漪。 And a highlight for other version. 其他版本的亮点。 Hope it helps 希望能帮助到你
I have tried several ways for hours and here is the two solutions I came out with. 我已经尝试了好几个小时,这是我提出的两个解决方案。 Both solutions assume I have my RecyclerView
declared as follows: 两种解决方案都假设我的RecyclerView
声明如下:
activity.xml 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" />
Nothing special here, just a regular RecyclerView
declaration. 这里没什么特别的,只是一个常规的RecyclerView
声明。 Now let's see the other files, starting with the most easy and viable solution. 现在让我们看看其他文件,从最简单可行的解决方案开始。
layout/item.xml 布局/ item.xml
The two important attributes here in the item's root ViewGroup
are background
and clickable
. 项目根ViewGroup
中的两个重要属性是background
和clickable
。
<?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>
drawable/selector_item.xml 绘制/ 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>
item.xml item.xml
No background
nor clickable
attribute here. 此处没有background
或clickable
属性。
<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 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;
}
};
...
}
I highly recommend using the first solution as it's easier to maintain and more powerful as it also allows you to add ripple effects (in the drawable/background_item...
XML files), which I believe isn't possible with solution 2. 我强烈建议使用第一个解决方案,因为它更容易维护和更强大,因为它还允许您添加涟漪效果(在drawable/background_item...
XML文件中),我认为这是解决方案2无法实现的。
you can use this code out of Adapter 您可以使用适配器中的此代码
LinearLayoutManager RvLayoutManager = (LinearLayoutManager)rootlayout.getLayoutManager();
View itemSelected = RvLayoutManager.findViewByPosition(position);
itemSelected.setBackgroundColor(Color.Red);
You should create a selector drawable with android:state_focused="true"
attribute as below 您应该使用android:state_focused="true"
属性创建一个可绘制的选择器,如下所示
<?xml version="1.0" encoding="utf-8"?>
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:drawable="@color/colorAccent"
android:state_focused="true" />
</selector>
</item>
</ripple>
then set this drawable as background of your RecyclerView row layout as 然后将此drawable设置为RecyclerView行布局的背景
android:background="@drawable/selector"
If you manage to use an observable pattern flavor such as Otto or AndroidRx, you can follow how to highlight the background as explained above, and for each viewHolder's itemView you can subscribe to the observable and unsubscribe when it detaches from your recyclerview like I did here: 如果您设法使用可观察的模式风格,如Otto或AndroidRx,您可以按照上面的说明关注如何突出显示背景,并且对于每个viewHolder的itemView,您可以订阅observable并取消订阅,当它与您在此处回收时一样:
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 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
By the way for a quick demo my itemView is using linearLayout, so it was easy to set background color as yellow. 顺便说一下,我的itemView使用linearLayout进行快速演示,因此很容易将背景颜色设置为黄色。
This solution is more of an interactive look like the tableView in IOS. 此解决方案更像是IOS中的tableView之类的交互式外观。 It'll highlight then unhighlight the cells. 它会突出显示然后不突出细胞。
@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;
}
});
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.