我有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中截取的屏幕截图和代码)
答案 0 :(得分:7)
您必须在某处存储项目的状态,并在调用onBindViewHolder()
时恢复它们。
在RecyclerView中,视图数与项目数不同;它通常不到那个。
首先创建项目1-10的视图,如果其中一些项目(例如项目1-4)已滚动,则为项目1-4创建的视图将重新用于/绑定到项目11-14,因此上。 (我只是编了数字。它们可能因情况而异)
换句话说,视图创建一次,并且多次绑定。
在你的情况下,
您需要跟踪所有项目状态,并使视图在onBindViewHolder()
编辑:
当您滚动并单击按钮时,会发生这些情况。 (为简单起见,我将项目数量限制为10,并假设屏幕上最多可以绘制3个项目。)
初始状态是这样的:
这里,onCreateViewHolder()
被称为4次;它将布局资源扩展到视图中,并为视图创建视图持有者。
同样onBindViewHolder()
被称为4次;设置视图的文本
然后点击第1项
dark color
视图#1的按钮颜色现在很暗。
向下滚动一点,
View #1 - (scrolled out, not visible, dark color)
View #4 - text:"Item 4", original color
现在,视图#1已滚动出来。视图#4变为可见,onBindViewHolder()
将视图的文本设置为“第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 ..
所以这个问题已经解决了。如果想在视图上添加一些开关或状态,则必须添加一些表示此状态的字段。
抱歉我的英语不好。如果您不理解下面的评论,我会尝试解释一下:)