Làm cách nào để tô sáng đúng mục đã chọn trên RecyclerView?


146

Tôi đang cố gắng sử dụng RecyclerViewnhư là một ngang ListView. Tôi đang cố gắng tìm ra cách làm nổi bật mục đã chọn. Khi tôi nhấp vào một trong các mục, nó sẽ được chọn và nó được tô sáng đúng nhưng khi tôi nhấp vào một mục khác, mục thứ hai sẽ được tô sáng bằng mục cũ hơn.

Đây là chức năng onClick của tôi:

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

Đây là 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);

}

Sử dụng các chế độ xem có thể tập trung không phải là một ý tưởng tốt để cố gắng theo dõi mục đã chọn. Kiểm tra câu trả lời của tôi để có giải pháp hoàn chỉnh
Greg


Trình tái chế xem mục lựa chọn: stackoverflow.com/a/38501676/2648035
Alok Omkar

Điều này rất khó để theo dõi khi bạn không có bất cứ điều gì đã hoạt động , điều này rất tệ vì thẻ câu trả lời cùng và không chỉ định nhiều về những gì đi đâu.
FirstOne

Câu trả lời:


61

Tôi đã viết một lớp bộ điều hợp cơ sở để tự động xử lý lựa chọn vật phẩm với RecyclerView. Chỉ cần lấy bộ điều hợp của bạn từ nó và sử dụng danh sách trạng thái có thể vẽ với state_selected, giống như bạn sẽ làm với chế độ xem danh sách.

Tôi có một bài viết Blog ở đây về nó, nhưng đây là mã:

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

mRecyclerViewkhông được tuyên bố ở bất cứ đâu. Chúng ta có nên vượt qua nó như là một tham số trong hàm tạo và lưu trữ nó trong một trường không?
Pedro

1
Xin lỗi vì điều đó. Bộ điều hợp của tôi là một lớp bên trong của đoạn của tôi để nó có quyền truy cập vào trường xem tái chế. Nếu không, bạn có thể vượt qua nó như là một tham số. Hoặc thậm chí tốt hơn, xử lý onRecyclerViewAttachedvà lưu trữ nó trong một biến thành viên ở đó.
Greg Enni

1
Câu trả lời hay, nhưng tại sao lại sử dụng getChildPocation ()? Có một phương thức khác developer.android.com/reference/android/support/v7/widget/ khăn
skyfishjy

Tôi xin lỗi, bạn có nghĩa là tôi chỉ cần nhập TrackSelectionAdapterlớp của bạn và sử dụng nó trong danh sách của tôi? Làm thế nào để tôi "lấy bộ điều hợp từ lớp của bạn"? Xin vui lòng trả lời câu hỏi của tôi? Tôi bị mắc kẹt quá sâu: stackoverflow.com/questions/29695811/ từ
Cristiano Colacillo

2
Tôi đã thử điều này và thấy hai cuộc gọi back-to-back tới NotifyItemChanged () đã giết chết mọi giao dịch di chuyển trơn tru trên phần cứng chậm hơn. Đặc biệt tệ trên Fire TV trước khi cập nhật Lollipop
Redcoat

157

Đây là cách đơn giản để làm điều đó.

Có một lớp private int selectedPos = RecyclerView.NO_POSITION;trong RecyclerView Adaptor và theo phương thức onBindViewHolder thử:

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

}

Và trong sự kiện OnClick của bạn sửa đổi:

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

Hoạt động như một bùa mê cho Ngăn kéo điều hướng và Bộ điều hợp vật phẩm RecyclerView khác.

Lưu ý: Đảm bảo sử dụng màu nền trong bố cục của bạn bằng cách sử dụng bộ chọn như colabug được làm 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>

Nếu không, setSelected (..) sẽ không làm gì cả, khiến giải pháp này trở nên vô dụng.


