需要獲取 ImageView 中圖片**實際繪製後的矩形區域**(含縮放、平移、旋轉後的位置與大小),而非 ImageView 本身的佈局邊界。
public class MatrixImageView extends ImageView {
private RectF mSrcRect = new RectF(); // 原始圖片區域
private RectF mDstRect = new RectF(); // 變換後區域
@Override
public void setImageMatrix(Matrix matrix) {
super.setImageMatrix(matrix);
// 1. 獲取原始圖片邊界
Drawable drawable = getDrawable();
if (drawable != null) {
mSrcRect.set(0, 0, drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight());
} else {
mSrcRect.set(0, 0, getWidth(), getHeight());
}
// 2. 使用當前 Matrix 映射得到實際顯示區域
Matrix currentMatrix = getImageMatrix();
currentMatrix.mapRect(mDstRect, mSrcRect);
// mDstRect 現在包含:左、上、右、下座標(相對 ImageView 左上角)
// 寬度:mDstRect.width(),高度:mDstRect.height()
}
// 取得實際顯示區域
public RectF getDisplayRect() {
return new RectF(mDstRect);
}
// 取得實際顯示寬高
public float getDisplayWidth() { return mDstRect.width(); }
public float getDisplayHeight() { return mDstRect.height(); }
}
| 方法 | 說明 |
|---|---|
getImageMatrix() | 取得 ImageView 當前的變換矩陣(含 scaleType、setScale、setRotation 等產生的變換) |
Matrix.mapRect(dst, src) | 將 src 矩形套用矩陣變換,結果存入 dst。支援縮放、旋轉、平移、傾斜等複合變換 |
Drawable.getIntrinsicWidth/Height() | 取得圖片原始像素寬高(未縮放) |
public class ZoomableImageView extends ImageView implements ScaleGestureDetector.OnScaleGestureListener {
private ScaleGestureDetector scaleDetector;
private Matrix matrix = new Matrix();
private float scaleFactor = 1.0f;
private RectF displayRect = new RectF();
public ZoomableImageView(Context context, AttributeSet attrs) {
super(context, attrs);
setScaleType(ScaleType.MATRIX); // 必須用 MATRIX 類型
scaleDetector = new ScaleGestureDetector(getContext(), this);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
scaleDetector.onTouchEvent(event);
return true;
}
@Override
public boolean onScale(ScaleGestureDetector detector) {
scaleFactor *= detector.getScaleFactor();
scaleFactor = Math.max(0.5f, Math.min(scaleFactor, 5.0f));
matrix.setScale(scaleFactor, scaleFactor,
detector.getFocusX(), detector.getFocusY());
setImageMatrix(matrix);
updateDisplayRect();
return true;
}
@Override public boolean onScaleBegin(ScaleGestureDetector d) { return true; }
@Override public void onScaleEnd(ScaleGestureDetector d) {}
private void updateDisplayRect() {
Drawable d = getDrawable();
if (d == null) return;
RectF src = new RectF(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
matrix.mapRect(displayRect, src);
// 現在可以用 displayRect 做邊界檢測、裁剪、標註等
Log.d(TAG, "顯示區域: " + displayRect.toShortString());
}
// 取得實際顯示區域供外部使用
public RectF getActualDisplayRect() {
return new RectF(displayRect);
}
}
| 場景 | 用途 |
|---|---|
| 圖片裁剪 | 獲取可見區域對應原圖座標,執行裁剪 |
| 標註/標記 | 將螢幕觸控座標轉換為圖片座標 |
| 區域辨識 | 僅處理可見區域像素,節省運算 |
| 動畫過渡 | 共用元素轉場需精確起始/結束矩形 |
| 列印/匯出 | 按實際顯示比例匯出高解析度圖片 |
// 螢幕座標 → ImageView 區域座標
public PointF screenToImageView(float screenX, float screenY) {
int[] location = new int[2];
getLocationOnScreen(location);
return new PointF(screenX - location[0], screenY - location[1]);
}
// ImageView 區域座標 → 原圖座標(需 Matrix 可逆)
public PointF imageViewToSource(float viewX, float viewY) {
Matrix inverse = new Matrix();
if (getImageMatrix().invert(inverse)) {
float[] pts = {viewX, viewY};
inverse.mapPoints(pts);
return new PointF(pts[0], pts[1]);
}
return null;
}
// 原圖座標 → ImageView 區域座標
public PointF sourceToImageView(float srcX, float srcY) {
float[] pts = {srcX, srcY};
getImageMatrix().mapPoints(pts);
return new PointF(pts[0], pts[1]);
}
使用 getImageMatrix().mapRect(dstRect, srcRect) 即可獲得 ImageView 中圖片**實際繪製後的區域與尺寸**。關鍵點:setScaleType(ScaleType.MATRIX)、以原圖邊界為 srcRect、套用 getImageMatrix() 變換。此法支援任意複合變換(縮放、旋轉、平移、傾斜),是圖片編輯、裁剪、標註等功能的基礎。