2015-05-01 4 views
43

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

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); 
    } 
} 
+1

может эта помощь у http://amolsawant88.blogspot.in/2015/08/easy-way-to-highlight-selected-rowitem .html –

+0

Воспользуйтесь ссылкой: https://stackoverflow.com/a/46677018/1308990 – oiyio

+0

Вы можете проверить [этот учебник] (http://thedeveloperworldisyours.com/android/highlight-selected-item-recycler-view/) и [этот пример в GitHub] (https://github.com/thedeveloperworldisyours/FullRecyclerView/tree/master/app/src/main/java/com/thedeveloperworldisyours/fullrecycleview/updateData) – Cabezas

ответ

80

Вы можете использовать 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, например, чтобы узнать, какая строка выбрана, а какая нет, поскольку строки будут повторно использоваться при прокрутке.

Edit: Запомнить выбранные элементы
Идея 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); 
       } 
     } 
    } 
} 
+0

Привет, Спасибо за вашу помощь, но когда я прокручиваю свой RecyclerView, другой элемент также получает выбранный. Это потому, что я не использовал SparseBooleanArray. Если бы вы, пожалуйста, объясните мне, как это сделать. –

+0

@ KuldeepDubey Точно. Поскольку вы не сбрасываете выбранное состояние строк, переработанные виды все еще выбираются. См. Мое редактирование для примера о том, как использовать * SparseBooleanArray *. – reVerse

+2

@reVrese, Спасибо Это помогло, я сделал некоторые изменения в классе Adapter с помощью вашего кода, и это сработало. –

35

нет селектора в 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> 

затем задайте этот размер как bac kground вашего RecyclerView макет строки, как

android:background="@drawable/selector" 
+1

Это работает очень хорошо. Непосредственная! –

+0

Хотел бы я проголосовать за ваш вопрос каждый раз, когда он меня спасает! Благодаря! – Ale

+1

не забудьте добавить android: clickable = "true" вам RecyclerView layout layout –

0

Если вам удастся использовать наблюдаемый образец аромат такой, как Отто или AndroidRx, вы можете проследить, как выделить фон, как описано выше, и для itemView каждого viewHolder в вы можете подписаться на наблюдаемую и отписываться, когда он отрывается от вашего 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, так что это было легко установить цвет фона, как желтый.

enter image description here

14

Вы можете добавить это к вашему 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 --> 

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

+6

это работает для нажатого эффекта, а не выбранного –

3

Я пробовал несколько способов в течение нескольких часов, и вот два решения, с которыми я выступил. Оба решения предполагающие У меня есть 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

Два важных атрибутов здесь, в корне элемента ViewGroupbackground являются и 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> 

Адаптер.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; 
     } 
    }; 

    ... 
} 

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

-1

Это решение более интерактивно выглядит как 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; 
      } 
     }); 
    } 
} 
+1

Пожалуйста, добавьте комментарии или какое-то объяснение для вашего кода. Почему вы используете как прослушиватель Click, так и Touch Listener? И как это позволит кому-то выбрать и выбрать элемент? –

+0

@SammyT Эй Сэмми извините за это. Эта реализация будет выделять тогда нестареющий свет при нажатии и будет оставаться выделенной при длительном нажатии. Кроме того, это будет неторопливо после сохранения ячейки, выделенной при длительном нажатии и прокрутке. –

1

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

LinearLayoutManager RvLayoutManager = (LinearLayoutManager)rootlayout.getLayoutManager(); 
View itemSelected = RvLayoutManager.findViewByPosition(position); 
itemSelected.setBackgroundColor(Color.Red); 
Смежные вопросы