RecyclerView'da seçilen öğeyi nasıl düzgün bir şekilde vurgulayabilirim?


146

RecyclerViewA'yı yatay olarak kullanmaya çalışıyorum ListView. Seçilen öğeyi vurgulamak için nasıl anlamaya çalışıyorum. Öğelerden birini tıkladığımda, seçiliyor ve düzgün bir şekilde vurgulanıyor, ancak başka bir öğeye tıkladığımda, ikincisi eskisiyle vurgulanıyor.

İşte benim onClick işlevi:

@Override
public void onClick(View view) {

    if(selectedListItem!=null){
        Log.d(TAG, "selectedListItem " + getPosition() + " " + item);
        selectedListItem.setBackgroundColor(Color.RED);
    }
    Log.d(TAG, "onClick " + getPosition() + " " + item);
    viewHolderListener.onIndexChanged(getPosition());
    selectedPosition = getPosition();
    view.setBackgroundColor(Color.CYAN); 
    selectedListItem = view;
}

İşte onBindViewHolder:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {   
    viewHolder.setItem(fruitsData[position]);
    if(selectedPosition == position)
        viewHolder.itemView.setBackgroundColor(Color.CYAN);    
    else
        viewHolder.itemView.setBackgroundColor(Color.RED);

}

Odaklanabilir görünümleri kullanmak, seçilen öğeyi izlemeye çalışmak için iyi bir fikir değildir. Tam bir çözüm için cevabımı kontrol et
Greg Ennis


Recycler ürün seçimini görüntüle: stackoverflow.com/a/38501676/2648035
Alok Omkar

Zaten çalışan bir şey olmadığında bunu takip etmek zordur , bu da cevaplar etiketlendiğinden kötüdür ve nereye gittiğine dair fazla bir şey belirtmez.
FirstOne

Yanıtlar:


61

Otomatik olarak RecyclerView ile öğe seçimi işlemek için bir temel bağdaştırıcı sınıfı yazdı. Bağdaştırıcınızı buradan türetmeniz ve list_ görünümünde yaptığınız gibi state_selected ile çekilebilir durum listeleri kullanmanız yeterlidir.

Burada bir Blog yazısı var, ama kod İşte:

public abstract class TrackSelectionAdapter<VH extends TrackSelectionAdapter.ViewHolder> extends RecyclerView.Adapter<VH> {
    // Start with first item selected
    private int focusedItem = 0;

    @Override
    public void onAttachedToRecyclerView(final RecyclerView recyclerView) {
        super.onAttachedToRecyclerView(recyclerView);

        // Handle key up and key down and attempt to move selection
        recyclerView.setOnKeyListener(new View.OnKeyListener() {
            @Override
            public boolean onKey(View v, int keyCode, KeyEvent event) {
                RecyclerView.LayoutManager lm = recyclerView.getLayoutManager();

                // Return false if scrolled to the bounds and allow focus to move off the list
                if (event.getAction() == KeyEvent.ACTION_DOWN) {
                    if (keyCode == KeyEvent.KEYCODE_DPAD_DOWN) {
                        return tryMoveSelection(lm, 1);
                    } else if (keyCode == KeyEvent.KEYCODE_DPAD_UP) {
                        return tryMoveSelection(lm, -1);
                    }
                }

                return false;
            }
        });
    }

    private boolean tryMoveSelection(RecyclerView.LayoutManager lm, int direction) {
        int tryFocusItem = focusedItem + direction;

        // If still within valid bounds, move the selection, notify to redraw, and scroll
        if (tryFocusItem >= 0 && tryFocusItem < getItemCount()) {
            notifyItemChanged(focusedItem);
            focusedItem = tryFocusItem;
            notifyItemChanged(focusedItem);
            lm.scrollToPosition(focusedItem);
            return true;
        }

        return false;
    }

