自定義控制元件之繪圖篇(三):區域(Range)
前言:最近幾天對畫圖的研究有些緩慢,專案開始寫程式碼了,只能在晚上空閒的時候捯飭一下自己的東西,今天給大家講講區域的相關知識,已經想好後面兩篇的內容了,這幾天有時間趕緊寫出來給大家。有關介面開發的東東內容確實比較多,慢慢來吧,總有一天會不一樣。
我自己的一句警言,送給大家:
想要跟別人不一樣,你就要跟別人不一樣。----- Harvic
相關文章:
一、構造Region
1、基本建構函式
public Region() //建立一個空的區域
public Region(Region region) //拷貝一個region的範圍
public Region(Rect r) //建立一個矩形的區域
public Region(int left, int top, int right, int bottom) //建立一個矩形的區域
上面的四個建構函式,第一個還要配合其它函式使用,暫時不提。
第二個建構函式是通過其它的Region來複制一個同樣的Region變數
第三個,第四個才是正規常的,根據一個矩形或矩形的左上角和右下角點構造出一個矩形區域
2、間接構造
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系列函式的替換概念:
關於重寫新建一個類,並派生自view,並且要重寫OnDraw函式的問題我就不再講了,有問題的同學,可以參考下《android Graphics(一):概述及基本幾何圖形繪製》,當然最後我也會給出相關的原始碼,直接看原始碼也行。
下面寫了一個函式,先把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函式後,替換為新區域
3、使用SetPath()構造不規則區域
boolean setPath (Path path, Region clip)
引數說明:
Path path:用來構造的區域的路徑
Region 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) //獲取下一個矩形,結果儲存在引數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)來逐個獲取所有矩形,繪製出來,最終得到的就是整個區域,如果我們將上面的畫筆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的區域
}
至於這六個引數的具體意義,後面給個具體的圖給大家顯示出來,先舉個取交集的例子。效果圖:
//構造兩個矩形
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引數值即可,下面就不再一一列舉,給出操作後的對比圖。四、其它一些方法
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
本篇所涉及到的程式碼,我集合在了一個工程中,大家可以下載