【发布时间】:2015-09-16 18:22:12
【问题描述】:
对于一项作业,我必须使用一些预定义的项目创建一个 recyclerview,然后单击它们中的每一个在另一个视图中执行一些操作。这一切都很好,对于我的任务来说可能已经足够了,但我对它不太满意,因为没有显示选择了什么项目等等。
所以我想在列表项被选中时突出显示背景。经过一番搜索,我找到了一个类似问题的答案:https://stackoverflow.com/a/28617619/2437682
我遵循了答案,并得到了令我非常满意的结果,直到我注意到如果在单击新项目时当前选定的项目不在屏幕上,则会导致应用程序因 NPE 而崩溃。
导致此崩溃的特定代码是:
void onItemClick(int position) {
ListItemViewHolder yourViewHolder;
int oldSelectedPosition = mSelectedIndex;
if (position != mSelectedIndex) {
mSelectedIndex = position;
yourViewHolder = (ListItemViewHolder) recyclerView.findViewHolderForAdapterPosition(oldSelectedPosition);
//this is the line that causes the crash when the view is off-screen
yourViewHolder.itemView.setSelected(false);
yourViewHolder = (ListItemViewHolder) recyclerView.findViewHolderForAdapterPosition(mSelectedIndex);
yourViewHolder.itemView.setSelected(true);
}
}
我明白发生了什么。如果项目不在屏幕上,findViewHolderForAdapterPosition 方法将返回 null,因此我无法更改 setSelected 属性。
我不确定如何解决它。我试着说:
if (yourViewHolder != null) {
yourViewHolder.itemView.setSelected(false);
}
这至少可以防止应用程序崩溃,但是下次该列表项滚动回屏幕时,它仍然像被选中一样突出显示。
有什么想法吗?
更新
这是更新后的适配器和查看器类:
public class ColorsAdaptor extends RecyclerView.Adapter<ListItemViewHolder>{
@Override
public ListItemViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
Context context = viewGroup.getContext();
LayoutInflater inflater = LayoutInflater.from(context);
View listItemView = inflater.inflate(R.layout.list_item, viewGroup, false);
ColorDrawable colorDrawableSelected =
new ColorDrawable(getResources().getColor(R.color.selected));
StateListDrawable stateListDrawable = new StateListDrawable();
stateListDrawable.addState(new int[]{android.R.attr.state_selected}, colorDrawableSelected);
stateListDrawable.addState(StateSet.WILD_CARD, getResources().getDrawable(R.drawable.border));
listItemView.setBackgroundDrawable(stateListDrawable);
ListItemViewHolder viewHolder = new ListItemViewHolder(listItemView);
return viewHolder;
}
@Override
public void onBindViewHolder(ListItemViewHolder listItemViewHolder, int position) {
listItemViewHolder.updateView();
MyColor color = items.get(position);
TextView colorText = listItemViewHolder.getColorText();
colorText.setText(color.getName());
ImageView colorBlock = listItemViewHolder.getColorBlock();
colorBlock.setBackgroundColor(color.getColorID());
}
@Override
public int getItemCount() {
return items.size();
}
}
public class ListItemViewHolder extends RecyclerView.ViewHolder{
private TextView colorText;
private ImageView colorBlock;
private View itemView;
public ListItemViewHolder(View view) {
super(view);
itemView = view;
this.colorBlock = (ImageView) view.findViewById(R.id.colorBlock);
this.colorText = (TextView) view.findViewById(R.id.colorText);
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if (position != mSelectedIndex) {
ListItemViewHolder oldViewHolder = (ListItemViewHolder) recyclerView.findViewHolderForAdapterPosition(mSelectedIndex);
if (oldViewHolder != null) {
oldViewHolder.itemView.setSelected(false);
}
itemView.setSelected(true);
mSelectedIndex = position;
}
ImageView temp = (ImageView) v.findViewById(R.id.colorBlock);
colorViewer.setBackground(temp.getBackground());
}
});
}
public void updateView(){
Log.d("", "updateView SelectedIndex: " + mSelectedIndex + " adapterPosition: " + getAdapterPosition());
this.itemView.setSelected(getAdapterPosition() == mSelectedIndex);
}
public TextView getColorText() {
return colorText;
}
public ImageView getColorBlock() {
return colorBlock;
}
}
哦,还有 updateView() 方法的调试输出。
第一次运行时:
SelectedIndex: 0 adapterPosition: 0
SelectedIndex: 0 adapterPosition: 1
SelectedIndex: 0 adapterPosition: 2
SelectedIndex: 0 adapterPosition: 3
SelectedIndex: 0 adapterPosition: 4
SelectedIndex: 0 adapterPosition: 5
SelectedIndex: 0 adapterPosition: 6
然后,当我向上和向下滚动几次,当新视图返回屏幕时调用 updateView:
SelectedIndex: 0 adapterPosition: 7
SelectedIndex: 0 adapterPosition: 9
SelectedIndex: 0 adapterPosition: 2
SelectedIndex: 0 adapterPosition: 0
SelectedIndex: 0 adapterPosition: 7
SelectedIndex: 0 adapterPosition: 9
SelectedIndex: 0 adapterPosition: 2
SelectedIndex: 0 adapterPosition: 0
SelectedIndex: 0 adapterPosition: 7
SelectedIndex: 0 adapterPosition: 9
看看它在滚动时是如何跳过adapterPositions的?因此,如果在滚动期间adapterPosition 8 永远不会恢复,那么adapterPosition8 处的视图永远不会在updateView() 方法中关闭。
【问题讨论】:
-
你适配了adapter的
onBindViewHolder()来设置itemViews的选择状态了吗?
标签: android android-recyclerview