    @Override
    public void onBindViewHolder(VH viewHolder, int i) {
        // Set selected state; use a state list drawable to style the view
        viewHolder.itemView.setSelected(focusedItem == i);
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        public ViewHolder(View itemView) {
            super(itemView);

            // Handle item click and set the selection
            itemView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    // Redraw the old selection and the new
                    notifyItemChanged(focusedItem);
                    focusedItem = getLayoutPosition();
                    notifyItemChanged(focusedItem);
                }
            });
        }
    }
} 

mRecyclerViewhiçbir yerde beyan edilmedi. Bunu yapıcıda bir parametre olarak geçirmeli ve bir alanda mı saklamalıyız?
Pedro

1
Bunun için üzgünüm. Bağdaştırıcım parçamın bir iç sınıfıdır, bu nedenle geri dönüşümcü görüntüleme alanına erişimi vardır. Aksi takdirde evet bunu parametre olarak iletebilirsiniz. Ya da daha iyisi, onRecyclerViewAttachedonu bir üye değişkeninde ele alın ve saklayın.
Greg Ennis

1
Güzel cevap, ama neden getChildPosition () kullanıyorsunuz? Başka bir yöntem geliştirici var.
Android.com/reference/android/support/v7/widget/…

Üzgünüm, sadece TrackSelectionAdaptersınıfınızı içe aktarmam ve listemde kullanmam gerektiği anlamına mı geliyor ? Bağdaştırıcıyı sınıfınızdan nasıl türetebilirim? Lütfen soruma cevap verebilir misiniz? Çok derinden sıkıştım: stackoverflow.com/questions/29695811/…
Cristiano Colacillo

2
Bunu denedim ve NotifyItemChanged () için arka arkaya iki çağrı yavaş donanım üzerinde düzgün kaydırma herhangi bir benzerlik öldürdü bulundu. Lollipop güncellemesinden önce Fire TV'de özellikle kötüydü
Redshirt

158

Bunu yapmanın çok basit bir yolu.

Bir var private int selectedPos = RecyclerView.NO_POSITION;ve onBindViewHolder yöntem denemede altında RecyclerView Adaptör sınıfında:

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {   
    viewHolder.itemView.setSelected(selectedPos == position);

}

Ve OnClick etkinliğinizde şunları değiştirin:

@Override
public void onClick(View view) {
     notifyItemChanged(selectedPos);
     selectedPos = getLayoutPosition();
     notifyItemChanged(selectedPos); 
}

Gezinme Çekmecesi ve diğer RecyclerView Öğe Bağdaştırıcıları için cazibe gibi çalışır.

Not: Açıklıklı bir etiket gibi bir seçici kullanarak mizanpajınızda bir arka plan rengi kullandığınızdan emin olun:

<selector xmlns:android="http://schemas.android.com/apk/res/android">
  <item android:drawable="@color/pressed_color" android:state_pressed="true"/>
  <item android:drawable="@color/selected_color" android:state_selected="true"/>
  <item android:drawable="@color/focused_color" android:state_focused="true"/>
</selector>

Aksi takdirde setSelected (..) hiçbir şey yapmaz ve bu çözümü işe yaramaz hale getirir.


12
: Benim satır görünümünde bir arka plan çizilebilir / selektör seti ile bu çözümü kullanılır <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@color/pressed_color" android:state_pressed="true"/> <item android:drawable="@color/selected_color" android:state_selected="true"/> <item android:drawable="@color/focused_color" android:state_focused="true"/> </selector>
colabug

1
@zIronManBox: güzel, basit bir yol! OnClick yöntemindeki "selectedPosition" öğesinin "selectedPos" olması gerekiyor mu?
AJW

3
getLayoutPosition () tarafımdan kullanılamıyor.
ka3ak

3
Sadece -1 kullanmayın, RecyclerView.NO_POSITION kullanın; (-1)
Martin Marconcini

8
@ ka3ak: getLayoutPosition, nesnesi bind view yönteminde ilk parametre olarak iletilen ViewHolder sınıfının yöntemidir. Böylece erişilebilirvieHolder.getLayoutPosition
Tushar Kathuria

