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);
}
}
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);
}
}
}
}
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"
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
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.
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>
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.
vous pouvez utiliser ce code hors de l'adaptateur
LinearLayoutManager RvLayoutManager = (LinearLayoutManager)rootlayout.getLayoutManager();
View itemSelected = RvLayoutManager.findViewByPosition(position);
itemSelected.setBackgroundColor(Color.Red);
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"
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. :
En passant, pour une démonstration rapide, itemView utilise linearLayout. Il était donc facile de définir la couleur de fond en jaune.