此问题是《Android编程权威指南》的第29章的29.5小节挑战练习:设备旋转问题。
从书本提示中可看出,要解决设备旋转后,绘制的矩形框会消失,需要注意的几点:
1.重写View的以下方法,用来保存数据和恢复数据:
protected Parcelable onSaveInstanceState()
protected Parcelable onRestoreInstanceState(Parcelable state)
2.View视图要有ID,只有这样,上面两个方法才会被调用:
<?xml version="1.0" encoding="utf-8"?>
<com.example.administrator.boxdrawingview.BoxDrawingView
xmlns:android="http://schemas.android.com/apk/res/android"
**android:id="@+id/box_drawing_view"**
android:layout_width="match_parent"
android:layout_height="match_parent"
>
</com.example.administrator.boxdrawingview.BoxDrawingView>
3.因为实现Parcelable比较繁琐,用Bundle保存状态数据。
4.需要保存View父视图的状态,在Bundle中保存super.onSaveInstanceState()方法结果,然后调用 super.onRestoreInstanceState(state)把结果发送给超类。
整个实现,BoxDrawingView.java文件为:
public class BoxDrawingView extends View {
private static final String TAG = "BoxDrawingView";
private Box mCurrentBox;
private Paint mBoxPaint;
private Paint mBackgroundPaint;
// 定制视图的List
private List<Box> mBoxen = new ArrayList<>();
// 保存状态数据,用Bundle
private Bundle saveStateBundle;
// 1.使用View的以下方法,用来保存数据和恢复数据:
// protected Parcelable onSaveInstanceState()
// protected Parcelable onRestoreInstanceState(Parcelable state)
@Override
protected Parcelable onSaveInstanceState() {
saveStateBundle = new Bundle();
// 在Bundle中保存父视图状态,恢复状态时会将此发送给超类
saveStateBundle.putParcelable("onSaveInstanceState", super.onSaveInstanceState());
// 保存当前的状态数据,bundle保存List<Object>,强转Serializable
saveStateBundle.putSerializable("mBoxen", (Serializable) mBoxen);
return saveStateBundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
Bundle bundle = (Bundle) state;
// 将父视图状态取出,发送给超类
Parcelable restoreState = bundle.getParcelable("onSaveInstanceState");
super.onRestoreInstanceState(restoreState);
// 恢复状态数据
mBoxen = (List<Box>) bundle.getSerializable("mBoxen");
}
public BoxDrawingView(Context context) {
super(context);
}
public BoxDrawingView(Context context, AttributeSet attrs) {
super(context, attrs);
mBoxPaint = new Paint();
mBoxPaint.setColor(0x22ff0000);
mBackgroundPaint = new Paint();
mBackgroundPaint.setColor(0xfff8efe0);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
PointF current = new PointF(event.getX(), event.getY());
String action = "";
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
action = "ACTION_DOWN";
mCurrentBox = new Box(current);
mBoxen.add(mCurrentBox);
break;
case MotionEvent.ACTION_MOVE:
action = "ACTION_MOVE";
if (mCurrentBox != null) {
mCurrentBox.setCurrent(current);
invalidate();
}
break;
case MotionEvent.ACTION_UP:
action = "ACTION_UP";
mCurrentBox = null;
break;
case MotionEvent.ACTION_CANCEL:
action = "ACTION_CANCEL";
mCurrentBox = null;
break;
}
Log.i(TAG, action + "at x=" + current.x + ", y=" + current.y);
return true;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawPaint(mBackgroundPaint);
for (Box box : mBoxen) {
float left = Math.min(box.getOrigin().x, box.getCurrent().x);
float right = Math.max(box.getOrigin().x, box.getCurrent().x);
float top = Math.min(box.getOrigin().y, box.getCurrent().y);
float bottom = Math.max(box.getOrigin().y, box.getCurrent().y);
canvas.drawRect(left, top, right, bottom, mBoxPaint);
}
}
}