129

GÜNCELLEME [26 / Tem / 2017]:

Pawan , bu sabit pozisyonun kullanılmamasıyla ilgili IDE uyarısı hakkındaki yorumda belirtildiği gibi, kodumu aşağıdaki gibi değiştirdim. Tıklama dinleyici taşındı ViewHolderve orada getAdapterPosition()yöntemi kullanarak pozisyon alıyorum

int selected_position = 0; // You have to set this globally in the Adapter class

@Override
public void onBindViewHolder(ViewHolder holder, int position) {
    Item item = items.get(position);

    // Here I am just highlighting the background
    holder.itemView.setBackgroundColor(selected_position == position ? Color.GREEN : Color.TRANSPARENT);
}

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {

    public ViewHolder(View itemView) {
        super(itemView);
        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        // Below line is just like a safety check, because sometimes holder could be null,
        // in that case, getAdapterPosition() will return RecyclerView.NO_POSITION
        if (getAdapterPosition() == RecyclerView.NO_POSITION) return;

        // Updating old as well as new positions
        notifyItemChanged(selected_position);
        selected_position = getAdapterPosition();
        notifyItemChanged(selected_position);

        // Do your another stuff for your onClick
    }
}

umarım bu yardımcı olur.


Bu harika! Yine de biraz kafam karıştı, bu yanıtı genişleterek, zaten seçili olan bir öğeyi tıkladığınızda else deyiminde ne yaparsanız yapın, böylece seçimini kaldırmak için bir yol uygulamama yardımcı olabilir misiniz: else { holder.itemView.setBackgroundColor (Color.TRANSPARENT); }
iBobb

Tabii ki evet. @iBobb. SEÇİLMEDİ öğeler için, yani konumu 'seçili_pozisyon' değişkenimize eşit olmayan öğeler için arka plan YOK olmalıdır. Bunu kullandım çünkü RecyclerView, adından da anlaşılacağı gibi, her bir öğeyi geri dönüştürüyor, bu yüzden biz SCROLL ederken rastgele satırlar için YEŞİL arka planı ayarlıyor, bu yüzden bu ELSE parçasını yerleştirdim. (Sadece ELSE bölümünü yorumlayarak deneyebilir ve daha sonra Recycler görünümünüzü kaydırabilirsiniz)
Vora ile tanışın

Sorumu anladığınızı sanmıyorum. Herhangi bir uygulamada bilirsiniz, bir şey seçtiğinizde vurgulanır. Tekrar tutarsanız, seçimi kaldırılır. Bunu nasıl uygularız? Şu anda yalnızca kodunuzu kullanarak seçebilir ve aynı öğeye dokunup basılı tutmak hiçbir şey yapmaz.
iBobb

Mümkün olabilir, ancak bunun için onClickListener yerine onLongClickListener'ı geçersiz kılmak zorundasınız, şu anda meşgulüm, bu yüzden tam kod sağlayamıyorum, ancak temelde bu şekilde yapmalısınız.
Vora

Herhangi bir nedenle, tıklamadan sonra yaklaşık 100 ila 200 milisaniye vurgulamak zaman alır. Neden olduğu hakkında bir fikrin var mı? Bunu bir emülatörde ve lolipop telefonumda yaşadım
suku

14

İçeriği görünümden sonra tekrar görünüme kaydırırsanız uygulamanız büyük olasılıkla çalışır. Sorunuza geldiğimde de benzer bir sorun yaşıyordum.

Aşağıdaki dosya pasajı benim için çalışıyor. Uygulamam çoklu seçime yönelikti, ancak tek seçimi zorlamak için oraya bir saldırı düzenledim. (* 1)

// an array of selected items (Integer indices) 
private final ArrayList<Integer> selected = new ArrayList<>();

// items coming into view
@Override
public void onBindViewHolder(final ViewHolder holder, final int position) {
    // each time an item comes into view, its position is checked
    // against "selected" indices
    if (!selected.contains(position)){
        // view not selected
        holder.parent.setBackgroundColor(Color.LTGRAY);
    }
    else
        // view is selected
        holder.parent.setBackgroundColor(Color.CYAN);
}

