gpt4 book ai didi

android - 在复合 View 小部件上保存状态

转载 作者:塔克拉玛干 更新时间:2023-11-02 08:29:05 27 4
gpt4 key购买 nike

问题

当通过使用 XML 定义的小部件布局,各个小部件实例的组件都具有相同的 ID 时,您如何保存 View 小部件实例状态?

例子

TimePicker 小部件中使用的 NumberPicker 小部件为例(请注意,NumberPicker 未向 SDK 公开)。这是一个简单的小部件,包含三个从 number_picker.xml 扩展而来的组件:一个递增按钮、一个递减按钮和一个可以直接输入数字的 EditText。为了让代码与这些小部件交互,它们都有 ID(R.id.incrementR.id.decrementR.id.timepicker_input 分别)。

假设您在 XML 布局中有三个 NumberPicker,并且您为它们指定了不同的 ID(例如,R.id.hourR.id。 minute).¹ 然后,此布局会膨胀到 Activity 的内容 View 。我们决定更改 Activity 的方向,因此 Activity.onSaveInstanceState(Bundle) 有助于为每个具有 ID 的 View 保存我们的 View 状态(这是默认行为)。

不幸的是,三个 NumberPickerEditText 都共享相同的 ID — R.id.timepicker_input。因此,当 Activity 恢复时, View 层次结构中最下方的那个是其状态似乎为所有三个 View 保留的那个。此外,焦点会在恢复时转到第一个 NumberPicker,而不管保存时哪个有焦点。

TimePicker 通过单独保存状态本身来解决这个问题。不幸的是,如果不做更多的工作,这将无法保留光标位置或聚焦 View 。我不确定它是如何保留该状态的(如果它确实存在的话)(并且快速播放时间输入对话框似乎表明它可以以某种方式保留)。

请查看示例代码来演示此问题: https://github.com/xxv/AndroidNumberPickerBug


¹ 在 View 层次结构中,这会设置 NumberPicker 扩展到您的 ID 的 LinearLayout 的 ID。

最佳答案

我在尝试创建自己的复合 View 时偶然发现了同样的问题。通过查看 Android 源代码,我认为实现复合 View 的正确方法是复合 View 本身承担保存和恢复其子实例状态的责任,并防止保存和恢复实例状态的调用被调用传递给 subview 。这解决了当您在一个 Activity 中有多个相同复合 View 的实例时, subview 的 ID 不是唯一的问题。

这听起来可能很复杂,但实际上非常简单,而且 API 实际上为这个确切的场景做出了规定。我写了一篇博文 here关于这是如何完成的,但基本上在您的复合 View 中,您需要实现以下 4 种方法,自定义 onSaveInstanceState() 和 onRestoreInstanceState() 以满足您的特定要求。

@Override
protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
return new SavedState(superState, numberPicker1.getValue(), numberPicker2.getValue(), numberPicker3.getValue());
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
SavedState savedState = (SavedState) state;
super.onRestoreInstanceState(savedState.getSuperState());

numberPicker1.setValue(savedState.getNumber1());
numberPicker2.setValue(savedState.getNumber2());
numberPicker3.setValue(savedState.getNumber3());
}

@Override
protected void dispatchSaveInstanceState(SparseArray container) {
// As we save our own instance state, ensure our children don't save
// and restore their state as well.
super.dispatchFreezeSelfOnly(container);
}

@Override
protected void dispatchRestoreInstanceState(SparseArray container) {
/** See comment in {@link #dispatchSaveInstanceState(android.util.SparseArray)} */
super.dispatchThawSelfOnly(container);
}

关于 NumberPicker/TimePicker 的问题,如另一条评论中所述,NumberPicker 和 TimePicker 似乎存在错误。要修复它,您可以覆盖两者并实现我描述的解决方案。

关于android - 在复合 View 小部件上保存状态,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4932179/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com