【发布时间】:2016-10-28 10:25:28
【问题描述】:
TL;DR :当RecyclerView 回收View 或替换Fragment 时,我无法区分RecyclerView 对onBindViewHolder 的调用。
我确实花了很多时间在 SO 上寻找答案,但最终没有任何效果。它所做的就是告诉我答案可能是使用savedInstanceState,但我没有成功使用它。
结构:
- 主要片段
- 主视图
- SwitchFragmentButton
MainView里面是一个FrameLayout,用来存放一个Fragment。
第一个Fragment无所谓,但第二个Fragment是OverviewFragment,其结构为:
- 概述片段
- 回收站查看
- 自定义项目视图
- 文本视图
- 更改文本颜色按钮
- 删除项目按钮
- ...
- 自定义项目视图
- 添加项目按钮
- 回收站查看
我使用的是RecyclerView,因为列表必须是水平的,这是我发现的最简单的方法。
期望的行为:
我希望在单击按钮两次(更改片段然后返回)时保留颜色更改,但在从列表中删除项目然后再次添加时不保留。
问题:
颜色要么一直保存,要么从不保存。在RecyclerView 的适配器中使用onBindViewHolder 设置文本颜色不允许我区分绑定是来自片段替换(我将恢复更改的颜色)还是视图回收(我不会恢复它)
代码:
SwitchFragmentButton 的OnClickListener 调用MainView 的方法
void switchFragment(Fragment fragment) {
FragmentManager fm = mainFragment.getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.mainView_fragment_slot, fragment);
ft.commit();
}
以下是管理颜色的方式(简化):
public class CustomItemView extends FrameLayout {
private TextView textView;
private int color;
/* other attributes */
public CustomItemView(/* any default constructor */) {
super(/* args */);
init();
}
private void init() {
inflate(getContext, R.layout.custom_item_view, this);
textView = (TextView) findViewById(R.id.customItemView_text_view);
ChangeTextColorButton ctcButton = /* ... */;
/* other views */
ctcButton.setOnClickListener(new OnClickListener() {
public void onClick() {
setColor(getColorWithDialogAndAll());
}
}
resetColor();
}
public void resetColor() {
setColor(0xff0000ff);
}
public void setColor(int color) {
this.color = color;
textView.setTextColor(color);
}
/* other methods */
}
这是RecyclerView 的Adapter 定义:
public class MyAdapter extends RecyclerView.Adapter {
private List<MyItem> myItemList = new LinkedList<>();
public void onBindViewHolder(final RecyclerView.ViewHolder holder, int position) {
MyViewHolder viewHolder = (MyViewHolder) holder;
//this is called in both situations
viewHolder.customItemView.resetColor();
}
/* other methods */
private class MyViewHolder extends RecyclerView.ViewHolder {
CustomItemView cutsomItemView;
/* constructor, calling super() and setting the attribute */
}
}
MyItem这里是CustomItemView的核心item(每个MyItem都有它的CustomItemView,每个CustomItemView都有它的MyItem)
注意事项:
minSdkVersion:19.
编辑:
感谢@goldenb,问题已经缩小,出现了两种解决方案。
解决方案 1:
不要替换片段,而是将它们全部添加然后显示/隐藏它们。
void switchFragment(Fragment fragment) {
FragmentManager fm = mainFragment.getChildFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.hide(currentFragment);
ft.show(R.id.mainView_fragment_slot, fragment);
ft.commit();
currentFragment = fragment;
}
此解决方案在某种程度上可行,但不能真正解决问题。它避免删除Fragments,因此状态被保留。
但是,我的问题是关于如何保存然后恢复 Fragment 的状态,所以我不能接受这个作为答案。
解决方案 2:
覆盖OverviewFragment#onPause 以保存状态,并在OverviewFragment#onCreate 中恢复它。
这个解决方案似乎是合理的,我目前正在探索它。然而,它需要在我的项目中进行一些重组,以将数据从 CustomItemView 重新定位到 MyAdapter,因此需要一些时间。
【问题讨论】:
-
伙计,你的问题很有趣,但我不清楚。我认为您应该尝试将其归结为: 1. 最小层次结构,去除不感兴趣的子级和不感兴趣的层 2. 清楚地说明问题所在。
-
作为一个快速响应,请注意,恢复其自己的状态是 view 的责任,而不是你的。覆盖自定义视图的 onSaveInstanceState() 和 onRestoreInstanceState() 方法以保存和恢复其颜色。
-
@natario 1. 你会删除哪个孩子?我试图对上下文给出一个很好的想法。 2.我改写了,看看是否有帮助。 3. 重写这些方法不会导致回收的视图也恢复不需要的颜色吗?
标签: android android-fragments android-lifecycle fragmenttransaction android-savedstate