Detailed explanation of Canvas API (Part 2) collection of cutting methods
Introduction to this section:
This section continues to bring a detailed explanation of the Canvas API (Part 2) of the Android drawing series. Today we will explain Canvas ClipXxx method family in! We can see that there are three types of Clip methods provided to us in the document: clipPath( ), clipRect( ), clipRegion( );
Through different combinations of Path, Rect, and Region, almost any shape of cropping area can be supported!
Path: It can be an open or closed curve, a complex collection of lines composed of graphics
Rect: Rectangular area
Region: It can be understood as a combination of regions. For example, two regions can be added, subtracted, combined, confused, etc.!
Region.Op defines the types of inter-region operations supported by Region! We will talk about it later, Another thing to say is that what we usually understand as clipping may be clipping existing graphics, but in Android, clipping Clip on Canvas must be done before drawing. If you Clip on Canvas after drawing, it will not affect Go to the drawn graphics, remember that Clip is for the Canvas, not the graphics! Well, no BB, let’s start this section directly!
Official API Document:Canvas
1.Detailed explanation of Region.Op combination method
In fact, the difficulty is nothing more than this. Region represents a region, which represents a certain closed area on the Canvas layer! Of course, if you have time, you can slowly deduct this class by yourself, and what we usually focus on is just one of its enumeration values: Op
Let’s take a look at each one The role of enumeration values: We assume two cropping areas A and B, then we call the enumeration value corresponding to Region.Op:
DIFFERENCE: the difference set range of A and B, That is, A - B, only the drawing content within this range will be displayed;
INTERSECT: That is, the intersection range of A and B, only within this range Only the drawing content within will be displayed
UNION: That is, the union range of A and B, that is, the drawing content of the range included in both will be displayed. ;
XOR: The complement range of A and B. In this example, it is the range of A except B. Only the drawing content within this range will Displayed;
REVERSE_DIFFERENCE: The difference set range between B and A, that is, B - A, only the drawing content within this range will be displayed;
REPLACE: Regardless of the collection status of A and B, the range of B will be displayed entirely. If it intersects with A, the intersection range of A will be covered;
If If you have studied sets, then it will be clear to draw a Venn (Venn diagram), haven’t you? It's okay, let's try it by writing an example Corresponding results~! Write a method to initialize the brush and draw a rectangle:
private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(6); mPaint.setColor(getResources().getColor(R.color.blush)); } private void drawScene(Canvas canvas){ canvas.drawRect(0, 0, 200, 200, mPaint); }
Op.DIFFERENCE:
canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二个 drawScene(canvas);
RESULT:
Using (10,10) and (50,50) as starting points, two rectangles of 100*100 were cropped. The cropping result is:
The difference between A and B = A - (The intersection of A and B)
##Op.INTERSECT:canvas.clipRect(10, 10, 110, 110); //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.INTERSECT); //第二个
drawScene(canvas);
Result:
Using (10,10) and (50,50) as the starting point, two rectangles of 100*100 were cropped. The cropping results are:A and B The intersection = the intersection of A and B
Op.UNION:canvas.clipRect(10, 10, 110, 110); //第一个
canvas.clipRect(40, 40, 140, 140, Region.Op.UNION); //第二个
drawScene(canvas);
Result:
Using (10,10) and (50,50) as the starting point, two rectangles of 100*100 were cropped. The cropping results are:A and B Union = A's area + B's area
Op.XOR:canvas.clipRect(10, 10, 110, 110); //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.XOR); //第二个
drawScene(canvas);
Result:
Cut two 100*100 rectangles using (10,10) and (50,50) as the starting point. The cropping result is:A and the complement of B = the set of A and B - the intersection of A and B
Op.REVERSE_DIFFERENCE:canvas.clipRect(10, 10, 110, 110); //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.REVERSE_DIFFERENCE); //第二个
drawScene(canvas);
result :
We cut two 100*100 rectangles using (10,10) and (50,50) as the starting point, and the resulting cropping results It is:The difference between B and A = B - The intersection of A and B
##Op.REPLACE
canvas.clipRect(10, 10, 110, 110); //第一个
canvas.clipRect(50, 50, 150, 150, Region.Op.REPLACE); //第二个
drawScene(canvas);
Result:
Cut two 100*100 rectangles at (10,10) and (50,50) as starting points, and the resulting cropping The result is:
Regardless of the collection status of A and B, the range of B will be displayed entirely. If it intersects with A, the intersection range of A will be covered;2. Region.Op usage examples:
Examples refer to:
Android 2D Graphics Learning (2), Canvas Part 2, Canvas Cropping and Region, RegionIteratorRun Rendering:
Key part of the code MyView.java:/**
* Created by Jay on 2015/11/10 0010.
*/
public class MyView extends View{
private Bitmap mBitmap = null;
private int limitLength = 0; //
private int width;
private int heigth;
private static final int CLIP_HEIGHT = 50;
private boolean status = HIDE;//显示还是隐藏的状态,最开始为HIDE
private static final boolean SHOW = true;//显示图片
private static final boolean HIDE = false;//隐藏图片
public MyView(Context context) {
this(context, null);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_meizi);
limitLength = width = mBitmap.getWidth();
heigth = mBitmap.getHeight();
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
Region region = new Region();
int i = 0;
while (i * CLIP_HEIGHT <= heigth) {//计算clip的区域
if (i % 2 == 0) {
region.union(new Rect(0, i * CLIP_HEIGHT, limitLength, (i + 1) * CLIP_HEIGHT));
} else {
region.union(new Rect(width - limitLength, i * CLIP_HEIGHT, width, (i + 1)
* CLIP_HEIGHT));
}
i++;
}
canvas.clipRegion(region);
canvas.drawBitmap(mBitmap, 0, 0, new Paint());
if (status == HIDE) {//如果此时是隐藏
limitLength -= 10;
if(limitLength = width)
status=HIDE;
}
invalidate();
}
}
: Get the width and height during initialization, and then loop. You can understand that the picture is divided into lines. The loop condition is: i * the height of each line.
Not greater than the height, and then the line is divided into two situations. The union of Region is called, which is actually the cutting method of UNINO.
That's it. Finally, we make a judgment on whether the image is displayed at this time, handle the hiding and display situations differently, and finally call invalidate()
Redraw! It's quite simple, just understand it yourself~ Another point to note: Canvas transformation has no effect on clipRegion clipRect provides seven overloaded methods: The parameters are introduced as follows: rect: Rect object, used to define the scope of the cropping area. Rect and RectF have similar functions, but the accuracy is different from the methods provided left: The left position of the rectangular cropping area top: The top position of the rectangular cropping area right: The right position of the rectangular cropping area bottom : The lower position of the rectangular cropping area op: The combination method of the cropping area The above four values can be floating point or integer Usage example: Running result: From the above example, I don’t know Did you find out?
clipRect will be affected by the Canvas transformation. The white area is the non-flowered area, so clipRect crops the canvas.
And our drawing is done on this cropped canvas! Anything beyond this area will not be displayed! Compared with clipRect, clipPath has only two overloaded methods. The usage method is very simple. You can Draw a Paht then
Just pass it in! Usage example: Here we reuse the circular ImageView example we wrote before in ImageView~ Implementation code: Custom ImageView: RoundImageView.java Layout code: activity_main.xml: MainActivity.java: Running renderings: In addition, the rounded ImageView produced using this method will have obvious jagged edges, even if you Set for Paint, Canvas
Anti-aliasing is useless~ If you have high requirements, you can use Xfermode-PorterDuff to set image shuffling to achieve it.
Basically no aliasing, you can see: Basic Android Introduction Tutorial - 8.3.6 Paint API - Detailed explanation of Xfermode and PorterDuff (3) Okay, this section will explain to you the three methods of cutting in Canvas: clipPath(), clipRect(),
clipRegion(), the difficulty should be in the last one. There are six different Op combinations. In fact, it is not difficult. Collection
It's just a concept, just put it at the beginning and it's easy to digest, but clipPath() and clipRect() are not difficult~
Yes, it’s Double 11 today, I wonder if you’ve bought it~3. Detailed explanation of clipRect method:
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(Color.BLACK);
mPaint.setTextSize(60);
canvas.translate(300,300);
canvas.clipRect(100, 100, 300, 300); //设置显示范围
canvas.drawColor(Color.WHITE); //白色背景
canvas.drawText("双11,继续吃我的狗粮...", 150, 300, mPaint); //绘制字符串
4. Detailed explanation of clipPath method:
/**
* Created by coder-pig on 2015/7/18 0018.
*/
public class RoundImageView extends ImageView {
private Bitmap mBitmap;
private Rect mRect = new Rect();
private PaintFlagsDrawFilter pdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG);
private Paint mPaint = new Paint();
private Path mPath=new Path();
public RoundImageView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
//传入一个Bitmap对象
public void setBitmap(Bitmap bitmap) {
this.mBitmap = bitmap;
}
private void init() {
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setFlags(Paint.ANTI_ALIAS_FLAG);
mPaint.setAntiAlias(true);// 抗锯尺
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if(mBitmap == null)
{
return;
}
mRect.set(0,0,getWidth(),getHeight());
canvas.save();
canvas.setDrawFilter(pdf);
mPath.addCircle(getWidth() / 2, getWidth() / 2, getHeight() / 2, Path.Direction.CCW);
canvas.clipPath(mPath, Region.Op.REPLACE);
canvas.drawBitmap(mBitmap, null, mRect, mPaint);
canvas.restore();
}
}
<com.jay.demo.imageviewdemo.RoundImageView
android:id="@+id/img_round"
android:layout_width="200dp"
android:layout_height="200dp"
android:layout_margin="5px"/>
public class MainActivity extends AppCompatActivity {
private RoundImageView img_round;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
img_round = (RoundImageView) findViewById(R.id.img_round);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),R.mipmap.meinv);
img_round.setBitmap(bitmap);
}
}
5. Download the sample code for this section:
Summary of this section: