【发布时间】:2016-04-17 03:11:47
【问题描述】:
EDIT2: 我在holder.showTaskRecyclerView 为false 的条件下明确表示隐藏视图,以便在onBindViewHolder 中明确覆盖true 和false 情况.我还是有同样的问题。
EDIT1:我应该补充一点,如果我使用notifyDataSetChanged() 而不是notifyItemChanged(),tasksRecyclerView 的显示和隐藏效果很好,但这会禁用动画并且成本更高。
我的 ViewHolder 中有一个名为 tasksRecyclerView 的 RecyclerView,它应该在单击视图时显示和隐藏。 (可以这么说,这是主 RecyclerView 内的一个 RecyclerView。):
public class ViewHolder extends RecyclerView.ViewHolder {
public ImageView routineStateImgView;
public TextView alarmTextView;
public TextView routineNameTextView;
public RecyclerView tasksRecyclerView;
public boolean showTaskRecyclerView = false;
public ViewHolder(View routineItemView){
super(routineItemView);
routineItemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//toggle showing TaskRecyclerView
showTaskRecyclerView = !showTaskRecyclerView;
notifyItemChanged(getAdapterPosition());
}
});
routineStateImgView = (ImageView) routineItemView.findViewById(R.id.routineStateImgView);
alarmTextView = (TextView) routineItemView.findViewById(R.id.alarmTextView);
routineNameTextView = (TextView) routineItemView.findViewById(R.id.routineNameTextView);
tasksRecyclerView = (RecyclerView) routineItemView.findViewById(R.id.tasksRecyclerView);
}
public ImageView getRoutineStateImgView() {
return routineStateImgView;
}
public TextView getAlarmTextView(){
return alarmTextView;
}
public TextView getRoutineNameTextView(){
return routineNameTextView;
}
public RecyclerView getTasksRecyclerView(){
return tasksRecyclerView;
}
}
目前,代码中的 onClick 设置为切换 ViewHolder 中定义的变量 (showTaskRecyclerView),然后调用 notifyItemChanged(getAdapterPosition()) 以使用动画更新项目更改。
调用 OnBindViewHolder 时,它会检查切换变量的状态(showTaskRecyclerView,再次)并根据变量隐藏或取消隐藏 RecyclerView。在这个sn-p中使用Log.d方法的那一行之后的代码中可以看到这个逻辑:
public void onBindViewHolder(RoutinesRecyclerViewAdapter.ViewHolder holder, int position) {
//Replace contents of view with data from item in adapterRoutinesList at position.
Routine routine = adapterRoutinesList.get(position);
TasksRecyclerViewAdapter mTasksRecyclerViewAdapter = null;
if(routine == null){
holder.getRoutineStateImgView().setImageResource(android.R.color.transparent);
holder.getAlarmTextView().setText("");
holder.getRoutineNameTextView().setText("");
holder.getTasksRecyclerView().setVisibility(View.GONE);
}else{
DateFormat dayTimeFormat = new SimpleDateFormat("HH:mm", Locale.US);
String dayTimeString = dayTimeFormat.format(routine.getWakeupTime().getTime());
holder.getAlarmTextView().setText(dayTimeString);
holder.getRoutineNameTextView().setText(routine.getName());
if(routine.getEnableRoutine()) {
holder.getRoutineStateImgView().setImageResource(R.drawable.check_mark);
}
else{
holder.getRoutineStateImgView().setImageResource(R.drawable.x_mark);
}
Log.d(TAG, "position: " + position + " holder: " + holder + " show?: " + holder.showTaskRecyclerView);
if(holder.showTaskRecyclerView) {
TasksManager mTasksManager = adapterTasksListCache.get(routine.getId());
if (mTasksManager == null) {
mTasksManager = new TasksManager(routine.getId());
mTasksManager.readTasksFromDisk(mContext);
adapterTasksListCache.put(routine.getId(), mTasksManager);
}
mTasksRecyclerViewAdapter = adapterTasksViewCache.get(routine.getId());
if (mTasksRecyclerViewAdapter == null) {
mTasksRecyclerViewAdapter = new TasksRecyclerViewAdapter(
mContext,
position,
mTasksManager.getTasksListFromCache(),
mRequestImageCaptureCallBack,
mTaskEditTextListener);
adapterTasksViewCache.put(routine.getId(), mTasksRecyclerViewAdapter);
}
RecyclerView.LayoutManager mTaskLayoutManager = new LinearLayoutManager(mContext);
holder.getTasksRecyclerView().setLayoutManager(mTaskLayoutManager);
holder.getTasksRecyclerView().setAdapter(mTasksRecyclerViewAdapter);
holder.getTasksRecyclerView().setHasFixedSize(true);
holder.getTasksRecyclerView().setVisibility(View.VISIBLE);
}
else{
holder.getTasksRecyclerView().setVisibility(View.GONE);
}
}
}
我希望看到 RecyclerView 在每次点击时隐藏或取消隐藏。但是,我只会在每 2 次点击后看到隐藏/取消隐藏行为。
点击 5 次后 Log.d 的输出如下:
04-16 21:33:37.026 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{263b1503 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: false
04-16 21:33:42.626 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: false
04-16 21:33:44.511 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{263b1503 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: true
04-16 21:33:46.274 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: true
04-16 21:33:47.938 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{263b1503 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: false
04-16 21:41:52.756 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: false
我的解释是,使用 notifyItemChanged 会提示使用相同 ViewHolder 的 2 个副本用于过渡动画目的(一个具有视图的旧状态,一个具有新状态)。但是,带有变量的副本在旧副本中错误地更改。我认为我对 notifyItemChanged 的工作原理有错误的理解,所以我来这里寻求帮助:/
另外,当我快速点击时,我不知道是什么导致了问题:如果我点击得足够快(大约不到半秒),我看不到任何变化
logcat 显示如下:
04-16 21:43:54.597 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: true
04-16 21:43:54.862 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{263b1503 position=0 id=-1, oldPos=-1, pLpos:-1 scrap [changeScrap] tmpDetached not recyclable(1) no parent} show?: true
04-16 21:43:55.387 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: true
04-16 21:43:55.668 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{263b1503 position=0 id=-1, oldPos=-1, pLpos:-1 scrap [changeScrap] tmpDetached not recyclable(1) no parent} show?: true
04-16 21:43:55.949 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: true
04-16 21:43:56.189 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{263b1503 position=0 id=-1, oldPos=-1, pLpos:-1 scrap [changeScrap] tmpDetached not recyclable(1) no parent} show?: true
04-16 21:43:56.479 13522-13522/co.edu.javeriana.faros D/RoutinesViewAdapter: position: 0 holder: ViewHolder{883eb98 position=0 id=-1, oldPos=-1, pLpos:-1 no parent} show?: true
有什么想法吗?
【问题讨论】:
标签: android android-layout android-recyclerview android-viewholder