我有一个RecyclerView
列出文本和按钮.如果我单击按钮,Toast
文本显示位置,按钮颜色将更改为#343434
.当我点击一个按钮时这很好但是如果我循环我的RecyclerView
另一个按钮颜色改变而不是点击,只有背景颜色改变.
正如您在下面看到的那样:首先我点击第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{ private Context mContext; private LayoutInflater mInflater; private ArrayList mItems; public CustomAdapter(Context context, ArrayList 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中截取的截图和代码)
您必须在某处存储项目的状态,并在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()
方法还会检查单击了哪个项目.