// selecting items
@Override
public boolean onLongClick(View v) {

        // set color immediately.
        v.setBackgroundColor(Color.CYAN);

        // (*1)
        // forcing single selection here
        if (selected.isEmpty()){
            selected.add(position);
        }else {
            int oldSelected = selected.get(0);
            selected.clear();
            selected.add(position);
            // we do not notify that an item has been selected
            // because that work is done here.  we instead send
            // notifications for items to be deselected
            notifyItemChanged(oldSelected);
        }
        return false;
}

Bu bağlantılı soruda belirtildiği gibi , viewHolders için dinleyicilerin ayarlanması onCreateViewHolder'da yapılmalıdır. Bundan daha önce bahsetmeyi unuttum.


6

Sanırım, RecyclerView'i ihtiyacımız olan tüm temel işlevlerle (tek + çoklu seçim, vurgulama, dalgalanma, tıklama ve çoklu seçimde kaldır vb.) Nasıl kullanacağım konusunda en iyi öğreticiyi buldum.

İşte -> http://enoent.fr/blog/2015/01/18/recyclerview-basics/

Buna dayanarak, bir SelectableAdapter genişleten "FlexibleAdapter" kütüphanesi oluşturabildim. Bunun Adaptörün sorumluluğu olması gerektiğini düşünüyorum, aslında her seferinde Adaptörün temel işlevlerini yeniden yazmanıza gerek yok, bir kütüphanenin bunu yapmasına izin verin, böylece aynı uygulamayı tekrar kullanabilirsiniz.

Bu Adaptör çok hızlı, kutudan çıkıyor (uzatmanıza gerek yok); ihtiyacınız olan her görünüm türü için öğeleri özelleştirirsiniz; ViewHolder önceden tanımlanmıştır: ortak etkinlikler zaten uygulanmıştır: tek ve uzun tıklama; dönmeden sonra durumu ve çok daha fazlasını korur .

Lütfen projelerinize uygulamak için bir göz atın ve çekinmeyin.

https://github.com/davideas/FlexibleAdapter

Bir Wiki de mevcuttur.


Bu adaptörün yazılması harika bir iş, çok kullanışlı görünüyor. Tek şey, gerçekten bazı temel örneklere ve belgelere ihtiyaç duyması, onu çalıştırmak ve çalıştırmak için biraz kafa karıştırıcı buluyorum. Potansiyel olarak harika!
Voy

Evet, başlamak için yeterli bilgi bulamadım. Kod akılda yorumlanmış gibi görünse bile API referansı bulunamadı. Örnek uygulama - geniş ve bilgilendirici olsa da - kütüphanenin ön bilgisi olmadan anlamak çok zor görünüyor. Tüm kullanım durumları birbirine bağlıdır, neyin ne olduğunu gösteren çok az gösterge vardır, sınıflar farklı senaryolarda yeniden kullanılır ve bu da bilgi ile aşırı yüklenmelerine neden olur. Burada bu önerilerle yeni bir sorun oluşturdum: github.com/davideas/F FlexibleAdapter/issues/120
Voy

wiki tamamen yeniden yazılmıştır ve tamamlanma yolundadır.
Davideas

6

Benim çözümüme bak. Seçilen konumu tutucuda ayarlamanız ve Görünüm Etiketi olarak geçirmeniz gerektiğini düşünüyorum. Görünüm onCreateViewHolder (...) yönteminde ayarlanmalıdır. Dinleyiciyi OnClickListener veya LongClickListener gibi görüntüleme için ayarlamak için doğru yer de vardır.

Lütfen aşağıdaki örneğe bakın ve kodla ilgili yorumları okuyun.

public class MyListAdapter extends RecyclerView.Adapter<MyListAdapter.ViewHolder> {
    //Here is current selection position
    private int mSelectedPosition = 0;
    private OnMyListItemClick mOnMainMenuClickListener = OnMyListItemClick.NULL;

