Android RecyclerView按钮滚动时多次单击效果

时间:2015-12-18 22:52:26

标签: android android-recyclerview

我有RecyclerView列出文字和按钮。 如果我点击按钮,Toast文字会显示位置,按钮颜色将更改为#343434。 当我点击一个按钮时效果很好但是如果我循环我的RecyclerView另一个按钮颜色改变而不是点击,只有背景颜色改变。

正如你在下面看到的gif: 首先,我点击第1项并显示Toast文本,按钮背景更改。 然后我循环下来,第15项的按钮背景正在改变。 最后,我向上滚动到第一个位置项目1的按钮颜色仍然是原始颜色,项目4的按钮背景颜色被更改。

所以这是我的代码块:

public class HandleTouchRecyclerViewActivity extends BaseActivity implements ObservableScrollViewCallbacks {
private static final String TAG = HandleTouchRecyclerViewActivity.class.getSimpleName();

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

    ObservableRecyclerView recyclerView = (ObservableRecyclerView) findViewById(R.id.scroll);
    recyclerView.setLayoutManager(new LinearLayoutManager(this));
    recyclerView.setHasFixedSize(true);
    recyclerView.setScrollViewCallbacks(this);
    recyclerView.setAdapter(new CustomAdapter(this, getDummyData()));
}

@Override
public void onScrollChanged(int scrollY, boolean firstScroll, boolean dragging) {
    Log.v(TAG, "onScrollChanged: scrollY: " + scrollY + " firstScroll: " + firstScroll + " dragging: " + dragging);
}

@Override
public void onDownMotionEvent() {
    Log.v(TAG, "onDownMotionEvent");
}

@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    Log.v(TAG, "onUpOrCancelMotionEvent: scrollState: " + scrollState);
}

public static class CustomAdapter extends RecyclerView.Adapter<CustomAdapter.ViewHolder> {
    private Context mContext;
    private LayoutInflater mInflater;
    private ArrayList<String> mItems;

    public CustomAdapter(Context context, ArrayList<String> items) {
        mContext = context;
        mInflater = LayoutInflater.from(context);
        mItems = items;
    }

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

    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return new ViewHolder(mContext, mInflater.inflate(R.layout.list_item_handletouch, parent, false));
    }

    @Override
    public void onBindViewHolder(ViewHolder viewHolder, int position) {
        viewHolder.textView.setText(mItems.get(position));
    }

    static class ViewHolder extends RecyclerView.ViewHolder {
        TextView textView;
        Context context;

        public ViewHolder(Context context, View view) {
            super(view);
            this.context = context;
            this.textView = (TextView) view.findViewById(android.R.id.text1);
            view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {

                    click(getLayoutPosition() + 1,v);

                    v.setBackgroundColor(Color.parseColor("#343434"))

                }
            });
        }

        private void click(int i,View view) {
            String message = "Button " + i + " is clicked";
            view.setBackgroundColor(Color.parseColor("#343434"));
            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();

            Log.v(TAG, "click: " + message);
        }
    }
}

}

那么,我该如何避免呢? (在Android Android Observable-ScrollView中截取的屏幕截图和代码) Thi gif about my process

2 个答案:

答案 0 :(得分:7)

您必须在某处存储项目的状态,并在调用onBindViewHolder()时恢复它们。

在RecyclerView中,视图数与项目数不同;它通常不到那个。

首先创建项目1-10的视图,如果其中一些项目(例如项目1-4)已滚动,则为项目1-4创建的视图将重新用于/绑定到项目11-14,因此上。 (我只是编了数字。它们可能因情况而异)

换句话说,视图创建一次,并且多次绑定。

在你的情况下,

  • 向下滚动时,首先创建并绑定到项目1的视图是 回收并绑定到第15项。
  • 当你再次向上滚动时,视图(第15项,暗按钮)被滚动并绑定到第4项
  • 第1项绑定到以前用于绑定到其他项目的其他视图,该视图具有原始按钮颜色。

您需要跟踪所有项目状态,并使视图在onBindViewHolder()

中反映出来

编辑:

