对于作业,我必须使用一些预定义的项目进行回收查看,并且点击其中的每一项都会在另一个视图中执行某些操作。这一切都运行良好,可能对我的任务来说已经足够好了,但我对它并不满意,因为没有任何东西显示选择的项目等等。
因此,无论何时选择列表项,我都希望对其进行背景突出显示。经过一番搜索,我发现了一个类似问题的答案: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永远不会恢复,那么在updateView()方法中,adapterPosition8上的视图永远不会被关闭。
答案 0 :(得分:0)
您必须将项目状态保留在“onBindViewHolder”方法中。 此外,你应该管理视图持有者内部的onItemClick,因为在那里,你正好在你想要的位置,所以基本上你会有:
YourAdapter.java
@Override
public void onBindViewHolder(YourViewHolder yourViewHolder, int i) {
yourViewHolder.updateView();
}
YourViewHolder.java
class YourViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
View itemView;
public YourViewHolder(View itemView){
this.itemView = itemView;
}
public void updateView(){
//Do whatever you need to do regarding the item view
this.itemView.setSelected(getAdapterPosition() == mSelectedIndex);
}
@Override
public void onClick(View v) {
int position = getAdapterPosition();
if (position == mSelectedIndex){
//It's the same view, deselect it or just leave it as it is
} else {
this.itemView.setSelected(true);
mSelectedIndex = position;
}
}
}
请记住,不应将mSelectedIndex放在ViewHolder中,而应放在单独的类中。