    ...

    // constructor, method which allow to set list yourObjectList

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        //here you prepare your view 
        // inflate it
        // set listener for it
        final ViewHolder result = new ViewHolder(view);
        final View view =  LayoutInflater.from(parent.getContext()).inflate(R.layout.your_view_layout, parent, false);
        view.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                //here you set your current position from holder of clicked view
                mSelectedPosition = result.getAdapterPosition();

                //here you pass object from your list - item value which you clicked
                mOnMainMenuClickListener.onMyListItemClick(yourObjectList.get(mSelectedPosition));

                //here you inform view that something was change - view will be invalidated
                notifyDataSetChanged();
            }
        });
        return result;
    }

    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        final YourObject yourObject = yourObjectList.get(position);

        holder.bind(yourObject);
        if(mSelectedPosition == position)
            holder.itemView.setBackgroundColor(Color.CYAN);
        else
            holder.itemView.setBackgroundColor(Color.RED);
    }

    // you can create your own listener which you set for adapter
    public void setOnMainMenuClickListener(OnMyListItemClick onMyListItemClick) {
        mOnMainMenuClickListener = onMyListItemClick == null ? OnMyListItemClick.NULL : onMyListItemClick;
    }

    static class ViewHolder extends RecyclerView.ViewHolder {


        ViewHolder(View view) {
            super(view);
        }

        private void bind(YourObject object){
            //bind view with yourObject
        }
    }

    public interface OnMyListItemClick {
        OnMyListItemClick NULL = new OnMyListItemClick() {
            @Override
            public void onMyListItemClick(YourObject item) {

            }
        };

        void onMyListItemClick(YourObject item);
    }
}

Yapılandırma değişikliklerini korumak için mSelectedPosition'ın statik olarak bildirilebileceğini düşünüyor musunuz?
Mart'ta Sathesh

Hayır! statik olarak yanlış yapmak çok yanlış
Konrad Krakowiak

Evet. tehlikeli. Ancak yapılandırma değişikliğini korumak için (özellikle ekran döndürme) bu değişkeni etkinlik olarak bildirebilir ve oradan alabiliriz, değil mi?
Mart'ta Sathesh

Birçok çözüm var ... Alıcı ve ayarlayıcı kullanabilirsiniz, adaptör için saveInstanceState kendi yönteminizi oluşturabilir ve Activity / Fragment
Konrad Krakowiak

4

RecyclerView'de ListView ve GridView gibi bir seçici yok ama benim için çalıştığı şeyin altında deniyorsunuz

aşağıdaki gibi çekilebilir bir seçici oluşturun

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

ardından bu çekilebilir öğeyi RecyclerView satır düzeninizin arka planı olarak ayarlayın

android:background="@drawable/selector"

2
Bu yararlı bir şey yapmaz. Sadece baskı süresini yaparak rengi değiştirir.
Leo Droidcoder

4

Arayüzler ve Geri Çağrılar ile Karar. Seçme ve seçimi kaldırma durumlarıyla Arayüz Oluşturma:

public interface ItemTouchHelperViewHolder {
    /**
     * Called when the {@link ItemTouchHelper} first registers an item as being moved or swiped.
     * Implementations should update the item view to indicate it's active state.
     */
    void onItemSelected();


    /**
     * Called when the {@link ItemTouchHelper} has completed the move or swipe, and the active item
     * state should be cleared.
     */
    void onItemClear();
}

Arabirimi ViewHolder'da uygulayın:

   public static class ItemViewHolder extends RecyclerView.ViewHolder implements
            ItemTouchHelperViewHolder {

        public LinearLayout container;
        public PositionCardView content;

        public ItemViewHolder(View itemView) {
            super(itemView);
            container = (LinearLayout) itemView;
            content = (PositionCardView) itemView.findViewById(R.id.content);

        }

               @Override
    public void onItemSelected() {
        /**
         * Here change of item
         */
        container.setBackgroundColor(Color.LTGRAY);
    }

    @Override
    public void onItemClear() {
        /**
         * Here change of item
         */
        container.setBackgroundColor(Color.WHITE);
    }
}