当您滚动并单击按钮时,会发生这些情况。 (为简单起见,我将项目数量限制为10,并假设屏幕上最多可以绘制3个项目。)

初始状态是这样的:

  • 查看#1 - 文字:“第1项”,原始颜色
  • 查看#2 - 文字:“第2项”,原始颜色
  • 查看#3 - 文字:“第3项”,原始颜色
  • 查看#4 - (这是预先创建以供将来使用,尚未显示)

这里,onCreateViewHolder()被称为4次;它将布局资源扩展到视图中,并为视图创建视图持有者。 同样onBindViewHolder()被称为4次;设置视图的文本

然后点击第1项

  • 查看#1 - 文字:“第1项”,dark color
  • 查看#2 - 文字:“第2项”,原始颜色
  • 查看#3 - 文字:“第3项”,原始颜色
  • 查看#4 - (尚未显示,原始颜色)

视图#1的按钮颜色现在很暗。

向下滚动一点,

  • View #1 - (scrolled out, not visible, dark color)
  • 查看#2 - 文字:“第2项”,原始颜色
  • 查看#3 - 文字:“第3项”,原始颜色
  • View #4 - text:"Item 4", original color

现在,视图#1已滚动出来。视图#4变为可见,onBindViewHolder()将视图的文本设置为“第4项”。

滚动更多,

  • 查看#2 - 文字:“第2项”,原始颜色
  • 查看#3 - 文字:“第3项”,原始颜色
  • 查看#4 - 文字:“第4项”,原始颜色
  • View #1 - text:"Item 5", dark color (now this view is recycled)

看最后一行;没有新创建视图,并调用onBindViewHolder()将View#1的文本设置为“Item 5”。 但是,onBindViewHolder()的实现不会设置按钮颜色。

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    viewHolder.textView.setText(mItems.get(position));
}

并且您的click()方法无法跟踪单击的项目。

private void click(int i,View view) {
    String message = "Button " + i + " is clicked";
    view.setBackgroundColor(Color.parseColor("#343434"))
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();

    Log.v(TAG, "click: " + message);
}

它只是更改视图的按钮颜色,而不关心单击哪个项目。 因此,onBindViewHolder()无法检查此项是否已被点击过。

以下是一种可能的解决方案:

// declare an array to check which item has been clicked
private boolean[] mIsItemClicked = new boolean[mItems.size()];

private void initClickedItems() {
    for (int i = 0; i < mIsItemClicked; ++i) {
        mIsItemClicked = false;
    }
}

private void click(int i,View view) {
    mIsItemClicked[i] = !mIsItemClicked[i]; // toggle
    String message = "Button " + i + " is clicked";
    view.setBackgroundColor(Color.parseColor("#343434"))
    Toast.makeText(context, message, Toast.LENGTH_SHORT).show();

    Log.v(TAG, "click: " + message);
}

@Override
public void onBindViewHolder(ViewHolder viewHolder, int position) {
    viewHolder.textView.setText(mItems.get(position));
    int buttonColor;
    if (mIsItemClicked[i])
        buttonColor = Color.parseColor("#343434");
    else
        buttonColor = Color.parseColor("#ffffff");  // whatever the original color is
    viewHolder.itemView.findViewById(R.id.button).setBackgroundColor(buttonColor);
}

每当调用onBindViewHolder()时,它会检查是否单击了该项并设置了按钮颜色。 click()方法还会检查点击了哪个项目。

答案 1 :(得分:0)

你可以看到nexus5x的答案。他说首先是1-10的观点。这是真的,但不是这样,RecyclerView根据设备屏幕创建项目。例如:你有2个设备名为A和B.Device A有一个更大的屏幕和10个项目适合屏幕这是好的。设备B的屏幕较小,屏幕上可能有7个项目。

所以在设备A中,首先创建10个项目,然后滚动一些新项目将会创建。在设备B中,前7个项目将被创建,然后bla bla bla ..

所以这个问题已经解决了。如果想在视图上添加一些开关或状态,则必须添加一些表示此状态的字段。

抱歉我的英语不好。如果您不理解下面的评论,我会尝试解释一下:)