Rect中文意思“矩形或長方形”,Rect物件持有一個矩形的四個integer座標值,RectF物件持有一個矩形的四個float座標值,這是兩者最大的差異。從實現的方式來看,Rect是一個final類實現Parcelable接口,RectF是一個普通類實現Parcelable接口,Rect和RectF除了記錄的坐標數據類型不一樣外,兩個類提供的方法大體上都是一樣的。
1. 聯繫:
都是用來表示座標系中的一塊矩形區域,並可以對其做一些簡單操作。這塊矩形區域,需要用左上和右下兩個座標點表示。
2. 區別:
(1).精準度不一樣。 Rect是使用int型別作為數值,RectF是使用float型別作為數值。
(2).兩個類型提供的方法也不是完全一致。
3. 程式碼部分
package com.pansoft.viewdemo.view; import android.content.Context; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Paint.Style; import android.graphics.Rect; import android.graphics.RectF; import android.view.View; /** 自定义View **/ public class MyView extends View { /** 上下文 */ private Context mContext; /** 画笔 */ private Paint mPaint; public MyView(Context context) { super(context); mContext = context; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mPaint = new Paint(); // 设置画笔的颜色 mPaint.setColor(Color.RED); // 设置填充颜色 mPaint.setStyle(Style.FILL); RectF rect = new RectF(10, 10, 100, 100); // Rect rect2 = new Rect(10, 10, 100, 100); canvas.drawRect(rect, mPaint); } }
RectF和Rect基礎
final TextView textView = new TextView(this); textView.setText("显示Rect存储坐标数据"); /** * 设置TextView的宽度和高度,最后计算TextView的左上角和右下角的坐标 */ textView.setLayoutParams(new ViewGroup.LayoutParams(400, 400)); textView.setBackgroundColor(Color.parseColor("#00BFFF")); textView.setGravity(Gravity.CENTER); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int top = v.getTop(); int left = v.getLeft(); int right = v.getRight(); int bottom = v.getBottom(); /** * 将TextView相对父控件的坐标保存在Rect对象 */ mRect.left = left; mRect.right = right; mRect.top = top; mRect.bottom = bottom; textView.setText(mRect.toShortString()); } });
final Button button = new Button(this); /** * 设置button的宽度和高度,最后计算矩形局域的宽和高 */ ViewGroup.MarginLayoutParams params=new ViewGroup.MarginLayoutParams(800, 300); /** * 设置button的margin属性值 */ params.setMargins(100,DensityUtil.dip2px(this,100),100,100); button.setLayoutParams(params); button.setText("计算Rect坐标"); button.setBackgroundColor(Color.parseColor("#7FFFAA")); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int top = v.getTop(); int left = v.getLeft(); int right = v.getRight(); int bottom = v.getBottom(); /** * 将TextView相对父控件的坐标保存在Rect对象 */ mRect.left = left; mRect.right = right; mRect.top = top; mRect.bottom = bottom; button.setText("宽度:"+mRect.width()+"\n"+"高度:"+mRect.height()); } });
final Button anim_btn =new Button(this); /** * 设置button的宽度和高度 */ params=new ViewGroup.MarginLayoutParams(800, 300); /** * 设置button的margin属性值,计算矩形局域的中心点坐标 */ params.setMargins(100,DensityUtil.dip2px(this,100),100,100); anim_btn.setLayoutParams(params); anim_btn.setText("计算Rect坐标"); anim_btn.setBackgroundColor(Color.parseColor("#DDA0DD")); anim_btn.setGravity(Gravity.RIGHT); anim_btn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int top = v.getTop(); int left = v.getLeft(); int right = v.getRight(); int bottom = v.getBottom(); /** * 将TextView相对父控件的坐标保存在Rect对象 */ mRect.left = left; mRect.right = right; mRect.top = top; mRect.bottom = bottom; anim_btn.setText("水平中心点:"+mRect.centerX()+"\n垂直中心点:"+mRect.centerY()); } });
正是因為每一個矩形局域包含著getRight()和getBottom()屬於View宣告的方法,因此每一個View子類別或控制項繼承上述方法,Rect或RectF類似一個工具類,封裝四個頂點座標的計算關係,使用getLeft()、getTop() 、getRight()和getBottom()需要注意兩個問題:
第一個問題:getLeft()、getTop()、getRight()和getBottom()計算相對其父容器的位置
第二個問題: getLeft()、getTop()、getRight()和getBottom()計算結果為0,是因為目前View子類別或控制項沒有繪製完成。解決方法,onClick方法點擊的時候計算或使用執行緒的延時計算
/** * 延时获取控件相对父容器的left、top、right、bottom坐标,否则为0 */ new Thread(new Runnable() { @Override public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } saveCoordinateToRect(); } }).start();
RectF和Rect深入
Rect是一個final類,不屬於被繼承,實現Parcelable介面執行序列化,聲明publicpublic作用域的四個整數屬性:left、top、right和bottom,用來記錄View矩形區域的四個頂點座標。
public Rect() {}
1、建立一個空的Rect對象,left、top、right和bottom的預設值為0
public Rect(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; }
2、建立一個指定座標值的Rect對象,left、top、right和bottom為指定值
public Rect(Rect r) { if (r == null) { left = top = right = bottom = 0; } else { left = r.left; top = r.top; right = r.right; bottom = r.bottom; } }
3、使用已知的Rect,建立一個新的Rect對象,left、top、right和bottom為已知的Rect包含的值
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Rect r = (Rect) o; return left == r.left && top == r.top && right == r.right && bottom == r.bottom; }
4、判斷當前Rect與指定的o是否同一個,相同的條件:屬於同一個物件或兩者left、top、right或bottom屬性值一樣
@Override public int hashCode() { int result = left; result = 31 * result + top; result = 31 * result + right; result = 31 * result + bottom; return result; }
5、計算Rect屬性值的雜湊碼
@Override public String toString() { StringBuilder sb = new StringBuilder(32); sb.append("Rect("); sb.append(left); sb.append(", "); sb.append(top); sb.append(" - "); sb.append(right); sb.append(", "); sb.append(bottom); sb.append(")"); return sb.toString(); }
6、以Rect(left,top-right,bottom)的格式傳回矩形四個座標值
public String toShortString(StringBuilder sb) { sb.setLength(0); sb.append('['); sb.append(left); sb.append(','); sb.append(top); sb.append("]["); sb.append(right); sb.append(','); sb.append(bottom); sb.append(']'); return sb.toString(); }
7、以[left,top] [right,bottom]的格式傳回矩形四個座標值,即矩形區域左上角和右下角座標
public String toShortString() { return toShortString(new StringBuilder(32)); }
8、以[left, top] [right,bottom]的格式傳回矩形四個座標值,即矩形區域左上角和右下角座標,和上述方法一樣
public String flattenToString() { StringBuilder sb = new StringBuilder(32); // WARNING: Do not change the format of this string, it must be // preserved because Rects are saved in this flattened format. sb.append(left); sb.append(' '); sb.append(top); sb.append(' '); sb.append(right); sb.append(' '); sb.append(bottom); return sb.toString(); }
9、以left top right bottom的格式傳回矩形四個座標值,即平舖的格式,例如:0 0 400 400或100 100 800 300
public static Rect unflattenFromString(String str) { Matcher matcher = UnflattenHelper.getMatcher(str); if (!matcher.matches()) { return null; } return new Rect(Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), Integer.parseInt(matcher.group(3)), Integer.parseInt(matcher.group(4))); }
10、給定一個平鋪格式的字串,例如:0 0 400 400,判斷是否合法,然後轉換為一個Rect物件
public void printShortString(PrintWriter pw) { pw.print('['); pw.print(left); pw.print(','); pw.print(top); pw.print("]["); pw.print(right); pw.print(','); pw.print(bottom); pw.print(']'); }
11、將Rect包含的屬性值以[left,top] [right,bottom]的格式寫入給定的PrintWriter流中
public final boolean isEmpty() { return left >= right || top >= bottom; }
12、判斷Rect是否一個空對象,即包含的屬性值是否不為0
public final int width() { return right - left; }
13、計算矩形區域的寬度
public final int height() { return bottom - top; }
14、計算矩形區域的高度
public final int centerX() { return (left + right) >> 1; }
15、計算矩形區域的水平中心點,計算結果為分數則傳回最接近的整數數,例如:水平中心點400
public final int centerY() { return (top + bottom) >> 1; }
16、計算矩形區域的垂直中心點,計算結果為分數則傳回最接近的整數數,例如:垂直中心點850
public final float exactCenterX() { return (left + right) * 0.5f; }
17、計算矩形區域的水平中心點,傳回結果float類型,例如:水平中心點400.0
public final float exactCenterY() { return (top + bottom) * 0.5f; }
18、計算矩形區域的垂直中心點,傳回結果float類型,例如:垂直中心點850.0
public void setEmpty() { left = right = top = bottom = 0; }
19、將Rect物件包含的屬性值設定為0
republic void set(int left, int top, int right, int bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; }
20、將Rect的屬性值設定為指定的值
public void set(Rect src) { this.left = src.left; this.top = src.top; this.right = src.right; this.bottom = src.bottom; }
21、複製指定的Rect物件所包含的屬性值
public void offset(int dx, int dy) { left += dx; top += dy; right += dx; bottom += dy; }
22、在目前矩形區域的水平方向、垂直方向分別增加dx、dy距離,即擴展
public void offsetTo(int newLeft, int newTop) { right += newLeft - left; bottom += newTop - top; left = newLeft; top = newTop; }
23、在目前矩形區域的水平方向、垂直方向分別偏移dx、dy距離,即水平平移dx、垂直平移dy
public void inset(int dx, int dy) { left += dx; top += dy; right -= dx; bottom -= dy; }
24、在目前矩形區域的水平方向、垂直方向分別減少dx 、dy距離,即縮小
public boolean contains(int x, int y) { return left < right && top < bottom // check for empty first && x >= left && x < right && y >= top && y < bottom; }
25、計算指定的座標(x,y)是否包含在矩形區域範圍內,包含返回true,否則回傳false
public boolean contains(int left, int top, int right, int bottom) { // check for empty first return this.left < this.right && this.top < this.bottom // now check for containment && this.left <= left && this.top <= top && this.right >= right && this.bottom >= bottom; }
26、計算指定的left、top、right、bottom頂點是否包含在矩形區域範圍內,包含回傳true,否則傳回false
public boolean contains(Rect r) { // check for empty first return this.left < this.right && this.top < this.bottom // now check for containment && left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom; }
27、計算指定的Rect是否包含在矩形區域範圍內,包含傳回true,否則傳回false
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; }
28、計算目前Rect與指定的left、top、right、bottom頂點是否存在交集區域,存在回傳true並且回傳指定座標,否則回傳false
public boolean intersect(Rect r) { return intersect(r.left, r.top, r.right, r.bottom); }
29、计算当前Rect与指定的Rect是否存在交集区域,存在返回true并且返回指定坐标,否则返回false
public boolean setIntersect(Rect a, Rect b) { if (a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom) { left = Math.max(a.left, b.left); top = Math.max(a.top, b.top); right = Math.min(a.right, b.right); bottom = Math.min(a.bottom, b.bottom); return true; } return false; }
30、计算指定的a、b是否存在交集区域,存在返回true并且返回最大坐标,否则返回false
public boolean intersects(int left, int top, int right, int bottom) { return this.left < right && left < this.right && this.top < bottom && top < this.bottom; }
31、计算当前Rect与指定的left、top、right、bottom顶点是否存在交集区域,存在返回true并且不返回指定坐标,否则返回false
public static boolean intersects(Rect a, Rect b) { return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom; }
32、计算指定的a、b是否存在交集区域,存在返回true并且不返回最大坐标,否则返回false
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; } } }
33、计算当前Rect与指定的left、top、right、bottom顶点是否存在并集区域,存在更新当前矩形区域,否则不更新
public void union(Rect r) { union(r.left, r.top, r.right, r.bottom); }
34、计算当前Rect与指定的Rect是否存在并集区域,存在更新当前矩形区域,否则不更新
public void union(int x, int y) { if (x < left) { left = x; } else if (x > right) { right = x; } if (y < top) { top = y; } else if (y > bottom) { bottom = y; } }
35、计算当前Rect与指定的坐标(x,y)是否存在并集区域,存在更新当前矩形区域,否则不更新
public void sort() { if (left > right) { int temp = left; left = right; right = temp; } if (top > bottom) { int temp = top; top = bottom; bottom = temp; } }
36、排序当前矩形区域,符合:left
public void scale(float scale) { if (scale != 1.0f) { left = (int) (left * scale + 0.5f); top = (int) (top * scale + 0.5f); right = (int) (right * scale + 0.5f); bottom = (int) (bottom * scale + 0.5f); } }
37、按照指定的值缩放当前矩形区域
public void scaleRoundIn(float scale) { if (scale != 1.0f) { left = (int) Math.ceil(left * scale); top = (int) Math.ceil(top * scale); right = (int) Math.floor(right * scale); bottom = (int) Math.floor(bottom * scale); } }
38、按照指定的值缩放当前矩形区域