自定义控件之绘图篇(三) —— 区域(Range)

前言

构造Region

基本构造函数

  • 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()// 置空

  • 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)// 后面单独讲

这是Region所具有的一系列set方法,我这里全部列了出来,下面一一对其讲解。

无论调用set系列函数的Region是不是有区域值,当调用set系列函数后,原来的区域值就会被替换成set函数里的区域。

  • setEmpty():从某种意义上讲置空也是一个构造函数,即将原来的一个区域变量变成了一个空变量,要再利用其它的set方法重新构造区域

  • set(Region region):利用新的区域值来替换原来的区域

  • set(Rect r):利用矩形所代表的区域替换原来的区域

  • set(int left, int top, int right, int bottom):同样,根据矩形的两个点构造出矩形区域来替换原来的区域值

  • setPath(Path path, Region clip):根据路径的区域与某区域的交集,构造出新区域,这个后面具体讲解

举个小例子,来说明一个set系列函数的替换概念。

下面写了一个函数,先把set函数注释起来,看看画出来的区域的位置,然后开启set函数,然后再看画出来的区域

里面有个函数drawRegion(Canvas canvas,Region rgn,Paint paint)只要知道它可以画出指定的区域就可以了,具体里面是什么意思,后面我们再仔细讲。

public class MyRegionView extends View {  

    public MyRegionView(Context context) {  
        super(context);  
        // TODO Auto-generated constructor stub  
    }  

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

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

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

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

    }  

    //这个函数不懂没关系,下面会细讲  
    private void drawRegion(Canvas canvas,Region rgn,Paint paint)  
    {  
        RegionIterator iter = new RegionIterator(rgn);  
        Rect r = new Rect();  

        while (iter.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) {  
        super(context);  
        // TODO Auto-generated constructor stub  
    }  

    @Override  
    protected void onDraw(Canvas canvas) {  
        // TODO Auto-generated method stub  
        super.onDraw(canvas);  
        //初始化Paint  
        Paint paint = new Paint();  
        paint.setColor(Color.RED);  
        paint.setStyle(Style.FILL);  
        paint.setStrokeWidth(2);  
        //构造一个椭圆路径  
        Path ovalPath = new Path();  
        RectF rect =  new RectF(50, 50, 200, 500);    
        ovalPath.addOval(rect, Direction.CCW);  
        //SetPath时,传入一个比椭圆区域小的矩形区域,让其取交集  
        Region rgn = new Region();  
        rgn.setPath(ovalPath,new Region(50, 50, 200, 200));  
        //画出路径  
        drawRegion(canvas, rgn, paint);  
    }  

    //这个函数不懂没关系,下面会细讲  
    private void drawRegion(Canvas canvas,Region rgn,Paint paint)  
    {  
        RegionIterator iter = new RegionIterator(rgn);  
        Rect r = new Rect();  

        while (iter.next(r)) {  
          canvas.drawRect(r, paint);  
        }   
    }  
}  

效果图如下:

这里写图片描述

矩形集枚举区域 —— RegionIterator类

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

  • RegionIterator(Region region) // 根据区域构建对应的矩形集

  • boolean next(Rect r) // 获取下一个矩形,结果保存到传参中去

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

private void drawRegion(Canvas canvas,Region rgn,Paint paint) {  
    RegionIterator iter = new RegionIterator(rgn);  
    Rect r = new Rect();  

    while (iter.next(r)) {  
      canvas.drawRect(r, paint);  
    }   
}  

上面我们也都看到了它的用法,首先,根据区域构建一个矩形集,然后利用next(Rect r)来逐个获取所有矩形,绘制出来,最终得到的就是整个区域,如果我们将上面的画笔StyleFILL改为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的区域    
 }

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

这里写图片描述

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

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

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

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

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

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

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

最后构造一个填充画笔,将所选区域用绿色填充起来

Paint paint_fill = new Paint();  
paint_fill.setColor(Color.GREEN);  
paint_fill.setStyle(Style.FILL);  
drawRegion(canvas, region, paint_fill);

完整代码如下:

/** 
 * created by harvic 
 * 2014/9/4 
 */  
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.Paint.Style;  
import android.graphics.Region.Op;  
import android.graphics.RegionIterator;  
import android.view.View;  

public class MyRegionView extends View {  

    public MyRegionView(Context context) {  
        super(context);  
        // TODO Auto-generated constructor stub  
    }  

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

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

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

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



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

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

        //再构造一个画笔,填充Region操作结果  
        Paint paint_fill = new Paint();  
        paint_fill.setColor(Color.GREEN);  
        paint_fill.setStyle(Style.FILL);  
        drawRegion(canvas, region, paint_fill);  

    }  


    private void drawRegion(Canvas canvas,Region rgn,Paint paint) {  
        RegionIterator iter = new RegionIterator(rgn);  
        Rect r = new Rect();  

        while (iter.next(r)) {  
            canvas.drawRect(r, paint);  
        }   
    }  
}  

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

这里写图片描述

其它一些方法

Region类除了上面的一些重要的方法以外,还有一些比较容易理解的方法,我就不再一一列举用法了,下面一并列出给大家

/**几个判断方法*/    
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 2D Graphics学习(二)、Canvas篇2、Canvas裁剪和Region、RegionIterator

原文链接:点击这里

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值