Take a look at the movie tickets. Online selection function to achieve the effect of the map:
The interface is rough, mainly to see the principle.
This interface mainly includes the following parts
1. Seating
2, the left row number
3, the top left thumbnail
4, the red area in the thumbnail
5. Follow the movement when the finger moves
6, two fingers zoom with zoom
Main technical points
1. Matrix matrices
2, Gesturedetector and Scalegesturedetector
3, bitmap the basic usage
4, here only need to rewrite the view OnDraw to achieve full functionality
It can be found that there is no difficulty in fact, mainly is the calculation of some positions.
In order to be able to easily understand the first to use the knowledge point of the comb
1. Matrix matrices
The matrix is determined by 9 values in the 3*3 matrix, and all of the settings we have for the matrix are operations on these 9 values.
{mscale_x,mskew_x,mtrans_x,
Mskew_y,mscale_y,mtrans_y,
Mpersp_0,mpersp_1,mpersp_2}
This is the 9 values of the matrix, see the name also know what they mean.
This is mainly used for scaling and panning, and the following is an example of scaling to understand the control of scaling
Through the API provided by Android we can invoke Setscale, Prescale, Postscale to change the value of mscale_x and mscale_y to achieve scaling effect
So as long as we understand the difference between the three methods of Setscale, Prescale and Postscale, we can simply zoom control.
1, Setscale (Sx,sy), the matrix will first be set to the diagonal matrix, which is equivalent to call the Reset () method, and then set the matrix of mscale_x and mscale_y directly set to Sx,sy values
2, Prescale (Sx,sy), will not reset the matrix, but directly with the matrix before the mscale_x and mscale_y values (multiplied), m ' = m * S (SX, SY).
3, Postscale (Sx,sy), does not reset the matrix, but directly with the matrix before the mscale_x and mscale_y values (multiplied), M ' = S (SX, SY) * M.
So there is some bad understanding, a chestnut to see
1. Order of execution of pre ....
Matrix matrix=new Matrix ();
Float[] Points=new float[]{10.0f,10.0f};
Matrix.prescale (2.0f, 3.0f);
Matrix.pretranslate (8.0f,7.0f);
Matrix.mappoints (points);
LOG.I ("Test", points[0]+ "");
LOG.I ("Test", points[1]+ "");
The result is a point coordinate (36.0,51.0)
It can be concluded that the order in which the transformations are performed is performed first by Pretranslate (8.0f,7.0f), in the execution of the Prescale (2.0f,3.0f). That is, for a matrix setting, all pre ... is executed backwards.
2, Post ... Order of execution
Matrix matrix=new Matrix ();
Float[] Points=new float[]{10.0f,10.0f};
Matrix.postscale (2.0f, 3.0f);
Matrix.posttranslate (8.0f,7.0f);
Matrix.mappoints (points);
LOG.I ("Test", points[0]+ "");
LOG.I ("Test", points[1]+ "");
The result is a point coordinate (28.0,37.0)
It can be concluded that the order in which the transformations are performed is performed first by Postscale (2.0f,3.0f), in the execution of the Posttranslate (8.0f,7.0f). That is, for a matrix setting, all post ... is carried forward.
The main knowledge here is set ... and post ... method on the line, because only use these two.
Self-understanding is actually similar to Scrollto and Scrollby.
2, Gesturedetector and Scalegesturedetector
Gesturedetector is mainly used to identify certain gestures, just call gesturedetector.ontouchevent () to pass motionevent in.
Scalegesturedetector the attack class usage used to handle scaling is similar to Gesturedetector
3, bitmap the basic usage
reference to: about bitmap Some things you don't know
Take a look at the bitmap.
The following is the official drawing of this selection function.
1, Draw the seat:
@Override protected void OnDraw (Canvas Canvas) {Super.ondraw (Canvas);
/** * If the first entry makes the seating chart centered * * (mviewh!= 0 && mvieww!= 0&&isfrist) {isfrist = false;
Matrix.settranslate (-(Mvieww-getmeasuredwidth ())/2, 0);
/** * Draw Seat * * drawseat (canvas);
/** * Draw the number of rows/drawText (canvas);
/** * Draw Thumbnails * * * Drawoverview (canvas);
/** * Draw Thumbnails Selection Area * * * drawovewrect (canvas); }
private void Drawseat (Canvas Canvas) {Float zoom = Getmatrixscalex ();
Scale1 = zoom;
Tranlatex = Gettranslatex ();
Tranlatey = Gettranslatey (); /** * Use a two-layer for loop to draw all seats * * for (int i = 0; i < row; i++) {Float top = i * seathight * scale * scale1 + i * mspacey
* Scale1 + Tranlatey;
for (int j = 0; j < column; J +) {Float left = J * Seatwidth * scale * scale1 + J * Mspacex * scale1 + Tranlatex;
Tempmatrix.settranslate (left, top);
Tempmatrix.postscale (scale, scale, left, top);
Tempmatrix.postscale (Scale1, Scale1, left, top);
/** * Get information for each position/int state = Getseattype (i, j);
/** * According to position information draw different position picture * * Switch (state) {case SEAT_TYPE_SOLD:canvas.drawBitmap (seatlock, Tempmatrix, NULL);
Break
Case SEAT_TYPE_SELECTED:canvas.drawBitmap (seatchecked, Tempmatrix, NULL);
Break
Case SEAT_TYPE_AVAILABLE:canvas.drawBitmap (seatnormal, Tempmatrix, NULL);
Break
Case Seat_type_not_available:break; }
}
}
}
In fact, there is no difficulty here, the main thing is to use the two for loop, a layer of painting lines, a layer of painting columns
Also note that the current position of the calculation top = (current position i) (seat icon size seathight its own scaling than scale* scaling than Scale1) + (the current position i* the vertical direction of spacing mspacey* zoom ratio scale1) + Moving vertically, yes, moving distances.
2, Draw row number
private void DrawText (Canvas Canvas) {
mtextpaint.setcolor (baccolor);
RECTF RECTF = new RECTF ();
Rectf.top = Gettranslatey ()-MNUMBERHEIGHT/2;
Rectf.bottom = Gettranslatey () + mviewh* Getmatrixscalex () + MNUMBERHEIGHT/2;
Rectf.left = 0;
Rectf.right = Mtextwidth;
Canvas.drawroundrect (RECTF, MTEXTWIDTH/2, MTEXTWIDTH/2, mtextpaint);
Mtextpaint.setcolor (color.white);
for (int i = 0; i < row; i++) {
float top = (i *seathight*scale + i * mspacey) * Getmatrixscalex () + Gettranslatey ();
Float bottom = (i * seathight*scale + i * mspacey + seathight) * Getmatrixscalex () + Gettranslatey ();
Float baseline = (bottom + top-linenumberpaintfontmetrics.bottom-linenumberpaintfontmetrics.top)/2-6;
Canvas.drawtext (Linenumbers.get (i), MTEXTWIDTH/2, Baseline, mtextpaint);
}
3. Draw thumbnail image
private void Drawoverview (Canvas Canvas) {/** * 1, first draw a background picture/Mbitmapoverview = Bitmap.createbitmap ((int) Moverviewwid
th, (int) moverviewhight,bitmap.config.argb_8888);
Canvas Overviewcanvas = new Canvas (Mbitmapoverview);
Paint Paint = new Paint ();
Paint.setcolor (Baccolor);
Scaleoverx = MOVERVIEWWIDTH/MVIEWW;
Scaleovery = MOVERVIEWHIGHT/MVIEWH;
float tempx = mvieww * SCALEOVERX;
float Tempy = MVIEWH * scaleovery;
Overviewcanvas.drawrect (0, 0, (float) tempx, (float) tempy, paint);
Matrix Tempovermatrix = new Matrix (); /** * 2, like the picture of a seating chart, draw seats in thumbnails (int i = 0; i < row; i++) {Float top = i * seathight * scale * scaleovery+ I * MSPA
Cey * scaleovery; for (int j = 0; j < column; J +) {Float left = J * Seatwidth * scale * Scaleoverx + J * Mspacex * Scaleoverx+mtextwid
Th*scaleoverx;
Tempovermatrix.settranslate (left, top);
Tempovermatrix.postscale (Scale*scaleoverx, Scale*scaleovery, left, top);
int state = Getseattype (i, j); Switch (state) {case Seat_type_soLD:OverViewCanvas.drawBitmap (Seatlock, Tempovermatrix, NULL);
Break
Case SEAT_TYPE_SELECTED:OverViewCanvas.drawBitmap (seatchecked, Tempovermatrix, NULL);
Break
Case SEAT_TYPE_AVAILABLE:OverViewCanvas.drawBitmap (seatnormal, Tempovermatrix, NULL);
Break
Case Seat_type_not_available:break;
}} canvas.drawbitmap (Mbitmapoverview,0,0,null);
}
4, red areas in thumbnails
private void Drawovewrect (Canvas Canvas) {overrectpaint = new Paint ();
Overrectpaint.setcolor (color.red);
Overrectpaint.setstyle (Paint.Style.STROKE);
Overrectpaint.setstrokewidth (Overrectlinewidth);
int tempvieww;
int TEMPVIEWH;
if (Getmeasuredwidth () <mvieww) {tempvieww = Getmeasuredwidth ();
}else{tempvieww = mvieww;
} if (Getmeasuredheight () <mviewh) {TEMPVIEWH = Getmeasuredheight ();
}else{TEMPVIEWH = MVIEWH;
} try{Rect Rect; if (Getmatrixscalex () >= 1.0f) {rect = new rect (int) (Scaleoverx*math.abs (Gettranslatex ())/getmatrixscalex ()), (int ) (Scaleovery*math.abs (Gettranslatey ())/getmatrixscalex ()), (int) (Scaleoverx*math.abs (Gettranslatex ())/ Getmatrixscalex () +tempvieww*scaleoverx/getmatrixscalex ()), (int) (Scaleovery*math.abs (Gettranslatey ())/
Getmatrixscalex () +tempviewh*scaleovery/getmatrixscalex ()); }else{rect = new rect ((int) (Scaleoverx*math.abs (Gettranslatex ())), (int) (Scaleovery*math.abs (Gettranslatey ())), ( int) (Scaleoverx*math.abs (GettraNslatex ()) +tempvieww*scaleoverx), (int) (Scaleovery*math.abs (Gettranslatey ()) +tempviewh*scaleovery));
} canvas.drawrect (Rect, overrectpaint);
}catch (Exception e) {e.printstacktrace ();
}
}
5. Follow the movement when the finger moves
@Override Public
Boolean ontouchevent (Motionevent event) {
/**
* Scaling event referred to scalegesturedetector processing
* *
scalegesturedetector.ontouchevent (event);
/**
* Move and click event to gesturedetector processing *
*
gesturedetector.ontouchevent (event);
return true;
}
/** * Mobile Event here is a simple judgment, the need for more detailed conditions to judge/public boolean onscroll (Motionevent E1, motionevent E2, float Distancex, float
Distancey) {Float tempmvieww = column * seatwidth*scale*scale1+ (column-1) *mspacex*scale1+mtextwidth-getwidth ();
float TEMPMVIEWH = row * seathight * scale * scale1 + (row-1) * Mspacey * scale1-getheight ();
if ((Gettranslatex () >mtextwidth+mspacex) && distancex<0) {Distancex = 0.0f;
if (Math.Abs (Gettranslatex ()) >tempmvieww) && (distancex>0)) {Distancex = 0.0f;
} if ((Gettranslatey () >0) &&distancey<0) {distancey=0.0f;
if (Math.Abs (Gettranslatey ()) >TEMPMVIEWH) && (distancey>0)) {Distancey = 0.0f;
} matrix.posttranslate (-distancex,-distancey);
Invalidate ();
return false;
/** * Click event/public boolean onsingletapconfirmed (Motionevent e) {int x = (int) e.getx ();
int y = (int) e.gety (); for (int i = 0; i < row; i++) {for (int j = 0; j < column; J +) {int tempx = (int) (j * Seatwidth * scale + J * Mspacex) * Getmatrixscalex () + Gettranslatex ());
int maxtemx = (int) (TEMPX + seatwidth * scale * GETMATRIXSCALEX ());
int tempy = (int) ((i * seathight * scale + i * Mspacex) * Getmatrixscaley () + Gettranslatey ());
int maxtempy = (int) (Tempy + seathight * scale * Getmatrixscaley ()); if (x >= tempx && x <= maxtemx && y >= tempy && y <= maxtempy) {int id = GetID (i,
j);
int index = Ishave (ID);
if (index >= 0) {remove (index);
else {addchooseseat (i, j);
float Currentscaley = Getmatrixscaley ();
if (Currentscaley < 1.7f) {ScaleX = x;
ScaleY = y;
/** * Zoom Operation When selected * * Zoomanimate (Currentscaley, 1.9f);
} invalidate ();
Break
}} return super.onsingletapconfirmed (e);
}
});
6, two fingers zoom with zoom
public boolean Onscale (Scalegesturedetector detector) {
float scalefactor = Detector.getscalefactor ();
ScaleX = Detector.getcurrentspanx ();
ScaleY = Detector.getcurrentspany ();
A direct judgment of greater than 2 causes the obtained matrix scaling to continue to run once, resulting in a number like 2.000001 so that the
//judgment condition is always true and thus does not perform a narrowing action
//judgment multiplication greater than 2 Can be the current obtained scaling ratio even if the number 1.9999 and so on if continue to enlarge even if multiplied by 1.0001 will be larger than 2 thereby
//avoid the above problem.
if (Getmatrixscaley () * scalefactor > 2) {
scalefactor = 2/getmatrixscaley ();
}
if (Getmatrixscaley () * Scalefactor < 0.8) {
scalefactor = 0.8f/getmatrixscaley ();
}
Matrix.postscale (Scalefactor, scalefactor);
Invalidate ();
return true;
}
So far this relatively rough selection function is achieved, there will be time to continue to optimize the details of the problem.
The following two demo are compared to the force I will not upload demo.
Resources:
Android Alternative block source analysis
Andriod to create cool movie tickets on-line selection control, 1:1 restore Taobao movie Online select Seat function
The above is the entire content of this article, I hope to help you learn, but also hope that we support the cloud habitat community.