设备旋转后,已绘制的矩形框会消失。要解决这个问题,可使用以下View方法:
protected Parcelable onSaveInstanceState()
protected void onRestoreInstanceState(Parcelable state)
以上方法的工作方式不同于Activity和Fragment的onSaveInstanceState(Bundle)方 法。首先,View视图有ID时,才可以调用它们。其次,相较于Bundle参数,这些方法返回并处 理的是实现Parcelable接口的对象。推荐使用Bundle,这样就不用自己实现Parcelable接口了。 (Parcelable接口的实现很复杂,如有可能,应尽量避免。) 最后,还需要保存BoxDrawingView的View父视图的状态。在Bundle中保存super. onSaveInstanceState()方法结果,然后调用super.onRestoreInstanceState(Parcelable)方法 把结果发送给超类。
首先,View要有ID
android:id="@+id/box_draw_view"
其次使用onSaveInstanceState、onRestoreInstanceState两个方法
//保存数据
@Override
protected Parcelable onSaveInstanceState() {
saveStateBundle = new Bundle();
saveStateBundle.putParcelable("onSaveInstanceState",super.onSaveInstanceState());
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)bundle.getSerializable("mBoxen");
}
请实现以两根手指旋转矩形框。这个练习有点难,想完成它,需在MotionEvent实现代码中 处理多个触控点(pointer)。当然,还要旋转canvas。 要处理多点触摸,先清楚以下概念。
pointer index:获知当前一组触控点中,动作事件对应的触控点。
pointer ID:给予手势中特定手指一个唯一的ID。
pointer index可能会变,但pointer ID绝对不会变。
请查阅开发者文档,学习以下MotionEvent方法的使用:
public final int getActionMasked()
public final int getActionIndex()
public final int getPointerId(int pointerIndex)
public final float getX(int pointerIndex)
public final float getY(int pointerIndex)
另外,还需查查ACTION_POINTER_UP和ACTION_POINTER_DOWN常量的用法。
@Override
public boolean onTouchEvent(MotionEvent event){
PointF current=new PointF(event.getX(),event.getY());
String action="";
switch(event.getActionMasked()){
case MotionEvent.ACTION_DOWN:
action="ACTION_DOWN";
mCurrentBox=new Box(current);
mBoxen.add(mCurrentBox);
//当第一个手指触摸到屏幕后,记录第一个触控点的ID
pointer1=event.getPointerId(event.getActionIndex());
break;
case MotionEvent.ACTION_POINTER_DOWN:
action="ACTION_POINTER_DOWN";
//当第二个手指触摸到屏幕后,记录第二个触控点的ID
pointer2=event.getPointerId(event.getActionIndex());
//得到第一,第二个触控点的横,纵坐标
fx = event.getX(event.findPointerIndex(pointer1));
fy = event.getY(event.findPointerIndex(pointer1));
sx = event.getX(event.findPointerIndex(pointer2));
sy=event.getY(event.findPointerIndex(pointer2));
mCurrentBox=null;
break;
case MotionEvent.ACTION_UP:
action="ACTION_UP";
pointer1=-1;
mCurrentBox=null;
break;
case MotionEvent.ACTION_POINTER_UP:
action="ACTION_POINTER_UP";
pointer2=-1;
break;
case MotionEvent.ACTION_MOVE:
action="ACTION_MOVE";
if(pointer1!=removed && pointer2!=removed){
//得到手指移动后第一,第二个触控点的横,纵坐标
float nfx=event.getX(event.findPointerIndex(pointer1));
float nfy=event.getY(event.findPointerIndex(pointer1));
float nsx=event.getX(event.findPointerIndex(pointer2));
float nsy=event.getY(event.findPointerIndex(pointer2));
//计算移动前后的角度差值
float mAngle = angleBetweenLines(fx, fy, sx, sy, nfx, nfy, nsx, nsy);
}
if(mCurrentBox!=null && pointer2==removed){
mCurrentBox.setmCurrent(current);
}
invalidate();
break;
case MotionEvent.ACTION_CANCEL:
action="ACTION_CANCEL";
mCurrentBox=null;
pointer1=-1;
pointer2=-1;
break;
default:;
}
Log.d(TAG,"action "+action+" at x="+current.x+" y="+current.y);
return true;
}
public float angleBetweenLines(float fx, float fy, float sx, float sy, float nfx, float nfy, float nsx, float nsy){
float radian1=(float)Math.atan2(fy-sy,fx-sx);
float radian2=(float)Math.atan2(nfy-nsy,nfx-nsx);
float angle=(float)(Math.toDegrees(radian2-radian1)%360);
if(angle<0){
angle+=360;
}
return angle;
}