12
Tôi đã sử dụng giải pháp này với bộ có thể vẽ / chọn nền trên chế độ xem hàng của mình: <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: cách hay, đơn giản! Có phải "selectPocation" trong phương thức onClick được cho là "chọnPos" không?
AJW

3
getLayoutP vị trí () không có sẵn bởi tôi.
ka3ak 17/03/2017

3
Không chỉ sử dụng -1, sử dụng RecyclerView.NO_POSITION; (đó là -1)
Martin Marconcini

8
@ ka3ak: getLayoutPocation là phương thức của lớp ViewHolder có đối tượng được truyền làm tham số đầu tiên trong phương thức xem liên kết. Vì vậy, nó có thể được truy cập bởivieHolder.getLayoutPosition
Tushar Kathuria

129

CẬP NHẬT [26/7/2017]:

Như Pawan đã đề cập trong bình luận về cảnh báo IDE đó về việc không sử dụng vị trí cố định đó, tôi vừa sửa đổi mã của mình như dưới đây. Trình nghe nhấp được chuyển đến ViewHoldervà ở đó tôi đang nhận vị trí bằng getAdapterPosition()phương thức

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

hy vọng điều này sẽ giúp.


Thật tuyệt vời! Mặc dù tôi hơi bối rối, bạn có thể giúp tôi thực hiện một cách, mở rộng câu trả lời này không, làm thế nào để làm bất cứ điều gì bạn đang làm trong câu lệnh khác khi bạn nhấp vào một mục đã được chọn, để bạn bỏ chọn nó: khác { người giữ.itemView.setBackgroundColor (Color.TRANSPARENT); }
iBobb

Tất nhiên là có. @iBobb. Đối với các mục KHÔNG CHỌN, tức là có vị trí không bằng với biến 'được chọn' của chúng tôi sẽ KHÔNG có nền. Tôi đã sử dụng điều này bởi vì RecyclerView, như tên cho thấy, tái chế từng mục, do đó, nó đặt nền XANH cho các hàng ngẫu nhiên trong khi chúng tôi XÓA, đó là lý do tại sao tôi đặt phần ELSE đó. (Bạn chỉ có thể dùng thử bằng cách nhận xét phần ELSE đó, sau đó cuộn chế độ xem Recycler của bạn)
Gặp Vora vào

Tôi không nghĩ bạn hiểu câu hỏi của tôi. Bạn biết trong bất kỳ ứng dụng nào, khi bạn chọn thứ gì đó, nó sẽ được tô sáng. Nếu bạn giữ nó một lần nữa, nó sẽ được bỏ chọn. Làm thế nào chúng ta sẽ thực hiện điều đó? Ngay bây giờ chúng tôi chỉ có thể chọn sử dụng mã của bạn và chạm và giữ cùng một mục không làm gì cả.
iBobb

Có thể là có thể, nhưng để bạn phải ghi đè lênLongClickListener thay vì onClickListener, ngay bây giờ tôi đang bận nên không thể cung cấp mã đầy đủ, nhưng về cơ bản bạn phải làm theo cách đó.
Gặp Vora

Vì một số lý do, phải mất thời gian để tô sáng sau khi nhấp, khoảng 100 đến 200 mili giây. Bất cứ ý tưởng tại sao? Tôi đã trải nghiệm điều này trên một trình giả lập và điện thoại kẹo mút của tôi
suku

14

Việc triển khai của bạn có thể hoạt động nếu bạn cuộn nội dung ra khỏi chế độ xem rồi quay lại xem. Tôi đã có một vấn đề tương tự khi tôi gặp câu hỏi của bạn.

Đoạn mã sau đây đang làm việc cho tôi. Việc triển khai của tôi nhằm vào nhiều lựa chọn, nhưng tôi đã ném một hack vào đó để buộc lựa chọn duy nhất. (* 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;
}

Như đã lưu ý trong câu hỏi được liên kết này , việc thiết lập trình nghe cho viewHolders nên được thực hiện trong onCreateViewHolder. Tôi quên đề cập đến điều này trước đây.


