自定義View-Rect和RectF
阿新 • • 發佈:2018-12-23
Rect 類定義了一個矩形結構,同樣實現了 Parcelable 序列化介面。Rect 類定義了 left、top、right、bottom 四個成員變數,我們需要正確理解這 4 個成員變數的作用:
left:矩形左邊線條離 y 軸的距離
top:矩形上面線條離 x 軸的距離
right:矩形右邊線條離 y 軸的距離
bottom:矩形底部線條離 x 軸的距離
矩形是一種非常常見的圖形結構,並且能衍生出更多的圖形,如橢圓、扇形、弧線等等;矩形還能進行各種圖形運算,如交集、並集等等,所以,與之對應的 Rect 類功能也更加複雜。有人會疑惑為什麼不直接指定左上角的座標、寬度和高度來確定一個矩形,因為指定 top、left、right 和 bottom 更符合座標系的數學邏輯,也能更好的支援矩形的計算。
Rect 的主要功能有:
1)初始化:主要有兩種初始化的方法:一是直接指定 left、top、right、bottom 等 4 個成員變數的值,二是從另一個 Rect 物件中複製。下面是 Rect 的三個構造方法:
2)增值計算:根據 left、top、right、bottom 等 4 個成員變數計算矩形的寬度、高度或中心點的座標,主要的方法定義如下:
矩形的 left、top、right 和 bottom 來自於另一個矩形 src。
表示縮小,負數表示放大。
4)包含測試:支援一個點是否位於矩形內和一個矩形是否位於另一個矩形內。
矩形的交集與並集運算:交集是指兩個矩形相交的公共部分,並集是指兩個矩形所佔
有最大面積區域。
主要的方法如下:
如果還有疑問,扒開原始碼探個究竟,我們發現,roundOut()方法中獲取 left 和 top 時呼叫了 FloatMath.floor()方法,該方法返回小於引數的最大值,如 FloatMath.floor(3.5)返回 3;而獲取 right 和 bottom 呼叫了 FloatMath.ceil()方法,該方法返回大於引數的最小值,如
FloatMath.ceil(5.2)返回 6。
Rect 轉換成 RectF 就相對簡單了,例項化 RectF 時,構造方法支援傳遞 Rect 物件作為引數:
left:矩形左邊線條離 y 軸的距離
top:矩形上面線條離 x 軸的距離
right:矩形右邊線條離 y 軸的距離
bottom:矩形底部線條離 x 軸的距離
矩形是一種非常常見的圖形結構,並且能衍生出更多的圖形,如橢圓、扇形、弧線等等;矩形還能進行各種圖形運算,如交集、並集等等,所以,與之對應的 Rect 類功能也更加複雜。有人會疑惑為什麼不直接指定左上角的座標、寬度和高度來確定一個矩形,因為指定 top、left、right 和 bottom 更符合座標系的數學邏輯,也能更好的支援矩形的計算。
Rect 的主要功能有:
1)初始化:主要有兩種初始化的方法:一是直接指定 left、top、right、bottom 等 4 個成員變數的值,二是從另一個 Rect 物件中複製。下面是 Rect 的三個構造方法:
Rect() Rect(int left,int top,int right,int bottom) Rect(Rect r)
2)增值計算:根據 left、top、right、bottom 等 4 個成員變數計算矩形的寬度、高度或中心點的座標,主要的方法定義如下:
public final boolean isEmpty(){
return left>=right ||top>= bottom;
}
判斷 Rect 是否為空,也就是矩形區域面積是否為 0 或者為無效矩形。
public final int width(){
return right - left;
}
返回矩形的寬度。
public final int height(){ return bottom - top; }
返回矩形的高度。
public final int centerX(){
return (left + right) >> 1;
}
計算矩形中心點的 x 座標,右移一位相當於除以 2,移位運算比普通的除法運算效率
更高。
public final int centerY(){
return (top + bottom) >> 1;
}
計算矩形中心點的 y 座標。
public final float exactCenterX(){
return (left + right) * 0.5f;
}
計算矩形中心點的 x 座標,返回 float 型別,結果更精確。
public final float exactCenterY(){
return (top + bottom) * 0.5f;
}
計算矩形中心點的 y 座標,返回 float 型別,結果更精確。
public void setEmpty(){
left = right = top = bottom = 0;
}
將矩形的 left、top、right 和 bottom 置 0。
public void set(int left,int top,int right,int bottom){
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
給 left、top、right 和 bottom 重新賦值。
public void set(Rect src){
this.left = src.left;
this.top = src.top;
this.right = src.right;
this.bottom = src.bottom;
}
矩形的 left、top、right 和 bottom 來自於另一個矩形 src。
public void offset(int dx,int dy){
left += dx;
top += dy;
right += dx;
bottom += dy;
}
矩形的 left 和 right 同時移動相同的距離 dx,矩形的 top 和 bottom 同時移動相同的距
離 dy,實際上就是將矩形移動(dx、dy)距離,正負決定移動的方向。
public void offsetTo(int newLeft,int newTop){
right += newLeft - left;
bottom += newTop - top;
left = newLeft;
top = newTop;
}
offsetTo()方法也是移位,和 offset()不同的是前者是絕對定位,後者是相對定位。
public void inset(int dx,int dy){
left += dx;
top += dy;
right -= dx;
bottom -= dy;
}
實現了矩形的縮放功能,縮放中心點就是矩形的中心點,要注意的是 dx、dy 為正數時
表示縮小,負數表示放大。
4)包含測試:支援一個點是否位於矩形內和一個矩形是否位於另一個矩形內。
public boolean contains(int x,int y){
return left < right && top < bottom
&& x >= left && x < right && y >= top && y < bottom;
}
判斷點(x,y)是否位於矩形內。
public boolean contains(int left,int top,int right,int bottom){
return this.left < this.right && this.top < this.bottom
&& this.left <= left && this.top <= top
&& this.right >= right && this.bottom >= bottom;
}
判斷傳遞過來的矩形是否位於矩形內。
public boolean contains(Rect r){
return this.left < this.right && this.top < this.bottom
&& left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom;
}
判斷傳遞過來的矩形是否位於矩形內。
矩形的交集與並集運算:交集是指兩個矩形相交的公共部分,並集是指兩個矩形所佔
有最大面積區域。
主要的方法如下:
public boolean intersect(int left,int top,int right,int bottom){
if (this.left < right && left < this.right && this.top < bottom && top < this.bottom) {
if (this.left < left) this.left = left;
if (this.top < top) this.top = top;
if (this.right > right) this.right = right;
if (this.bottom > bottom) this.bottom = bottom;
return true;
}
return false;
}
傳入 Rect 的 left、top、right、bottom,並將構建的 Rect 物件與當前 Rect 物件做交集運算,結果儲存在當前 Rect 物件中。
public boolean intersect(Rect r){
return intersect(r.left, r.top, r.right, r.bottom);
}
傳入新的 Rect 物件,並將該物件與當前 Rect 物件做交集運算,結果儲存在當前 Rect物件中。比如有下面的程式碼段:
Rect rect1 = new Rect(0, 0, 400, 400);
Rect rect2 = new Rect(200, 200, 600, 600);
rect1.intersect(rect2);
此時,rect1 的 left、top、right、bottom 屬性被改變了,分別為 200、200、400、400,
public void union(int left,int top,int right,int bottom){
if ((left < right) && (top < bottom)) {
if ((this.left < this.right) && (this.top < this.bottom)) {
if (this.left > left) this.left = left;
if (this.top > top) this.top = top;
if (this.right < right) this.right = right;
if (this.bottom < bottom) this.bottom = bottom;
} else {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
}
}
}
public void union(Rect r){
union(r.left, r.top, r.right, r.bottom);
}
union()方法是計算兩個矩形的並集,傳入一個新的 Rect,與當前 Rect 進行並集運算,並將結果儲存在當前 Rect 物件中。比如有下面的程式碼段:
Rect rect1 = new Rect(0, 0, 400, 400);
Rect rect2 = new Rect(200, 200, 600, 600);
rect1.union(rect2);
執行後與交集一樣,最終的結果儲存在 rect1 物件中, rect1 的 left、top、right、bottom屬性值分別為:0,0,600,600,也就是說,並集取的是四個方向的最大值。與 Rect 類類似的還有 RectF 類,RectF 類的程式碼實現與 Rect 如出一轍,主要的不同是 Rect的 left、top、right、bottom 四個成員變數為 int 型別,而 RectF 為 float 型別。在開發中,常常會出現 Rect 與 RectF 相互轉換的情況,Rect 類中沒有定義與 RectF 相關的任何資訊,但在 RectF 類中,則定義了二者相互轉換的方法。RectF 轉換成 Rect。RectF 定義了兩個名為 round 和 roundOut 的方法,round()方法將 RectF類的型別為 float 的 left、top、right、bottom 屬性以四捨五入的方式轉換成 int 再通過 Rect 型別的引數傳回,roundOut()方法雖然和 round()差不多,但在某些情況下返回的矩形區域要大些。
如果還有疑問,扒開原始碼探個究竟,我們發現,roundOut()方法中獲取 left 和 top 時呼叫了 FloatMath.floor()方法,該方法返回小於引數的最大值,如 FloatMath.floor(3.5)返回 3;而獲取 right 和 bottom 呼叫了 FloatMath.ceil()方法,該方法返回大於引數的最小值,如
FloatMath.ceil(5.2)返回 6。
public void round(Rect dst){
dst.set(FastMath.round(left), FastMath.round(top),
FastMath.round(right), FastMath.round(bottom));
}
public void roundOut(Rect dst){
dst.set((int) FloatMath.floor(left), (int) FloatMath.floor(top),
(int) FloatMath.ceil(right), (int) FloatMath.ceil(bottom));
}
Rect 轉換成 RectF 就相對簡單了,例項化 RectF 時,構造方法支援傳遞 Rect 物件作為引數:
public RectF(Rect r) {
if (r == null) {
left = top = right = bottom = 0.0f;
} else {
left = r.left;
top = r.top;
right = r.right;
bottom = r.bottom;
}
}