Geri Arama'da durum değişikliği çalıştır:

public class ItemTouchHelperCallback extends ItemTouchHelper.Callback {

    private final ItemTouchHelperAdapter mAdapter;

    public ItemTouchHelperCallback(ItemTouchHelperAdapter adapter) {
        this.mAdapter = adapter;
    }

    @Override
    public boolean isLongPressDragEnabled() {
        return true;
    }

    @Override
    public boolean isItemViewSwipeEnabled() {
        return true;
    }

    @Override
    public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
        int swipeFlags = ItemTouchHelper.END;
        return makeMovementFlags(dragFlags, swipeFlags);
    }

    @Override
    public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
        ...
    }

    @Override
    public void onSwiped(final RecyclerView.ViewHolder viewHolder, int direction) {
        ...
    }

    @Override
    public void onSelectedChanged(RecyclerView.ViewHolder viewHolder, int actionState) {
        if (actionState != ItemTouchHelper.ACTION_STATE_IDLE) {
            if (viewHolder instanceof ItemTouchHelperViewHolder) {
                ItemTouchHelperViewHolder itemViewHolder =
                        (ItemTouchHelperViewHolder) viewHolder;
                itemViewHolder.onItemSelected();
            }
        }
        super.onSelectedChanged(viewHolder, actionState);
    }

    @Override
    public void clearView(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
        super.clearView(recyclerView, viewHolder);
        if (viewHolder instanceof ItemTouchHelperViewHolder) {
            ItemTouchHelperViewHolder itemViewHolder =
                    (ItemTouchHelperViewHolder) viewHolder;
            itemViewHolder.onItemClear();
        }
    }   
}

Geri Arama ile RecyclerView oluşturun (örnek):

mAdapter = new BuyItemsRecyclerListAdapter(MainActivity.this, positionsList, new ArrayList<BuyItem>());
positionsList.setAdapter(mAdapter);
positionsList.setLayoutManager(new LinearLayoutManager(this));
ItemTouchHelper.Callback callback = new ItemTouchHelperCallback(mAdapter);
mItemTouchHelper = new ItemTouchHelper(callback);
mItemTouchHelper.attachToRecyclerView(positionsList);

İPaulPro makalesinde daha fazlasını görün: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.6gh29uaaz


3

Bu benim çözümüm, bir öğeyi (veya grubu) ayarlayabilir ve başka bir tıklama ile seçimini kaldırabilirsiniz:

 private final ArrayList<Integer> seleccionados = new ArrayList<>();
@Override
    public void onBindViewHolder(final ViewHolder viewHolder, final int i) {
        viewHolder.san.setText(android_versions.get(i).getAndroid_version_name());
        if (!seleccionados.contains(i)){ 
            viewHolder.inside.setCardBackgroundColor(Color.LTGRAY);
        }
        else {
            viewHolder.inside.setCardBackgroundColor(Color.BLUE);
        }
        viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (seleccionados.contains(i)){
                    seleccionados.remove(seleccionados.indexOf(i)); 
                    viewHolder.inside.setCardBackgroundColor(Color.LTGRAY);
                } else { 
                    seleccionados.add(i);
                    viewHolder.inside.setCardBackgroundColor(Color.BLUE);
                }
            }
        });
    }

2

Ben aynı sorunu vardı ve ben aşağıdaki şekilde çözmek:

CreateViewholder içinde bir Satır oluşturmak için kullanılan xml dosyası, sadece aşağıdaki satırı ekleyin:

 android:clickable="true"
 android:focusableInTouchMode="true"
 android:background="?attr/selectableItemBackgroundBorderless"

VEYA satır öğesinin üst öğesi olarak frameLayout kullanıyorsanız:

