Android matrix 控制图片的旋转、缩放、移动


本文主要讲解利用Android中Matrix控制图形的旋转缩放移动,具体参见一下代码:

 
  1. /** 
  2.  * 使用矩阵控制图片移动、缩放、旋转 
  3.  * @author 张进 
  4.  */  
  5. public class CommonImgEffectView extends View {  
  6.   
  7.     private Context context ;  
  8.     private Bitmap mainBmp , controlBmp ;  
  9.     private int mainBmpWidth , mainBmpHeight , controlBmpWidth , controlBmpHeight ;  
  10.     private Matrix matrix ;   
  11.     private float [] srcPs , dstPs ;  
  12.     private RectF srcRect , dstRect ;  
  13.     private Paint paint ,paintRect , paintFrame;  
  14.     private float deltaX = 0, deltaY = 0//位移值   
  15.     private float scaleValue = 1//缩放值   
  16.     private Point lastPoint ;  
  17.     private Point prePivot , lastPivot;  
  18.     private float preDegree , lastDegree ;  
  19.     private short currentSelectedPointindex;        //当前操作点击点   
  20.     private Point symmetricPoint  = new Point();    //当前操作点对称点   
  21.       
  22.     /** 
  23.      * 图片操作类型 
  24.      */  
  25.     public static final int OPER_DEFAULT = -1;      //默认   
  26.     public static final int OPER_TRANSLATE = 0;     //移动   
  27.     public static final int OPER_SCALE = 1;         //缩放   
  28.     public static final int OPER_ROTATE = 2;        //旋转   
  29.     public static final int OPER_SELECTED = 3;      //选择   
  30.     public int lastOper = OPER_DEFAULT;  
  31.       
  32.     /* 图片控制点 
  33.      * 0---1---2 
  34.      * |       | 
  35.      * 7   8   3 
  36.      * |       | 
  37.      * 6---5---4  
  38.      */  
  39.     public static final int CTR_NONE = -1;  
  40.     public static final int CTR_LEFT_TOP = 0;  
  41.     public static final int CTR_MID_TOP = 1;  
  42.     public static final int CTR_RIGHT_TOP = 2;  
  43.     public static final int CTR_RIGHT_MID = 3;  
  44.     public static final int CTR_RIGHT_BOTTOM = 4;  
  45.     public static final int CTR_MID_BOTTOM = 5;  
  46.     public static final int CTR_LEFT_BOTTOM = 6;  
  47.     public static final int CTR_LEFT_MID = 7;  
  48.     public static final int CTR_MID_MID = 8;  
  49.     public int current_ctr = CTR_NONE;  
  50.       
  51.     public CommonImgEffectView(Context context){  
  52.         super(context);  
  53.         this.context = context ;  
  54.     }  
  55.       
  56.     public CommonImgEffectView(Context context, AttributeSet attrs) {  
  57.         super(context, attrs);  
  58.         this.context = context ;  
  59.         initData();  
  60.     }  
  61.       
  62.     /** 
  63.      * 初始化数据 
  64.      * @author 张进 
  65.      */  
  66.     private void initData(){  
  67.         mainBmp = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.flower);  
  68.         controlBmp = BitmapFactory.decodeResource(this.context.getResources(), R.drawable.control);  
  69.         mainBmpWidth = mainBmp.getWidth();  
  70.         mainBmpHeight = mainBmp.getHeight();  
  71.         controlBmpWidth = controlBmp.getWidth();  
  72.         controlBmpHeight = controlBmp.getHeight();  
  73.           
  74.         srcPs = new float[]{  
  75.                                 0,0,   
  76.                                 mainBmpWidth/2,0,   
  77.                                 mainBmpWidth,0,   
  78.                                 mainBmpWidth,mainBmpHeight/2,  
  79.                                 mainBmpWidth,mainBmpHeight,   
  80.                                 mainBmpWidth/2,mainBmpHeight,   
  81.                                 0,mainBmpHeight,   
  82.                                 0,mainBmpHeight/2,   
  83.                                 mainBmpWidth/2,mainBmpHeight/2  
  84.                             };  
  85.         dstPs = srcPs.clone();  
  86.         srcRect = new RectF(00, mainBmpWidth, mainBmpHeight);  
  87.         dstRect = new RectF();  
  88.           
  89.         matrix = new Matrix();  
  90.           
  91.         prePivot = new Point(mainBmpWidth/2, mainBmpHeight/2);  
  92.         lastPivot = new Point(mainBmpWidth/2, mainBmpHeight/2);  
  93.           
  94.         lastPoint = new Point(0,0);  
  95.           
  96.         paint = new Paint();  
  97.           
  98.         paintRect = new Paint();  
  99.         paintRect.setColor(Color.RED);  
  100.         paintRect.setAlpha(100);  
  101.         paintRect.setAntiAlias(true);  
  102.           
  103.         paintFrame = new Paint();  
  104.         paintFrame.setColor(Color.GREEN);  
  105.         paintFrame.setAntiAlias(true);  
  106.           
  107.         setMatrix(OPER_DEFAULT);  
  108.     }  
  109.       
  110.     /** 
  111.      * 矩阵变换,达到图形平移的目的 
  112.      * @author 张进 
  113.      */  
  114.     private void setMatrix(int operationType){  
  115.         switch (operationType) {  
  116.         case OPER_TRANSLATE:  
  117.             matrix.postTranslate(deltaX , deltaY);  
  118.             break;  
  119.         case OPER_SCALE:  
  120.             matrix.postScale(scaleValue, scaleValue, symmetricPoint.x, symmetricPoint.y);  
  121.             break;  
  122.         case OPER_ROTATE:  
  123.             matrix.postRotate(preDegree - lastDegree, dstPs[CTR_MID_MID * 2], dstPs[CTR_MID_MID * 2 + 1]);  
  124.             break;  
  125.         }  
  126.           
  127.         matrix.mapPoints(dstPs, srcPs);  
  128.         matrix.mapRect(dstRect, srcRect);  
  129.     }  
  130.       
  131.     private boolean isOnPic(int x , int y){  
  132.         if(dstRect.contains(x, y)){  
  133.             return true;  
  134.         }else   
  135.             return false;  
  136.     }  
  137.       
  138.     private int getOperationType(MotionEvent event){  
  139.   
  140.         int evX = (int)event.getX();  
  141.         int evY = (int)event.getY();  
  142.         int curOper = lastOper;  
  143.         switch(event.getAction()) {  
  144.             case MotionEvent.ACTION_DOWN:  
  145.                 current_ctr = isOnCP(evX, evY);  
  146.                 Log.i("img""current_ctr is "+current_ctr);  
  147.                 if(current_ctr != CTR_NONE || isOnPic(evX, evY)){  
  148.                     curOper = OPER_SELECTED;  
  149.                 }  
  150.                 break;  
  151.             case MotionEvent.ACTION_MOVE:  
  152.                     if(current_ctr > CTR_NONE && current_ctr < CTR_MID_MID ){  
  153.                         curOper = OPER_SCALE;  
  154.                     }else if(current_ctr == CTR_MID_MID ){  
  155.                         curOper = OPER_ROTATE;  
  156.                     }else if(lastOper == OPER_SELECTED){  
  157.                         curOper = OPER_TRANSLATE;  
  158.                     }  
  159.                 break;  
  160.             case MotionEvent.ACTION_UP:  
  161.                 curOper = OPER_SELECTED;  
  162.                 break;  
  163.             default:  
  164.                 break;  
  165.         }  
  166.         Log.d("img""curOper is "+curOper);  
  167.         return curOper;  
  168.           
  169.     }  
  170.       
  171.      /** 
  172.      * 判断点所在的控制点 
  173.      * @param evX 
  174.      * @param evY 
  175.      * @return 
  176.      */   
  177.     private int isOnCP(int evx, int evy) {  
  178.         Rect rect = new Rect(evx-controlBmpWidth/2,evy-controlBmpHeight/2,evx+controlBmpWidth/2,evy+controlBmpHeight/2);  
  179.         int res = 0 ;  
  180.         for (int i = 0; i < dstPs.length; i+=2) {  
  181.             if(rect.contains((int)dstPs[i], (int)dstPs[i+1])){  
  182.                 return res ;  
  183.             }  
  184.             ++res ;   
  185.         }  
  186.         return CTR_NONE;  
  187.     }  
  188.       
  189.       
  190.       
  191.     @Override  
  192.     public boolean dispatchTouchEvent(MotionEvent event) {  
  193.         int evX = (int)event.getX();  
  194.         int evY = (int)event.getY();  
  195.           
  196.         int operType = OPER_DEFAULT;  
  197.         operType = getOperationType(event);  
  198.           
  199.         switch (operType) {  
  200.         case OPER_TRANSLATE:  
  201.             translate(evX, evY);  
  202.             break;  
  203.         case OPER_SCALE:  
  204.             scale(event);  
  205.             break;  
  206.         case OPER_ROTATE:  
  207.             rotate(event);  
  208.             break;  
  209.         }  
  210.       
  211.         lastPoint.x = evX;  
  212.         lastPoint.y = evY;    
  213.           
  214.         lastOper = operType;  
  215.         invalidate();//重绘   
  216.         return true;  
  217.     }  
  218.   
  219.     /** 
  220.      * 移动 
  221.      * @param evx 
  222.      * @param evy 
  223.      * @author zhang_jin1 
  224.      */  
  225.     private void translate(int evx , int evy){  
  226.           
  227.         prePivot.x += evx - lastPoint.x;  
  228.         prePivot.y += evy -lastPoint.y;  
  229.           
  230.         deltaX = prePivot.x - lastPivot.x;  
  231.         deltaY = prePivot.y - lastPivot.y;  
  232.           
  233.         lastPivot.x = prePivot.x;  
  234.         lastPivot.y = prePivot.y;  
  235.           
  236.         setMatrix(OPER_TRANSLATE); //设置矩阵   
  237.           
  238.     }  
  239.       
  240.     /** 
  241.      * 缩放 
  242.      * 0---1---2 
  243.      * |       | 
  244.      * 7   8   3 
  245.      * |       | 
  246.      * 6---5---4 
  247.      * @param evX 
  248.      * @param evY 
  249.      */  
  250.     private void scale(MotionEvent event) {  
  251.           
  252.         int pointIndex = current_ctr*2 ;  
  253.           
  254.         float px = dstPs[pointIndex];  
  255.         float py = dstPs[pointIndex+1];  
  256.           
  257.         float evx = event.getX();  
  258.         float evy = event.getY();  
  259.           
  260.         float oppositeX = 0 ;  
  261.         float oppositeY = 0 ;  
  262.         if(current_ctr<4 && current_ctr >= 0){  
  263.              oppositeX = dstPs[pointIndex+8];  
  264.              oppositeY = dstPs[pointIndex+9];  
  265.         }else if(current_ctr >= 4){  
  266.              oppositeX = dstPs[pointIndex-8];  
  267.              oppositeY = dstPs[pointIndex-7];  
  268.         }  
  269.         float temp1 = getDistanceOfTwoPoints(px,py,oppositeX,oppositeY);  
  270.         float temp2 = getDistanceOfTwoPoints(evx,evy,oppositeX,oppositeY);  
  271.           
  272.         this.scaleValue = temp2 / temp1 ;  
  273.         symmetricPoint.x = (int) oppositeX;  
  274.         symmetricPoint.y = (int)oppositeY;  
  275.           
  276.         Log.i("img""scaleValue is "+scaleValue);  
  277.         setMatrix(OPER_SCALE);  
  278.     }  
  279.       
  280.     /** 
  281.      * 旋转图片 
  282.      * 0---1---2 
  283.      * |       | 
  284.      * 7   8   3 
  285.      * |       | 
  286.      * 6---5---4  
  287.      * @param evX 
  288.      * @param evY 
  289.      */  
  290.     private void rotate(MotionEvent event) {  
  291.          
  292.         if(event.getPointerCount() == 2){  
  293.             preDegree = computeDegree(new Point((int)event.getX(0), (int)event.getY(0)), new Point((int)event.getX(1), (int)event.getY(1)));  
  294.         }else{  
  295.             preDegree = computeDegree(new Point((int)event.getX(), (int)event.getY()), new Point((int)dstPs[16], (int)dstPs[17]));  
  296.         }  
  297.         setMatrix(OPER_ROTATE);  
  298.         lastDegree = preDegree;  
  299.     }  
  300.       
  301.       
  302.     /** 
  303.      * 计算两点与垂直方向夹角 
  304.      * @param p1 
  305.      * @param p2 
  306.      * @return 
  307.      */  
  308.     public float computeDegree(Point p1, Point p2){  
  309.         float tran_x = p1.x - p2.x;  
  310.         float tran_y = p1.y - p2.y;  
  311.         float degree = 0.0f;  
  312.         float angle = (float)(Math.asin(tran_x/Math.sqrt(tran_x*tran_x + tran_y* tran_y))*180/Math.PI);  
  313.         if(!Float.isNaN(angle)){  
  314.             if(tran_x >= 0 && tran_y <= 0){//第一象限   
  315.                 degree = angle;  
  316.             }else if(tran_x <= 0 && tran_y <= 0){//第二象限   
  317.                 degree = angle;  
  318.             }else if(tran_x <= 0 && tran_y >= 0){//第三象限   
  319.                 degree = -180 - angle;  
  320.             }else if(tran_x >= 0 && tran_y >= 0){//第四象限   
  321.                 degree = 180 - angle;  
  322.             }  
  323.         }  
  324.         return degree;  
  325.     }  
  326.       
  327.     /** 
  328.      * 计算两个点之间的距离 
  329.      * @param p1 
  330.      * @param p2 
  331.      * @return 
  332.      */  
  333.     private float getDistanceOfTwoPoints(Point p1, Point p2){  
  334.         return (float)(Math.sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)));  
  335.     }  
  336.       
  337.     private float getDistanceOfTwoPoints(float x1,float y1,float x2,float y2){  
  338.         return (float)(Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)));  
  339.     }  
  340.       
  341.       
  342.     @Override  
  343.     public void onDraw(Canvas canvas){  
  344.         drawBackground(canvas);//绘制背景,以便测试矩形的映射   
  345.         canvas.drawBitmap(mainBmp, matrix, paint);//绘制主图片   
  346.         drawFrame(canvas);//绘制边框,以便测试点的映射   
  347.         drawControlPoints(canvas);//绘制控制点图片   
  348.     }  
  349.       
  350.     private void drawBackground(Canvas canvas){  
  351.         canvas.drawRect(dstRect, paintRect);  
  352.     }  
  353.       
  354.     private void drawFrame(Canvas canvas){  
  355.         canvas.drawLine(dstPs[0], dstPs[1], dstPs[4], dstPs[5], paintFrame);  
  356.         canvas.drawLine(dstPs[4], dstPs[5], dstPs[8], dstPs[9], paintFrame);  
  357.         canvas.drawLine(dstPs[8], dstPs[9], dstPs[12], dstPs[13], paintFrame);  
  358.         canvas.drawLine(dstPs[0], dstPs[1], dstPs[12], dstPs[13], paintFrame);  
  359.         canvas.drawPoint(dstPs[16], dstPs[17], paintFrame);  
  360.     }  
  361.       
  362.     private void drawControlPoints(Canvas canvas){  
  363.           
  364.         for (int i = 0; i < dstPs.length; i+=2) {  
  365.             canvas.drawBitmap(controlBmp, dstPs[i]-controlBmpWidth/2, dstPs[i+1]-controlBmpHeight/2, paint);  
  366.         }  
  367.           
  368.     }  
  369.       
  370. }  

Demo效果:


相关内容