Android编程权威指南第三版 第31章

一、设备旋转问题

1.问题

设备旋转后,已绘制的矩形框会消失。要解决这个问题,可使用以下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)方法 把结果发送给超类。 

2.解决办法

首先,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");
    }

二、旋转矩形框

1.问题

请实现以两根手指旋转矩形框。这个练习有点难,想完成它,需在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常量的用法。 

2.解决办法

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

 

你可能感兴趣的:(Android编程权威指南第三版 第31章)