how to highlight the selected Item of Recycler View?

拈花ヽ惹草 提交于 2019-12-17 06:24:23

问题


I have a Recycler View with the Images loaded from the Internal Storage. 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. 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);
    }
}

回答1:


You can use a StateListDrawable to achieve the desired effect.

Example

Create a new Drawable resource file in your drawable directory with the following content:

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

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:

// 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). 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.

Edit: Remember selected items
The idea behind the SparseBooleanArray is to remember the items which are selected. 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);
              }
        }
    }
}



回答2:


there is no selector in RecyclerView like ListView and GridView but you try below thing it worked for me

create a selector drawable as below

<?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

android:background="@drawable/selector"



回答3:


You can add this to your 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. And a highlight for other version. Hope it helps




回答4:


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:

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. Now let's see the other files, starting with the most easy and viable solution.

First solution (XML only)

layout/item.xml

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

<?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)

item.xml

No background nor clickable attribute here.

<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;
        }
    };

    ...
}

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.




回答5:


you can use this code out of Adapter

LinearLayoutManager RvLayoutManager = (LinearLayoutManager)rootlayout.getLayoutManager();
View itemSelected = RvLayoutManager.findViewByPosition(position);
itemSelected.setBackgroundColor(Color.Red);



回答6:


You should create a selector drawable with android:state_focused="true" attribute as below

<?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

android:background="@drawable/selector"



回答7:


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:

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.




回答8:


This solution is more of an interactive look like the tableView in IOS. 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;
            }
        });
    }
}


来源:https://stackoverflow.com/questions/29983848/how-to-highlight-the-selected-item-of-recycler-view

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!