简体   繁体   English

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

[英]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. 现在让我们看看其他文件,从最简单可行的解决方案开始。

First solution (XML only) 第一个解决方案(仅限XML)

layout/item.xml 布局/ item.xml

The two important attributes here in the item's root ViewGroup are background and clickable . 项目根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>

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>

Second solution (XML + Java) 第二个解决方案(XML + Java)

item.xml item.xml

No background nor clickable attribute here. 此处没有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 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.

相关问题 如何在“回收者”视图中突出显示选定的项目 - How to Highlight the selected item in Recycler view 如何在 RecyclerView 中选择和取消选择一个项目? 如何仅在回收站视图中突出显示所选项目? - how to select and de-select an item in RecyclerView? How to Highlight selected item only in recycler view? 如何通过位置android在回收器视图中突出显示项目 - How to highlight a item in recycler view by position android 如何设置“回收者视图”中所选项目的颜色? - how to set color the selected Item of Recycler View? 如何像Instagram一样在Drag / Touch上突出显示Recycler视图项? - How to Highlight the Recycler view Item on Drag/Touch like Instagram? 检查回收站视图中的项目是否已选中 - Check if the item in recycler view selected 回收商查看中心选定的项目 - recycler view center selected item 如何选择回收商视图中的项目并将项目位置获取到我的活动 - How a item in recycler view is selected and get the item position to my activity 选择时如何将项目设置为回收站视图的中心 - How to set item to center of Recycler view when selected 如何在Recycler视图中更改所选项目的文本颜色 - how to change the text color of selected item inside recycler view
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM