Android 区域--Range(三)

顽强的毅力可以征服世界上任何一座高峰!——狄更斯

我喜欢写博客之前用一句励志名言激励自己!

上一篇文章地址

首先介绍Region类

Region,中文意思即区域的意思,它表示的是canvas图层上的某一块封闭的区域。

 public Region()  //创建一个空的区域  
 public Region(Region region) //拷贝一个region的范围  
 public Region(Rect r)  //创建一个矩形的区域  
 public Region(int left, int top, int right, int bottom) //创建一个矩形的区域  

第二个构造函数是通过其它的Region来复制一个同样的Region变量
第三个,第四个才是正规常的,根据一个矩形或矩形的左上角和右下角点构造出一个矩形区域

public void setEmpty()  // 从某种意义上讲置空也是一个构造函数,即将原来的一个区域变量变成了一个空变量,要再利用其它的Set方法重新构造区域。
 public boolean set(Region region)    //利用新的区域值来替换原来的区域
 public boolean set(Rect r)   //利用矩形所代表的区域替换原来的区域
 public boolean set(int left, int top, int right, int bottom)    //根据矩形的两个点构造出矩形区域来替换原来的区域值
 public boolean setPath(Path path, Region clip)// 根据路径的区域与某区域的交集,构造出新区域,这个后面具体讲解

举个小例子,来说明一个Set系列函数的替换概念:
下面写了一个函数,先把Set函数注释起来,看看画出来的区域的位置,然后开启Set函数,然后再看画出来的区域注:里面有个函数drawRegion(Canvas canvas,Region rgn,Paint paint),只知道它可以画出指定的区域就可以了,具体里面是什么意思,后面我们再仔细讲。

package com.as.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

public class MyRegionView extends View {

    public MyRegionView(Context context) {
        this(context, null);
    }

    public MyRegionView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public MyRegionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        //初始化画笔
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(2);

        Region region = new Region(10, 10, 100, 100);

        //region.set(100, 100, 200, 200);
        drawRegion(canvas, region, paint);

    }

    //这个函数不懂没关系,下面会细讲
    private void drawRegion(Canvas canvas, Region region, Paint paint) {
        RegionIterator regionIterator = new RegionIterator(region);
        Rect r = new Rect();
        while (regionIterator.next(r)) {
            canvas.drawRect(r, paint);
        }
    }

}

未开启Set函数时


使用Set函数后,替换为新区域

使用SetPath()构造不规则区域

boolean setPath (Path path, Region clip)
//path:用来构造的区域的路径
//clip:与前面的path所构成的路径取交集,并将两交集设置为最终的区域

由于路径有很多种构造方法,而且可以轻意构造出非矩形的路径,这就摆脱了前面的构造函数只能构造矩形区域的限制。但这里有个问题是要指定另一个区域来取共同的交集,当然如果想显示路径构造的区域,Region clip参数可以传一个比Path范围大的多的区域,取完交集之后,当然是Path参数所对应的区域喽。机智的孩子。

下面,先构造一个椭圆路径,然后在setPath时,传进去一个比Path小的矩形区域,让它们两个取交集

public class MyRegionView extends View {

    public MyRegionView(Context context) {
        this(context, null);
    }

    public MyRegionView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public MyRegionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        //初始化画笔
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL);
        paint.setStrokeWidth(2);


        //构造一个椭圆路径
        Path ovalPath = new Path();
        RectF oval = new RectF(50, 50, 200, 500);
        ovalPath.addOval(oval, Path.Direction.CCW);

        //setPath传入一个比椭圆区域小的矩形区域,让其取交集
        Region region = new Region();
        region.setPath(ovalPath, new Region(50, 50, 200, 200));
        drawRegion(canvas, region, paint);
    }

    private void drawRegion(Canvas canvas, Region region, Paint paint) {
        RegionIterator regionIterator = new RegionIterator(region);
        Rect r = new Rect();
        while (regionIterator.next(r)) {
            canvas.drawRect(r, paint);
        }
    }

}

矩形集枚举区域——RegionIterator类

其实RegionIterator类非常简单,总共就两个函数,一个构造函数和一个获取下一个矩形的函数,实现了获取组成区域的矩形集的功能。对于特定的区域,可以使用多个矩形来表示其大致形状。事实上,如果矩形足够小,一定数量的矩形就能够精确表示区域的形状,也就是说,一定数量的矩形所合成的形状,也可以代表区域的形状。

RegionIterator(Region region) //根据区域构建对应的矩形集
boolean next(Rect r) //获取下一个矩形,结果保存在参数Rect r 中

由于在Canvas中没有直接绘制Region的函数,我们想要绘制一个区域,就只能通过利用RegionIterator构造矩形集来显示区域。用法如下:

private void drawRegion(Canvas canvas, Region region, Paint paint) {
        RegionIterator regionIterator = new RegionIterator(region);
        Rect r = new Rect();
        while (regionIterator.next(r)) {
            canvas.drawRect(r, paint);
        }
}

上面我们也都看到了它的用法,根据区域构建一个矩形集,然后利用next(Rect r)来逐个获取所有矩形,绘制出来,最终得到的就是整个区域,如果我们将上面的画笔Style从FILL改为STROKE,重新绘制椭圆路径,会看得更清楚。


区域的合并、交叉等操作

无论是区域还是矩形,都会涉及到与另一个区域的一些操作,比如取交集、取并集等,涉及到的函数有:

