1. Preview of “Turn around APP” effect

Keep an eye on the Indicator

2. Action analysis

  1. The left part

The left part is a white circle, which shows the current page number in red font. When the ViewPager slides, the white circle rotates around the Y-axis, and when rotated 180 degrees, that is, when the back is displayed, the word in the circle becomes the next page number.

  1. The right side of

The right part is simpler, a notched oval showing the total number of pages.

Three. Break the difficult points one by one

1. Use canvas to draw rotation around Y axis

When drawing pictures on Canvas, if it is rotating around the Z-axis, it is relatively simple to use Matrix Matrix:

Matrix matrix = new Matrix(); matrix.setRotate(angle); Bimtap newBitmap = Bitmap. CreateBitmap (oldBitmap, 0, 0, oldBitmap getWidth (), oldBitmap. GetHeight (), matrix, true);Copy the code

But this can only be done when drawing an image, not if you want to do a rotation on a whole, for example, the rotating indicator coordinate circle above, the circle is a circle with a number on it, so you can’t do this with the circle and the number.

What’s more, it was not easy to express this problem when I searched on Google. At the beginning, I searched “Android Canvas 3D rotation”, but the result was not quite consistent. Later, I searched “Android Canvas rotates around the y axis”, and found the corresponding result.

The rotateY interface of Android.Graphics.camera is used to realize the operation of the matrix when rotating about the Y-axis.

Let’s first declare camera

camera = new Camera();
Copy the code

In Ondraw method, first save canvas state, using Canvas.save (), then save camera state, rotate the camera by rotateAngle, and assign the matrix of the camera to the matrix. Finally, restore the camera state to the state before rotation. Then append matrix to the matrix of the current canvas using concat method. At this time, the whole canvas is equivalent to rotating the rotateAngle, and then restore to the original state after drawing the circle.

canvas.save();
Matrix matrix = new Matrix(); 
camera.save();
camera.rotateY(rotateAngle);
camera.getMatrix(matrix);
camera.restore();

mPaint.setColor(textBackgroundColor);
int centerX = diameter / 2;
int centerY = diameter / 2;
matrix.preTranslate(-centerX, -centerY);
matrix.postTranslate(centerX, centerY);
canvas.concat(matrix);

canvas.drawCircle(diameter / 2, diameter / 2, diameter / 2, mPaint);

canvas.restore();
Copy the code

2. Canvas drawText Center the text vertically

Gravity = Paint.Align.CENTER = gravity; gravity = gravity;

textPaint.setTextAlign(Paint.Align.CENTER);
canvas.drawText("of " + maxPage, rect.centerX(), rect.centerY(), textPaint);
Copy the code

The effect appears, as shown in the figure, to find that the text is biased on:

What’s going on here? In fact, we set the text love center point at the drawing, in fact, the text is based on the baseline as the anchor point for drawing, English called baseline.

You can see an explanation of the baseline in Wikipedia:

So if we want to center the text, we need to move the Y coordinate of the drawing point down.

If the distance from the baseline to the top of the font is TOP and the distance from the baseline to the bottom of the font is bottom, the following equation can be obtained:

(top + baseline)+ (bottom + baseline) / 2 = centenY() 
Copy the code

Use Paint.FontMetrics to get the top and bottom values of baseline.

Rect = new Rect(diameter, 0, (int) (diameter * 3.4f), diameter); TextPaint = new Paint(); textPaint.setColor(Color.WHITE); TextPaint. SetTextSize ((int) (0.6 f) diameter *); textPaint.setStyle(Paint.Style.FILL); TextPaint. SetTextAlign (Paint.Align. Center); Paint.FontMetrics fontMetrics = textPaint.getFontMetrics(); float top = fontMetrics.top; // Top float bottom = fontMetrics. Bottom; Bottom int baseLineY = (int) (rect.centery () - top / 2 - bottom / 2); DrawText ("of "+ maxPage, rect.centerx (), baseLineY, textPaint);Copy the code

3. Automatic rotation

Automatic rotation, through Handler+Timer.

// Timer = new timer (); timer.schedule(new TimerTask() { @Override public void run() { Message message = new Message(); message.what = 1; if (mViewPager.getCurrentItem() == Integer.MAX_VALUE - 1) { currentIndex = -1; } currentIndex = mViewPager.getCurrentItem(); message.arg1 = currentIndex + 1; mHandler.sendMessage(message); }}, 1000200, 0);Copy the code

Then customize the Handler.

// Select * from *; Private Handler mHandler = new Handler() {public void handleMessage(Message MSG) {switch (MSG. What) {private Handler mHandler = new Handler() {public void handleMessage(Message MSG) { case 1: mViewPager.setCurrentItem(msg.arg1,true); }}};Copy the code

Four. Code implementation

The code is on Github, please don’t be stingy with Star.

RotateIndicatorView

Contact information and suggestions

Weibo: orzangleli

All original articles are copyrighted by Orzangleli.
www.orzangleli.com/2016/11/10/…