在RecyclerView中正确突出显示所选项目

时间:2018-12-02 14:38:57

标签: android android-recyclerview

通过简单的编码,我希望在RecyclerView上突出显示选中的项目,就像下面的代码一样:

仅突出显示RecyclerView项的第一个位置,而我的代码上的onClick无效

private int selected_position = 0; //globally in the Adapter class

@Override
public void onBindViewHolder(final ViewHolder holder, int position) {
    holder.mItem = mValues.get(position);
    holder.mCoverView.setImageResource(holder.mItem.getCover());
    holder.mTitleView.setText(holder.mItem.getTitle());

    ...

    holder.itemView.setBackgroundColor(selected_position == position ? Color.GREEN : Color.TRANSPARENT);
}

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
    public final View mView;
    public final ImageView mCoverView;
    public final TextView mTitleView;
    public final TextView mDurationView;
    public MusicContent mItem;
    public FrameLayout itemsRoot;

    public ViewHolder(View itemView) {
        super(itemView);
        mView = itemView;
        mCoverView = (ImageView) itemView.findViewById(R.id.cover);

        ...

        itemView.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (getAdapterPosition() == RecyclerView.NO_POSITION) return;
        notifyItemChanged(selected_position);
        selected_position = getAdapterPosition();
        notifyItemChanged(selected_position);
    }
}

RecyclerView项目xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/itemsRoot"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:foreground="?attr/selectableItemBackground"
    android:minHeight="?attr/listPreferredItemHeight"

    android:background="@drawable/selectable_item"

    android:transitionGroup="true">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_vertical"
        android:gravity="center_vertical"
        android:paddingStart="@dimen/activity_horizontal_margin"
        android:paddingEnd="@dimen/activity_horizontal_margin">

        <TextView
            android:id="@+id/duration"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/inner_padding"
            android:textAppearance="@style/TextAppearance.AppCompat.Caption" />

    </LinearLayout>

</FrameLayout>

然后是selectable_item xml内容

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@color/colorPrimary" android:state_pressed="true"/>
    <item android:drawable="@color/colorPrimaryLite" android:state_selected="true"/>
    <item android:drawable="@color/colorPrimaryDark" android:state_focused="true"/>
</selector>

2 个答案:

答案 0 :(得分:1)

我将告诉您一种简单的方法来突出显示recyclerView中的所选头寸项目 此方法未使用,并且没有任何选择器属性,我只需更改所选项目onclick的背景,当您再次单击时,我将重置为其初始状态。

public class ModelItem {
private String name;

public void setName(String name) {
    this.name = name;
}

public String getName() {
    return this.name;
}

public boolean isClicked = false;

}

我假设您知道如何用虚拟物品或实际数据来增加回收站视图,所以我将直接直接向您展示如何设置listener和更改LinearLayout or RelativeLayout的背景。

您可以在ImageViewTextView之类的任何视图上设置监听器

我在上面创建的模型类将扮演关键角色,这里的boolean值isClicked最初会将背景设置为正常,我们将在click上更改其值,如下所示: 以下代码位于您的onBindViewHolder()

YOUR_ITEM_ON_WHICH_YOU_WANT_CLICK.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            ModelClass m = yourList.get(position);
            if (m.isClicked) {
                m.isClicked = false;
                yourList.set(position, m);
            } else {
                m.isClicked = true;
                yourList.set(position, m);
            }
        }
    });

    if (yourList.get(position).isClicked) {
     // If it is clicked   YOUR_LINEAR_OR_RELATIVELAYOUT.setBackgroundColor(context.getResources().getColor(R.color.white));
    } else {
    // If clicked again change the color to its original state
        YOUR_LINEAR_OR_RELATIVELAYOUT.setBackgroundColor(context.getResources().getColor(R.color.black));
    }

让我知道它是否对您有帮助,否则我将尝试发布另一个示例。

答案 1 :(得分:0)

From the code you've posted, your solution works perfectly. I've recreated it myself with a tiny app, and everything does exactly what it should.

public class MainActivity extends AppCompatActivity {

    private int selectedPosition = 0;
    private MyAdapter adapter = new MyAdapter();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        RecyclerView rv = findViewById(R.id.recycler);
        rv.setAdapter(adapter);
    }

    private class MyAdapter extends RecyclerView.Adapter<MyViewHolder> {

        @NonNull
        @Override
        public MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
            LayoutInflater inflater = LayoutInflater.from(parent.getContext());
            View itemView = inflater.inflate(R.layout.itemview, parent, false);
            return new MyViewHolder(itemView);
        }

        @Override
        public void onBindViewHolder(@NonNull MyViewHolder holder, int position) {
            holder.itemView.setBackgroundColor((position == selectedPosition) ? Color.GREEN : Color.WHITE);
        }

        @Override
        public int getItemCount() {
            return 1000;
        }
    }

    private class MyViewHolder extends RecyclerView.ViewHolder {

        public MyViewHolder(View itemView) {
            super(itemView);

            itemView.setOnClickListener(v -> {
                int position = getAdapterPosition();
                if (position != -1) {
                    adapter.notifyItemChanged(selectedPosition);
                    selectedPosition = position;
                    adapter.notifyItemChanged(selectedPosition);
                }
            });
        }
    }
}

That means that something else in your app is causing your code to not work. My best guess is that your adapter's data is changing over time in a way that's causing selectedPosition to become out of sync. For example:

  • selectedPosition is 10
  • a new item is inserted into the list at position 0
  • the adapter is notified notifyItemInserted(0)

At this point, selectedPosition is still 10, but the logically "selected" item is at position 11. When your onClick() method runs, you'll notify the item at position 10 that it has been changed, but that won't change the background of the item at position 11, so now you'll have two green rows.