Подтвердить что ты не робот

Как выделить выбранный элемент просмотра ресайклеров?

У меня есть Recycler View с изображениями, загруженными из внутреннего хранилища. Я хочу выделить выделенный элемент при нажатии. Я много пробовал, но он не работал. Фактически, мне нужно, когда я нажимаю на любой элемент в представлении Recycler, что элемент должен идти в My ArrayList, и он также должен быть подсвечен, и снова, когда я нажимаю или говорю, что он отменяет выбор, он должен снова стать нормальным. Вот мой код:

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

Это мой класс адаптера:

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);
    }
}
4b9b3361

Ответ 1

Вы можете использовать StateListDrawable для достижения желаемого эффекта.

Пример

Создайте новый файл ресурса Drawable в каталоге drawable со следующим содержимым:

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>

Теперь просто используйте этот StateListDrawable в качестве фона в строке-макете вашего 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>

Теперь, как только метод onClick() в вашем адаптере вызывается, вам просто нужно сделать следующее:

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

Фон строк будет иметь цвет (в данном случае darker_gray), пока вы вызываете myBackground.setSelected(false). Конечно, вы должны создать SparseBooleanArray, например, чтобы узнать, какая строка выбрана, а какая нет, поскольку строки будут повторно использоваться, когда скроллинг.

Изменить: запомнить выбранные элементы
Идея SparseBooleanArray заключается в том, чтобы запомнить выбранные элементы. Следуя образцу о том, как его использовать:

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

в RecyclerView нет селектора, такого как ListView и GridView, но вы пытаетесь найти что-то, что сработало для меня

создайте селектор, как показано ниже

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

затем установите этот чертеж в качестве фона вашего макета строки RecyclerView как

android:background="@drawable/selector"

Ответ 3

Вы можете добавить это в свой файл row_item.xml

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

Например:

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

Если версия для Android - Lolipop или больше, селектор имеет пульсацию. И подсветка для другой версии. Надеюсь, что это поможет.

Ответ 4

Я пробовал несколько способов в течение нескольких часов, и вот два решения, с которыми я столкнулся. Оба решения предполагают, что мой RecyclerView объявлен следующим образом:

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

Ничего особенного здесь, просто регулярное объявление RecyclerView. Теперь посмотрим другие файлы, начиная с самого легкого и жизнеспособного решения.

Первое решение (только XML)

макет /item.xml

Два важных атрибута в корневом элементе 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>

вытяжка /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>

Второе решение (XML + Java)

item.xml

Нет 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

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 finger moves out of the view
                case MotionEvent.ACTION_UP:
                    v.setBackgroundResource(R.drawable.background_item_event);
                    break;
                default:
                    break;
            }

            return true;
        }
    };

    ...
}

Я настоятельно рекомендую использовать первое решение, так как оно проще поддерживать и более мощным, так как оно также позволяет добавлять эффекты пульсации (в XML файлы drawable/background_item...), что, на мой взгляд, невозможно с решением 2.

Ответ 5

Если вам удастся использовать наблюдаемый паттерн, такой как Otto или AndroidRx, вы можете следить за тем, как выделить фон, как описано выше, и для каждого элемента viewHolder itemView вы можете подписаться на наблюдаемую и отмену подписки, когда она отвлекается от вашего recyclerview, например Я здесь:

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

Кстати, для быстрой демонстрации мой itemView использует linearLayout, поэтому было легко установить цвет фона как желтый.

введите описание изображения здесь

Ответ 6

вы можете использовать этот код из адаптера

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

Ответ 7

Это решение более интерактивно выглядит как tableView в IOS. Затем он выделяет ярлыки ячеек.

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