首頁 > Java > java教程 > 深入理解Android開發RectF和Rect之間的差異

深入理解Android開發RectF和Rect之間的差異

伊谢尔伦
發布: 2017-01-16 13:12:56
原創
5467 人瀏覽過

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

re
public 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、按照指定的值缩放当前矩形区域


相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板