web-dev-qa-db-fra.com

Comment mettre en évidence l'élément sélectionné de la vue Recycler?

J'ai une vue Recycler avec les images chargées à partir de la mémoire interne. Je veux mettre en surbrillance l'élément sélectionné lorsque vous cliquez dessus. J'ai essayé beaucoup de choses mais cela ne fonctionnait pas. En fait, ce dont j'ai besoin, c’est que lorsque je clique sur un élément de la vue Recycler, cet élément doit figurer dans Mon ArrayList. Voici mon 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;
    }
}

Ceci est ma classe d'adaptateur:

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);
    }
}
48
Kuldeep Dubey

Vous pouvez utiliser un StateListDrawable pour obtenir l'effet souhaité.

Exemple

Créez un nouveau fichier de ressources Drawable dans votre répertoire drawable avec le contenu suivant:

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>

Maintenant, utilisez simplement ce StateListDrawable comme arrière-plan de la disposition des lignes de votre 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>

Désormais, dès que la méthode onClick() de votre adaptateur est appelée, vous devez simplement procéder comme suit:

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

L'arrière-plan des lignes aura la couleur (dans ce cas darker_gray) tant que vous appelez myBackground.setSelected(false). Bien sûr, vous devez créer SparseBooleanArray par exemple pour savoir quelle ligne est sélectionnée et laquelle ne l’est pas, car les lignes seront réutilisées lors du défilement.

Modifier: mémoriser les éléments sélectionnés
L'idée derrière SparseBooleanArray est de rappeler les éléments sélectionnés. En suivant un exemple d'utilisation:

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);
              }
        }
    }
}
86
reVerse

il n'y a pas de sélecteur dans RecyclerView comme ListView et GridView mais vous essayez ci-dessous ce qui a fonctionné pour moi

créer un sélecteur dessinable comme ci-dessous

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

puis définissez ce dessin comme arrière-plan de votre disposition de ligne RecyclerView en tant que

Android:background="@drawable/selector"
36
amodkanthe

Vous pouvez ajouter ceci à votre row_item.xml

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

Par exemple:

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

Si Android la version est Lolipop ou supérieure, le sélecteur est livré avec une ondulation. Et une surbrillance pour une autre version. J'espère que cela aidera

20
Tuss

J'ai essayé plusieurs façons pendant des heures et voici les deux solutions que j'ai proposées. Les deux solutions supposons que mon RecyclerView soit déclaré comme suit:

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" />

Rien de spécial ici, juste une déclaration régulière RecyclerView. Voyons maintenant les autres fichiers, en commençant par la solution la plus simple et la plus viable.

Première solution (XML uniquement)

layout/item.xml

Les deux attributs importants ici dans la racine de l'élément ViewGroup sont background et 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>

Deuxième solution (XML + Java)

item.xml

Aucun attribut background ni clickable ici.

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

    ...
}

Je recommande fortement d’utiliser la première solution car elle est plus facile à maintenir et plus puissante, car elle vous permet également d’ajouter des effets d’ondulation (dans le drawable/background_item... Fichiers XML), ce qui, à mon avis, n’est pas possible avec la solution 2.

4
flawyte

vous pouvez utiliser ce code hors de l'adaptateur

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

Vous devriez créer un sélecteur pouvant être dessiné avec Android:state_focused="true" attribut comme ci-dessous

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

puis définissez ce dessin comme arrière-plan de votre disposition de ligne RecyclerView en tant que

Android:background="@drawable/selector"
1
Insoft

Si vous parvenez à utiliser un modèle de motif observable tel qu'Otto ou AndroidRx, vous pouvez suivre la mise en surbrillance de l'arrière-plan comme expliqué ci-dessus, et pour chaque élément viewView, vous pouvez vous abonner à l'élément observable et vous désabonner lorsqu'il se détache de votre vue recyclée comme je l'ai fait ici. :

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

En passant, pour une démonstration rapide, itemView utilise linearLayout. Il était donc facile de définir la couleur de fond en jaune.

enter image description here

0
Juan Mendez