This article mainly explains how to use Matrix in android to control the rotation, scaling, and movement of images. For details, refer to the Code:
Copy codeThe Code is as follows :/**
* Use a matrix to control image movement, scaling, and Rotation
*/
Public class CommonImgEffectView extends View {
Private Context context;
Private Bitmap mainBmp, controlBmp;
Private int mainbmp width, mainBmpHeight, controlbmp width, controlBmpHeight;
Private Matrix matrix;
Private float [] srcPs, dstPs;
Private RectF srcRect, dstRect;
Private Paint paint, paintRect, paintFrame;
Private float deltaX = 0, deltaY = 0; // displacement value
Private float scaleValue = 1; // scaling Value
Private Point lastPoint;
Private Point prefix, lastPivot;
Private float preDegree, lastDegree;
Private short currentSelectedPointindex; // click the current operation
Private Point symmetric ricpoint = new Point (); // The symmetry Point of the current operation Point.
/**
* Image operation type
*/
Public static final int OPER_DEFAULT =-1; // default
Public static final int OPER_TRANSLATE = 0; // move
Public static final int OPER_SCALE = 1; // scale
Public static final int OPER_ROTATE = 2; // rotate
Public static final int OPER_SELECTED = 3; // select
Public int lastOper = OPER_DEFAULT;
/* Image Control Point
* 0---1---2
* |
* 7 8 3
* |
* 6---5---4
*/
Public static final int CTR_NONE =-1;
Public static final int CTR_LEFT_TOP = 0;
Public static final int CTR_MID_TOP = 1;
Public static final int CTR_RIGHT_TOP = 2;
Public static final int CTR_RIGHT_MID = 3;
Public static final int CTR_RIGHT_BOTTOM = 4;
Public static final int CTR_MID_BOTTOM = 5;
Public static final int CTR_LEFT_BOTTOM = 6;
Public static final int CTR_LEFT_MID = 7;
Public static final int CTR_MID_MID = 8;
Public int current_ctr = CTR_NONE;
Public CommonImgEffectView (Context context ){
Super (context );
This. context = context;
}
Public CommonImgEffectView (Context context, AttributeSet attrs ){
Super (context, attrs );
This. context = context;
InitData ();
}
/**
* Initialize data
* @ Author zhangjin
*/
Private void initData (){
MainBmp = BitmapFactory. decodeResource (this. context. getResources (), R. drawable. flower );
ControlBmp = BitmapFactory. decodeResource (this. context. getResources (), R. drawable. control );
MainBmp width = mainBmp. getWidth ();
MainBmpHeight = mainBmp. getHeight ();
ControlBmp width = controlBmp. getWidth ();
ControlBmpHeight = controlBmp. getHeight ();
SrcPs = new float [] {
0, 0,
Mainbmp width/2, 0,
Mainbmp width, 0,
Mainbmp width, mainBmpHeight/2,
Mainbmp width, mainBmpHeight,
Mainbmp width/2, mainBmpHeight,
0, mainBmpHeight,
0, mainBmpHeight/2,
Mainbmp width/2, mainBmpHeight/2
};
DstPs = srcPs. clone ();
SrcRect = new RectF (0, 0, mainbmp width, mainBmpHeight );
DstRect = new RectF ();
Matrix = new Matrix ();
Prefill = new Point (mainbmp width/2, mainBmpHeight/2 );
Lastparts = new Point (mainbmp width/2, mainBmpHeight/2 );
LastPoint = new Point (0, 0 );
Paint = new Paint ();
PaintRect = new Paint ();
PaintRect. setColor (Color. RED );
PaintRect. setAlpha (100 );
PaintRect. setAntiAlias (true );
PaintFrame = new Paint ();
PaintFrame. setColor (Color. GREEN );
PaintFrame. setAntiAlias (true );
SetMatrix (OPER_DEFAULT );
}
/**
* Matrix transformation for graphic Translation
* @ Author zhangjin
*/
Private void setMatrix (int operationType ){
Switch (operationType ){
Case OPER_TRANSLATE:
Matrix. postTranslate (deltaX, deltaY );
Break;
Case OPER_SCALE:
Matrix. postScale (scaleValue, scaleValue, metrics ricpoint. x, metrics ricpoint. y );
Break;
Case OPER_ROTATE:
Matrix. postRotate (preDegree-lastDegree, dstPs [CTR_MID_MID * 2], dstPs [CTR_MID_MID * 2 + 1]);
Break;
}
Matrix. mapPoints (dstPs, srcPs );
Matrix. mapRect (dstRect, srcRect );
}
Private boolean isOnPic (int x, int y ){
If (dstRect. contains (x, y )){
Return true;
} Else
Return false;
}
Private int getOperationType (MotionEvent event ){
Int evX = (int) event. getX ();
Int evY = (int) event. getY ();
Int curOper = lastOper;
Switch (event. getAction ()){
Case MotionEvent. ACTION_DOWN:
Current_ctr = isOnCP (evX, evY );
Log. I ("img", "current_ctr is" + current_ctr );
If (current_ctr! = CTR_NONE | isOnPic (evX, evY )){
CurOper = OPER_SELECTED;
}
Break;
Case MotionEvent. ACTION_MOVE:
If (current_ctr> CTR_NONE & current_ctr <CTR_MID_MID ){
CurOper = OPER_SCALE;
} Else if (current_ctr = CTR_MID_MID ){
CurOper = OPER_ROTATE;
} Else if (lastOper = OPER_SELECTED ){
CurOper = OPER_TRANSLATE;
}
Break;
Case MotionEvent. ACTION_UP:
CurOper = OPER_SELECTED;
Break;
Default:
Break;
}
Log. d ("img", "curOper is" + curOper );
Return curOper;
}
/**
* The control point of the judgment point
* @ Param evX
* @ Param evY
* @ Return
*/
Private int isOnCP (int evx, int evy ){
Rect rect = new Rect (evx-controlbmp width/2, evy-controlBmpHeight/2, evx + controlbmp width/2, evy + controlBmpHeight/2 );
Int res = 0;
For (int I = 0; I <dstPs. length; I ++ = 2 ){
If (rect. contains (int) dstPs [I], (int) dstPs [I + 1]) {
Return res;
}
++ Res;
}
Return CTR_NONE;
}
@ Override
Public boolean dispatchTouchEvent (MotionEvent event ){
Int evX = (int) event. getX ();
Int evY = (int) event. getY ();
Int operType = OPER_DEFAULT;
OperType = getOperationType (event );
Switch (operType ){
Case OPER_TRANSLATE:
Translate (evX, evY );
Break;
Case OPER_SCALE:
Scale (event );
Break;
Case OPER_ROTATE:
Rotate (event );
Break;
}
LastPoint. x = evX;
LastPoint. y = evY;
LastOper = operType;
Invalidate (); // redraw
Return true;
}
/**
* Mobile
* @ Param evx
* @ Param evy
* @ Author zhang_jin1
*/
Private void translate (int evx, int evy ){
Prefill. x + = evx-lastPoint. x;
Prefill. y + = evy-lastPoint. y;
DeltaX = Preprocessor. x-lastPivot. x;
DeltaY = prefetch. y-lastPivot. y;
LastPivot. x = Preprocessor. x;
Lasttings. y = Preprocessor. y;
SetMatrix (OPER_TRANSLATE); // sets the matrix.
}
/**
* Zoom
* 0---1---2
* |
* 7 8 3
* |
* 6---5---4
* @ Param evX
* @ Param evY
*/
Private void scale (MotionEvent event ){
Int pointIndex = current_ctr * 2;
Float px = dstPs [pointIndex];
Float py = dstPs [pointIndex + 1];
Float evx = event. getX ();
Float evy = event. getY ();
Float oppositeX = 0;
Float oppositeY = 0;
If (current_ctr <4 & current_ctr> = 0 ){
OppositeX = dstPs [pointIndex + 8];
OppositeY = dstPs [pointIndex + 9];
} Else if (current_ctr> = 4 ){
OppositeX = dstPs [pointIndex-8];
OppositeY = dstPs [pointIndex-7];
}
Float temp1 = getDistanceOfTwoPoints (px, py, oppositeX, oppositeY );
Float temp2 = getDistanceOfTwoPoints (evx, evy, oppositeX, oppositeY );
This. scaleValue = temp2/temp1;
Repeated ricpoint. x = (int) oppositeX;
Repeated ricpoint. y = (int) oppositeY;
Log. I ("img", "scaleValue is" + scaleValue );
SetMatrix (OPER_SCALE );
}
/**
* Rotating Images
* 0---1---2
* |
* 7 8 3
* |
* 6---5---4
* @ Param evX
* @ Param evY
*/
Private void rotate (MotionEvent event ){
If (event. getPointerCount () = 2 ){
PreDegree = computeDegree (new Point (int) event. getX (0), (int) event. getY (0), new Point (int) event. getX (1), (int) event. getY (1 )));
} Else {
PreDegree = computeDegree (new Point (int) event. getX (), (int) event. getY (), new Point (int) dstPs [16], (int) dstPs [17]);
}
SetMatrix (OPER_ROTATE );
LastDegree = preDegree;
}
/**
* Calculate the angle between two points and the vertical direction.
* @ Param p1
* @ Param p2
* @ Return
*/
Public float computeDegree (Point p1, Point p2 ){
Float tran_x = p1.x-p2.x;
Float tran_y = p1.y-p2.y;
Float degree = 0.0f;
Float angle = (float) (Math. asin (tran_x/Math. sqrt (tran_x * tran_x + tran_y * tran_y) * 180/Math. PI );
If (! Float. isNaN (angle )){
If (tran_x> = 0 & tran_y <= 0) {// First quadrant
Degree = angle;
} Else if (tran_x <= 0 & tran_y <= 0) {// Second quadrant
Degree = angle;
} Else if (tran_x <= 0 & tran_y> = 0) {// third quadrant
Degree =-180-angle;
} Else if (tran_x> = 0 & tran_y> = 0) {// quadrant
Degree = 180-angle;
}
}
Return degree;
}
/**
* Calculate the distance between two points
* @ Param p1
* @ Param p2
* @ Return
*/
Private float getDistanceOfTwoPoints (Point p1, Point p2 ){
Return (float) (Math. sqrt (p1.x-p2.x) * (p1.x-p2.x) + (p1.y-p2.y) * (p1.y-p2.y )));
}
Private float getDistanceOfTwoPoints (float x1, float y1, float x2, float y2 ){
Return (float) (Math. sqrt (x1-x2) * (x1-x2) + (y1-y2) * (y1-y2 )));
}
@ Override
Public void onDraw (Canvas canvas ){
DrawBackground (canvas); // draws the background to test the ing of the rectangle.
Canvas. drawBitmap (mainBmp, matrix, paint); // draw the main Image
DrawFrame (canvas); // draw a border for the ing of the test point
DrawControlPoints (canvas); // draw a control point image
}
Private void drawBackground (Canvas canvas ){
Canvas. drawRect (dstRect, paintRect );
}
Private void drawFrame (Canvas canvas ){
Canvas. drawLine (dstPs [0], dstPs [1], dstPs [4], dstPs [5], paintFrame );
Canvas. drawLine (dstPs [4], dstPs [5], dstPs [8], dstPs [9], paintFrame );
Canvas. drawLine (dstPs [8], dstPs [9], dstPs [12], dstPs [13], paintFrame );
Canvas. drawLine (dstPs [0], dstPs [1], dstPs [12], dstPs [13], paintFrame );
Canvas. drawPoint (dstPs [16], dstPs [17], paintFrame );
}
Private void drawControlPoints (Canvas canvas ){
For (int I = 0; I <dstPs. length; I ++ = 2 ){
Canvas. drawBitmap (controlBmp, dstPs [I]-controlBmp width/2, dstPs [I + 1]-controlBmpHeight/2, paint );
}
}
}
Demo effect: