您的位置:首页 > 移动开发 > Android开发

Android 自定义组件及组件如何保存/恢复状态

2016-05-26 18:10 411 查看
此文是参考《Android用户界面设计》而写的,主要目的是为了记录,备忘,及分享。

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);
}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: