Android 自定义组件及组件如何保存/恢复状态
2016-05-26 18:10
411 查看
此文是参考《Android用户界面设计》而写的,主要目的是为了记录,备忘,及分享。
Android屏幕旋转禁止重新加载布局,可以在Manifest.xml中配置一下属性来实现。
我们此处讨论的是:在屏幕旋转,重新加载布局文件的情况下,如何保存和恢复状态。
关于Android自定义组件保存和恢复状态之前一直没有研究,所熟悉的也仅仅是Activity如何保存和恢复状态。但是对于代码规范来说,在自定义组件内部进行状态的保存和恢复至关重要。
此组件是类似于RadioButton似的单选开关组件,效果如下:
首先,创建一个继承于LinearLayout的控件。并创建initView方法
此段代码的作用就是在自定义组件中创建三个ToggleButton,可以看一下效果,在选中第三个开关后,旋转屏幕,控件又重新加载了。还是回到了第一个Button被选中的状态。
想要改变这种情况就需要用到下面的内容了。
首先在initView()函数中设置setSaveEnabled(true);此方法的作用是请求视图保存状态。也可以不写,因为View默认的就是true。但是参考编程规范,还是写上的好。
扩展BaseSavedState类,作为状态保存的媒介,它是一个Parcelable类,可以在Activity被拆除和重建时被有效的传递开。创建类SaveState扩展BaseSavedState类,记录被选中的按钮。任何继承于Parcelable的类都要创建一个名为CREATOR的公共域来执行Parcelable.Creator接口。
代码如下:
重写方法onSaveInstanceState 来保存视图状态:
重写方法onRestoreInstanceState 来恢复视图状态:
此时,再次旋转屏幕,就会保存并恢复当前状态。
全部代码如下:
Android屏幕旋转禁止重新加载布局,可以在Manifest.xml中配置一下属性来实现。
android:configChanges="keyboardHidden|screenSize|orientation"
我们此处讨论的是:在屏幕旋转,重新加载布局文件的情况下,如何保存和恢复状态。
关于Android自定义组件保存和恢复状态之前一直没有研究,所熟悉的也仅仅是Activity如何保存和恢复状态。但是对于代码规范来说,在自定义组件内部进行状态的保存和恢复至关重要。
此组件是类似于RadioButton似的单选开关组件,效果如下:
首先,创建一个继承于LinearLayout的控件。并创建initView方法
<pre name="code" class="java">public class MultiButton extends LinearLayout implements View.OnClickListener { CompoundButton mSelectButton; public MultiButton(Context context) { super(context); initView(context,null); } public MultiButton(Context context, AttributeSet attrs) { super(context, attrs); initView(context,attrs); } public MultiButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context, attrs); } void initView(Context context,AttributeSet set){ for (int i = 0; i < 3; i++) { final CompoundButton toggleButton = new ToggleButton(context); addView(toggleButton); toggleButton.setOnClickListener(this); if (i == 0) { mSelectButton = toggleButton; mSelectButton.setChecked(true); } } } @Override public void onClick(View v) { CompoundButton btn = (CompoundButton) v; btn.setChecked(true); if (btn != mSelectButton) { mSelectButton.setChecked(false); mSelectButton = btn; } } }
此段代码的作用就是在自定义组件中创建三个ToggleButton,可以看一下效果,在选中第三个开关后,旋转屏幕,控件又重新加载了。还是回到了第一个Button被选中的状态。
想要改变这种情况就需要用到下面的内容了。
首先在initView()函数中设置setSaveEnabled(true);此方法的作用是请求视图保存状态。也可以不写,因为View默认的就是true。但是参考编程规范,还是写上的好。
扩展BaseSavedState类,作为状态保存的媒介,它是一个Parcelable类,可以在Activity被拆除和重建时被有效的传递开。创建类SaveState扩展BaseSavedState类,记录被选中的按钮。任何继承于Parcelable的类都要创建一个名为CREATOR的公共域来执行Parcelable.Creator接口。
代码如下:
@SuppressLint("ParcelCreator") class SaveState extends BaseSavedState{ int selectPosition; final Creator<SaveState> CREATOR = new Creator<SaveState>(){ @Override public SaveState createFromParcel(Parcel source) { return new SaveState(source); } @Override public SaveState[] newArray(int size) { return new SaveState[size]; } }; @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(selectPosition); } public SaveState(Parcel source) { super(source); selectPosition = source.readInt(); } public SaveState(Parcelable superState) { super(superState); } }
重写方法onSaveInstanceState 来保存视图状态:
@Override protected Parcelable onSaveInstanceState() { Parcelable parcelable = super.onSaveInstanceState(); SaveState saveState = new SaveState(parcelable); int childCount = getChildCount(); for (int i=0;i<childCount;i++){ if(mSelectButton==getChildAt(i)){ saveState.selectPosition = i; break; } } return saveState; }
重写方法onRestoreInstanceState 来恢复视图状态:
@Override protected void onRestoreInstanceState(Parcelable state) { if (!(state instanceof SaveState)){ super.onRestoreInstanceState(state); return; } SaveState saveState = (SaveState)state; super.onRestoreInstanceState(saveState.getSuperState()); mSelectButton.setChecked(false); mSelectButton = (CompoundButton) getChildAt(saveState.selectPosition); mSelectButton.setChecked(true); }
此时,再次旋转屏幕,就会保存并恢复当前状态。
全部代码如下:
public class MultiButton extends LinearLayout implements View.OnClickListener { CompoundButton mSelectButton; public MultiButton(Context context) { super(context); initView(context,null); } public MultiButton(Context context, AttributeSet attrs) { super(context, attrs); initView(context,attrs); } public MultiButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initView(context, attrs); } void initView(Context context,AttributeSet set){ setSaveEnabled(true); for (int i = 0; i < 3; i++) { final CompoundButton toggleButton = new ToggleButton(context); addView(toggleButton); toggleButton.setOnClickListener(this); if (i == 0) { mSelectButton = toggleButton; mSelectButton.setChecked(true); } } } @Override public void onClick(View v) { CompoundButton btn = (CompoundButton) v; btn.setChecked(true); if (btn != mSelectButton) { mSelectButton.setChecked(false); mSelectButton = btn; } } @SuppressLint("ParcelCreator") class SaveState extends BaseSavedState{ int selectPosition; final Creator<SaveState> CREATOR = new Creator<SaveState>(){ @Override public SaveState createFromParcel(Parcel source) { return new SaveState(source); } @Override public SaveState[] newArray(int size) { return new SaveState[size]; } }; @Override public void writeToParcel(Parcel out, int flags) { super.writeToParcel(out, flags); out.writeInt(selectPosition); } public SaveState(Parcel source) { super(source); selectPosition = source.readInt(); } public SaveState(Parcelable superState) { super(superState); } } @Override protected Parcelable onSaveInstanceState() { Parcelable parcelable = super.onSaveInstanceState(); SaveState saveState = new SaveState(parcelable); int childCount = getChildCount(); for (int i=0;i<childCount;i++){ if(mSelectButton==getChildAt(i)){ saveState.selectPosition = i; break; } } return saveState; } @Override protected void onRestoreInstanceState(Parcelable state) { if (!(state instanceof SaveState)){ super.onRestoreInstanceState(state); return; } SaveState saveState = (SaveState)state; super.onRestoreInstanceState(saveState.getSuperState()); mSelectButton.setChecked(false); mSelectButton = (CompoundButton) getChildAt(saveState.selectPosition); mSelectButton.setChecked(true); } }
相关文章推荐
- android 开源
- 关于Android 添加系统级(java)服务和调用的编写实现说明
- Android:解决Gradle DSL method not found: 'runProguard()' 问题
- 给android增加屏幕校准
- RecyclerView入门
- Android中通过注解代替findViewById方法
- 国内镜像 android源码下载,无需翻墙
- Android中自动跳转到系统设置界面
- 各版本Android Support包里究竟有什么
- Android6.0更新内容介绍
- android手机访问本地电脑Web服务器
- Android Studio常用插件
- Android--ViewPager的使用(未使用fragment)
- Android 按下home键,程序在后台运行,在launcher里面再点击icon又重新启动了
- 孙孙啊i之项目实战(三) 引导页
- Android background tint颜色渲染
- Android之布局
- Android中getwidth和getmeasuredwidth的区别
- Android Video学习笔记
- android中WebView的Java与JavaScript交互