public final boolean union(Rect r)   
public boolean op(Rect r, Op op) {  
public boolean op(int left, int top, int right, int bottom, Op op)   
public boolean op(Region region, Op op)   
public boolean op(Rect rect, Region region, Op op)   

除了Union(Rect r)是指定合并操作以外,其它四个op()构造函数,都是指定与另一个区域的操作。其中最重要的指定Op的参数,Op的参数有下面四个:

假设用region1  去组合region2   
public enum Op {  
        DIFFERENCE(0), //最终区域为region1 与 region2不同的区域  
        INTERSECT(1), // 最终区域为region1 与 region2相交的区域  
        UNION(2),      //最终区域为region1 与 region2组合一起的区域  
        XOR(3),        //最终区域为region1 与 region2相交之外的区域  
        REVERSE_DIFFERENCE(4), //最终区域为region2 与 region1不同的区域  
        REPLACE(5); //最终区域为为region2的区域  
 } 

至于这六个参数的具体意义,后面给个具体的图给大家显示出来,先举个取交集的例子。

先构造两个相交叉的矩形,并画出它们的轮廓

        //构造一个画笔,画出矩形轮廓
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(2);

        //构造两个矩形
        Rect rect1 = new Rect(100, 100, 400, 200);
        Rect rect2 = new Rect(200, 0, 300, 300);
        
        //绘制两个矩形
        canvas.drawRect(rect1, paint);
        canvas.drawRect(rect2, paint);

然后利用上面的两个rect(rect1和rect2)来构造两个区域,并在rect1的基础上取与rect2的交集

        Region region1 = new Region(rect1);
        Region region2 = new Region(rect2);

        region1.op(region2, Region.Op.INTERSECT);
private void drawRegion(Canvas canvas, Region region, Paint paint) {
        RegionIterator regionIterator = new RegionIterator(region);
        Rect rect = new Rect();
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.FILL);
        while (regionIterator.next(rect)) {
            Log.d("tag", "------r.toString()=" + rect.toShortString());
            canvas.drawRect(rect, paint);
        }
    }

全部代码为:

package com.as.customview;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.RegionIterator;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import androidx.annotation.Nullable;

public class MyRegionView extends View {

    public MyRegionView(Context context) {
        this(context, null);
    }

    public MyRegionView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs, 0);
    }

    public MyRegionView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // TODO Auto-generated method stub
        super.onDraw(canvas);

        //初始化画笔
//        Paint paint = new Paint();
//        paint.setColor(Color.RED);
//        paint.setStyle(Paint.Style.FILL);
//        paint.setStrokeWidth(2);


        //构造一个椭圆路径
//        Path ovalPath = new Path();
//        RectF oval = new RectF(50, 50, 200, 500);
//        ovalPath.addOval(oval, Path.Direction.CCW);
//
//        //setPath传入一个比椭圆区域小的矩形区域,让其取交集
//        Region region = new Region();
//        region.setPath(ovalPath, new Region(50, 50, 200, 200));
//        drawRegion(canvas, region, paint);

        //构造一个画笔,画出矩形轮廓
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.STROKE);
        paint.setStrokeWidth(2);

        //构造两个矩形
        Rect rect1 = new Rect(100, 100, 400, 200);
        Rect rect2 = new Rect(200, 0, 300, 300);

        canvas.drawRect(rect1, paint);
        canvas.drawRect(rect2, paint);

        //构造两个Region
        Region region1 = new Region(rect1);
        Region region2 = new Region(rect2);

        //取两个区域的交集
        region1.op(region2, Region.Op.INTERSECT);

        drawRegion(canvas, region1, paint);

    }

    private void drawRegion(Canvas canvas, Region region, Paint paint) {
        RegionIterator regionIterator = new RegionIterator(region);
        Rect rect = new Rect();
        paint.setColor(Color.GREEN);
        paint.setStyle(Paint.Style.FILL);
        while (regionIterator.next(rect)) {
            Log.d("tag", "------r.toString()=" + rect.toShortString());
            canvas.drawRect(rect, paint);
        }
    }

}

其它参数的操作与这个类似,其实只需要改动region.op(region2, Op.INTERSECT);的Op参数值即可,下面就不再一 一列举,给出操作后的对比图。





其它一些方法

/**几个判断方法*/  
public native boolean isEmpty();//判断该区域是否为空  
public native boolean isRect(); //是否是一个矩阵  
public native boolean isComplex();//是否是多个矩阵组合  
  
  
/**一系列的getBound方法,返回一个Region的边界*/  
public Rect getBounds()   
public boolean getBounds(Rect r)   
public Path getBoundaryPath()   
public boolean getBoundaryPath(Path path)   
  
  
/**一系列的判断是否包含某点 和是否相交*/  
public native boolean contains(int x, int y);//是否包含某点  
public boolean quickContains(Rect r)   //是否包含某矩形
public native boolean quickContains(int left, int top, int right,  
                                        int bottom) //是否包含某矩形
 public boolean quickReject(Rect r) //是否没和该矩形相交  
 public native boolean quickReject(int left, int top, int right, int bottom); //是否没和该矩形相交  
 public native boolean quickReject(Region rgn);  //是否没和该矩形相交  
  
/**几个平移变换的方法*/  
public void translate(int dx, int dy)   
public native void translate(int dx, int dy, Region dst);  
public void scale(float scale) //hide  
public native void scale(float scale, Region dst);//hide  

下一篇文章地址

你可能感兴趣的:(Android 区域--Range(三))