android:clickable="true"
android:focusableInTouchMode="true"
android:foreground="?attr/selectableItemBackgroundBorderless"

Tıklama dinleyicisine eklediğiniz görünüm tutucu içindeki java kodunda:

@Override
   public void onClick(View v) {

    //ur other code here
    v.setPressed(true);
 }

1

Web'de bu sorun için iyi bir çözüm bulamadım ve kendim çözdüm. Bu sorundan muzdarip birçok insan var. Böylece çözümümü burada paylaşmak istiyorum.

Kaydırma sırasında satırlar geri dönüştürülür. Bu nedenle, işaretli onay kutuları ve vurgulanan satırlar düzgün çalışmaz. Aşağıdaki adaptör sınıfını yazarak bu sorunu çözdüm.

Ayrıca tam bir proje yürütüyorum. Bu projede, birden fazla onay kutusu seçebilirsiniz. Seçili onay kutularını içeren satırlar vurgulanır. Ve daha da önemlisi, kaydırma sırasında bunlar kaybolmaz. Bağlantıdan indirebilirsiniz:

https://www.dropbox.com/s/ssm58w62gw32i29/recyclerView_checkbox_highlight.zip?dl=0

    public class RV_Adapter extends RecyclerView.Adapter<RV_Adapter.ViewHolder> {
        public ArrayList<String> list;
        boolean[] checkBoxState;
        MainActivity mainActivity;
        MyFragment myFragment;
        View firstview;

        private Context context;

        FrameLayout framelayout;

        public RV_Adapter() {

      }

        public RV_Adapter(Context context, MyFragment m, ArrayList<String> list ) {
          this.list = list;
          myFragment = m;
          this.context = context;
          mainActivity = (MainActivity) context;
          checkBoxState = new boolean[list.size()];
          // relativeLayoutState = new boolean[list.size()];
        }

        public class ViewHolder extends RecyclerView.ViewHolder  {
            public TextView textView;
            public CheckBox checkBox;
            RelativeLayout relativeLayout;
            MainActivity mainActivity;
            MyFragment myFragment;
            public ViewHolder(View v,MainActivity mainActivity,MyFragment m) {
                super(v);
                textView = (TextView) v.findViewById(R.id.tv_foodname);
                /**/
                checkBox= (CheckBox) v.findViewById(R.id.checkBox);
                relativeLayout = (RelativeLayout)v.findViewById(R.id.relativelayout);
                this.mainActivity = mainActivity;
                this.myFragment = m;
                framelayout = (FrameLayout) v.findViewById(R.id.framelayout);
                framelayout.setOnLongClickListener(m);
            }

        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            firstview = inflater.inflate(R.layout.row, parent, false);
            return new ViewHolder(firstview,mainActivity, myFragment);
        }

        @Override
        public void onBindViewHolder( final ViewHolder holder,  final int position) {

            holder.textView.setText(list.get(position));

            holder.itemView.setOnClickListener(new View.OnClickListener() {
              @Override
              public void onClick(View v) {

              }
            });

            // When action mode is active, checkboxes are displayed on each row, handle views(move icons) on each row are disappered.
            if(!myFragment.is_in_action_mode)
            {

              holder.checkBox.setVisibility(View.GONE);
            }
            else
            {
              holder.checkBox.setVisibility(View.VISIBLE);
              holder.checkBox.setChecked(false);
            }

              holder.checkBox.setTag(position);

              holder.checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener(){
                @Override
                public void onCheckedChanged(CompoundButton compoundButton, boolean b) {
                  if(compoundButton.isPressed()) // ekrandan kaybolan checkbox'lar otomatik olarak state degistiriyordu ve bu listener method cagiriliyordu, bunu onlemek icin isPressed() method'u ile kullanici mi basmis diye kontrol ediyorum.
                  {
                    int getPosition = (Integer) compoundButton.getTag();  // Here we get the position that we have set for the checkbox using setTag.
                    checkBoxState[getPosition] = compoundButton.isChecked(); // Set the value of checkbox to maintain its state.
                    //relativeLayoutState[getPosition] = compoundButton.isChecked();

                  if(checkBoxState[getPosition] && getPosition == position )
                    holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view  **/
                  else
                    holder.relativeLayout.setBackgroundResource(R.color.food_unselected); /** Change background color of the selected items in list view  **/
                    myFragment.prepareselection(compoundButton, getPosition, holder.relativeLayout);

                  }
                }
              });
              holder.checkBox.setChecked(checkBoxState[position]);

              if(checkBoxState[position]  )
                holder.relativeLayout.setBackgroundResource(R.color.food_selected); /** Change background color of the selected items in list view  **/
              else
                holder.relativeLayout.setBackgroundResource(R.color.food_unselected);
        }



        @Override
        public int getItemCount() {
            return list.size();
        }

        public void updateList(ArrayList<String> newList){
          this.list = newList;
          checkBoxState = new boolean[list.size()+1];
        }

      public void resetCheckBoxState(){
        checkBoxState = null;
        checkBoxState = new boolean[list.size()];
      }

    }