6

Tôi nghĩ rằng, tôi đã tìm thấy hướng dẫn tốt nhất về cách sử dụng RecyclerView với tất cả các chức năng cơ bản mà chúng tôi cần (đơn + đa điểm, tô sáng, gợn, nhấp và xóa trong đa hướng, v.v ...).

Đây là -> http://enoent.fr/blog/2015/01/18/recyclerview-basics/

Dựa vào đó, tôi đã có thể tạo một thư viện "Linh hoạt Chương trình", mở rộng một Chương trình có thể chọn. Tôi nghĩ rằng đây phải là trách nhiệm của Bộ điều hợp, thực ra bạn không cần phải viết lại các chức năng cơ bản của Bộ điều hợp mỗi lần, hãy để thư viện thực hiện, vì vậy bạn có thể sử dụng lại cách thực hiện tương tự.

Bộ điều hợp này rất nhanh, nó hoạt động tốt (bạn không cần phải mở rộng nó); bạn tùy chỉnh các mục cho mọi kiểu xem bạn cần; ViewHolder được xác định trước: các sự kiện phổ biến đã được triển khai: nhấp chuột đơn và dài; nó duy trì trạng thái sau khi quay và nhiều hơn nữa .

Xin vui lòng xem và cảm thấy tự do để thực hiện nó trong các dự án của bạn.

https://github.com/davideas/FlexibleAd CHƯƠNG

Một Wiki cũng có sẵn.


Công việc tuyệt vời viết bộ chuyển đổi đó, nó có vẻ rất hữu ích. Chỉ có điều là nó thực sự cần một số ví dụ và tài liệu cơ bản, tôi thấy hơi khó hiểu khi thậm chí tải nó lên và chạy. Có khả năng lớn mặc dù!
Chuyến đi

Có, tôi không tìm thấy đủ thông tin ở đó để bắt đầu. Không thể tìm thấy tài liệu tham khảo API mặc dù mã dường như được nhận xét với ý nghĩ đó. Ứng dụng mẫu dường như - trong khi rộng và nhiều thông tin - rất khó hiểu nếu không có kiến ​​thức trước về thư viện. Tất cả các trường hợp sử dụng được liên kết với nhau, có rất ít dấu hiệu cho thấy điều gì, các lớp được sử dụng lại trong các tình huống khác nhau dẫn đến việc chúng bị quá tải thông tin. Tôi đã tạo một vấn đề mới với các đề xuất này tại đây: github.com/davideas/FlexibleAdOG/issues/120
Voy

Wiki đã được viết lại hoàn toàn và đang trên đường hoàn thành.
Davideas

6

Nhìn vào giải pháp của tôi. Tôi cho rằng bạn nên đặt vị trí đã chọn trong ngăn chứa và chuyển nó làm Thẻ xem. Chế độ xem phải được đặt trong phương thức onCreateViewHolder (...). Cũng có nơi chính xác để đặt trình nghe cho chế độ xem, chẳng hạn như OnClickListener hoặc LongClickListener.

Xin vui lòng xem ví dụ dưới đây và đọc ý kiến ​​để mã.

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

Bạn có nghĩ rằng mSelectedPocation có thể được khai báo là tĩnh để duy trì thay đổi cấu hình không?
Sathesh 18/03/2015

Không! thật sai lầm khi biến nó thành tĩnh, nó rất sai
Konrad Krakowiak

Vâng. Nguy hiểm. Nhưng để duy trì thay đổi cấu hình (đặc biệt là xoay màn hình), chúng ta có thể khai báo biến này trong hoạt động và lấy nó từ đó, phải không?
Sathesh 18/03/2015

Có nhiều giải pháp ... Bạn có thể sử dụng getter và setter, Bạn có thể tạo phương thức riêng của mình saveInstanceState cho bộ điều hợp và gọi nó trong saveInstanceState từ Activity / Fragment
Konrad Krakowiak

