IOS 11 has released beta, and I believe some of the partners with the iphone are eager to upgrade.
So in this article, we use a simple custom View to implement a very novel progress bar in the control center similar to iOS 11.
Let's first look at the target effect map and the final result.
Custom Property Analysis
Name | Interpretation |
---|---|
progressMax | Maximum |
progressValue | Speed of progress |
iconSrc | Icon |
bgColor | background color |
progressColor | Progress color |
progressOrientation | direction |
rectRadius | Rounded arc |
iconPadding | icon Interior Spacing |
In summary, the relevant attribute definition code is as follows:
<declare-styleable name="RectProgress"> <attr name="progressValue" format="integer" /> <attr name="progressMax" format="integer" /> <attr name="bgColor" format="color" /> <attr name="rectRadius" format="dimension" /> <attr name="iconPadding" format="dimension" /> <attr name="progressColor" format="color" /> <attr name="iconSrc" format="reference" /> <attr name="progressOrientation"> <enum name="vertical" value="1" /> <enum name="horizontal" value="2" /> </attr> </declare-styleable>
Progress Bar Drawing
Firstly, the composition of the next progress bar is analyzed.
- background
- Speed of progress
- Icon
It seems very simple. Use canvas.drawRoundRect() to draw background and progress respectively, and finally add a bitmap.
However, in practice, we will find that it is not feasible to operate according to the idea of covering Background with Progress. The problem is that when drawing Progress, we deal with the upper corner.
The solution is to use Paint.setXfermode(); (For details of each Mode, see here . ) Here we use PorterDuff.Mode.SRC_ATOP.
This idea is described in vernacular: first draw a rounded background, and then draw a rectangular Progress on the basis of the rounded background. At this time, because Paint.setXfermode(); so the rectangular Progresses will only be shown on the intersection of the background.
(Note: Paint.setXfermode(); hardware acceleration needs to be turned off, otherwise it may not take effect: setLayerType(View.LAYER_TYPE_SOFTWARE, null);
So drawing progress code in ondraw() is actually very simple:
//bgPaint is the background brush and progressPaint is the progress brush. int canvasWidth = canvas.getWidth(); int canvasHeight = canvas.getHeight(); int layerId = canvas.saveLayer(0, 0, canvasWidth, canvasHeight, null, Canvas.ALL_SAVE_FLAG); { bgPaint.setColor(bgColor); // draw the background of progress canvas.drawRoundRect(bgRect, rectRadius, rectRadius, bgPaint); // draw progress canvas.drawRect(progressRect, progressPaint); bgPaint.setXfermode(null); } canvas.restoreToCount(layerId);
Handling of gestures
Here we only analyze the vertical direction of gesture processing, the horizontal direction is the same: gesture processing this logic is very simple. Logically, ACTION_DOWN is the same as ACTION_MOVE. Only one point needs to be addressed:
- Considering the padding of View, it is necessary to determine whether ACTION_DOWN is processed in the progress bar or not.
Main code://bgRect background rectangle, progressRect progress rectangle if (event.getY() < bgRect.top) { //Contacts beyond the top of Progress progressRect.top = bgRect.top; } else if (event.getY() > bgRect.bottom) { //Contacts over the bottom of Progress progressRect.top = bgRect.bottom; } else { progressRect.top = getPaddingTop() + event.getY(); }
Icon Drawing
icon draws only one line of code:
canvas.drawBitmap(bitmap, srcRect, dstRect, bgPaint);
What needs to be explained is the parameters of this method.
- Bitmap region to be drawn by srcRect
- The area to be drawn by dstRect Bitmp
Callback
It is important to note that a callback is made only once per percentage change.
Project hosting address
https://github.com/CuiZhaoHui/IOS11RectProgress