Uygulamanın ekran görüntüleri:

Ekran1 Ekran2 SCREEN3 Ekran4


-1

private int selected_position = -1;Başlangıçta herhangi bir öğenin seçilmesini önlemek için ayarlayın .

 @Override
 public void onBindViewHolder(final OrdersHolder holder, final int position) {
    final Order order = orders.get(position);
    holder.bind(order);
    if(selected_position == position){
        //changes background color of selected item in RecyclerView
        holder.itemView.setBackgroundColor(Color.GREEN);
    } else {
        holder.itemView.setBackgroundColor(Color.TRANSPARENT);
        //this updated an order property by status in DB
        order.setProductStatus("0");
    }
    holder.itemView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //status switch and DB update
            if (order.getProductStatus().equals("0")) {
                order.setProductStatus("1");
                notifyItemChanged(selected_position);
                selected_position = position;
                notifyItemChanged(selected_position);
             } else {
                if (order.getProductStatus().equals("1")){
                    //calls for interface implementation in
                    //MainActivity which opens a new fragment with 
                    //selected item details 
                    listener.onOrderSelected(order);
                }
             }
         }
     });
}

-1

android:background="?attr/selectableItemBackgroundBorderless"Arka plan renginiz yoksa eklemeniz gerekir, ancak setSelected yöntemini kullanmayı unutmayın. Farklı arka plan renginiz varsa, bunu sadece kullandım (veri bağlama kullanıyorum);

OnClick işlevinde isSelected olarak ayarlanır

b.setIsSelected(true);

Ve bunu xml'ye ekleyin;

android:background="@{ isSelected ? @color/{color selected} : @color/{color not selected} }"

-1

Seçici yap:

 <?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/Green_10" android:state_activated="true" />
    <item android:drawable="@color/Transparent" />
</selector>

Liste öğesi düzeninizde arka plan olarak ayarla

   <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:background="@drawable/selector_attentions_list_item"
        android:layout_width="match_parent"
        android:layout_height="64dp">

Bağdaştırıcınızda görünüme OnClickListener ekleyin (onBind yöntemi)

 @Suppress("UNCHECKED_CAST")
    inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

        fun bindItems(item: T) {
            initItemView(itemView, item)
            itemView.tag = item
            if (isClickable) {
                itemView.setOnClickListener(onClickListener)
            }
        }
    }

OnClick etkinliğinde görünümü etkinleştirin:

 fun onItemClicked(view: View){
        view.isActivated = true
    }

2
Bunun 2 sorunu vardır: 1) Geri dönüşüm cihazındaki diğer öğelerin etkinleştirilmesini geri almanın herhangi bir yolunu sağlamadınız. 2) Görünümler yeniden kullanılır. Bu nedenle, aynı etkinleştirilmiş görünüm kaydırıldığında sırayla görülebilir.
Anup Sharma
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.