4

không có bộ chọn trong RecyclerView như ListView và GridView nhưng bạn hãy thử bên dưới điều này nó hoạt động với tôi

tạo một bộ chọn có thể vẽ như dưới đây

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

sau đó đặt drawable này làm nền của bố cục hàng RecyclerView của bạn thành

android:background="@drawable/selector"

2
Điều này không có gì hữu ích. Nó sẽ chỉ thay đổi màu sắc làm thời gian báo chí.
Leo Droidcoder

4

Quyết định với Giao diện và Gọi lại. Tạo giao diện với các trạng thái chọn và bỏ chọn:

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

Giao diện triển khai trong ViewHolder:

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

Chạy thay đổi trạng thái trên Callback:

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

Tạo RecyclerView với Callback (ví dụ):

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

Xem thêm trong bài viết của iPaulPro: https://medium.com/@ipaulpro/drag-and-swipe-with-recyclerview-6a6f0c422efd#.6gh29uaaz


3

đây là giải pháp của tôi, bạn có thể đặt trên một mục (hoặc một nhóm) và bỏ chọn nó bằng một nhấp chuột khác:

 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

Tôi đã có cùng một vấn đề và tôi giải quyết nó theo cách sau:

Tệp xml đang sử dụng để tạo Hàng bên trong createViewholder, chỉ cần thêm dòng dưới đây:

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

HOẶC Nếu bạn sử dụng frameLayout làm cha mẹ của mục hàng thì:

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

Trong mã java bên trong khung nhìn nơi bạn đã thêm vào trình nghe nhấp chuột:

@Override
   public void onClick(View v) {

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

1

Tôi không thể tìm thấy một giải pháp tốt trên web cho vấn đề này và tự mình giải quyết nó. Có rất nhiều người mắc phải vấn đề này. Vì vậy tôi muốn chia sẻ giải pháp của tôi ở đây.

Trong khi cuộn, hàng được tái chế. Do đó, các hộp kiểm tra và các hàng được tô sáng không hoạt động đúng. Tôi đã giải quyết vấn đề này bằng cách viết lớp bộ điều hợp bên dưới.

Tôi cũng thực hiện một dự án đầy đủ. Trong dự án này, bạn có thể chọn nhiều hộp kiểm. Hàng bao gồm các hộp kiểm được chọn được tô sáng. Và quan trọng hơn, những thứ này không bị mất trong khi cuộn. Bạn có thể tải xuống từ liên kết:

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()];
      }

    }

Ảnh chụp màn hình của ứng dụng:

màn hình1 màn hình2 màn hình3 màn hình4


-1

Đặt private int selected_position = -1;để ngăn chặn bất kỳ mục nào được chọn khi bắt đầu.

 @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

Chỉ cần thêm android:background="?attr/selectableItemBackgroundBorderless"sẽ hoạt động nếu bạn không có màu nền, nhưng đừng quên sử dụng phương thức setSelected. Nếu bạn có màu nền khác, tôi chỉ sử dụng màu này (Tôi đang sử dụng liên kết dữ liệu);

Đặt isSelected tại chức năng onClick

b.setIsSelected(true);

Và thêm nó vào xml;

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

-1

Tạo bộ chọn:

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

Đặt nó làm nền trong bố trí mục danh sách của bạn

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

Trong bộ điều hợp của bạn, thêm OnClickListener vào dạng xem (phương thức onBind)

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

Trong sự kiện onClick kích hoạt chế độ xem:

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

2
Điều này có 2 vấn đề: 1) Bạn chưa cung cấp bất kỳ cách nào để hoàn tác việc kích hoạt các mục khác trong trình tái chế. 2) Lượt xem được sử dụng lại. Vì vậy, có thể cùng một chế độ xem được kích hoạt sẽ hiển thị theo thứ tự khi cuộn.
Anup Sharma
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.