首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Android 自定義 ImageView 實現圓角圖片:Xfermode 遮罩完整實作

     編輯:Java 相關知識

效果預覽

繼承 ImageView,利用 PorterDuffXfermode 的 `SRC_IN` 模式,以圓角矩形作為遮罩,實現圖片圓角顯示,支援 XML 屬性配置圓角半徑。

核心原理

  1. 建立圓角矩形 RectF 與 Paint。
  2. `onDraw` 中先繪製圓角矩形到離屏圖層(`saveLayer`)。
  3. 設定 `Paint.setXfermode(new PorterDuffXfermode(Mode.SRC_IN))`。
  4. 呼叫 `super.onDraw(canvas)` 繪製原圖,因 Xfermode 效果,僅保留圓角區域。
  5. 恢復圖層(`restoreToCount`)。

完整實作代碼

public class RoundedImageView extends ImageView {
    private Paint paint;
    private RectF rectF;
    private float radius = 40f; // 預設圓角半徑
    private PorterDuffXfermode xfermode;

    public RoundedImageView(Context context) {
        this(context, null);
    }

    public RoundedImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RoundedImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init();
        // 可從 attrs 讀取自訂屬性 radius
    }

    private void init() {
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        rectF = new RectF();
        xfermode = new PorterDuffXfermode(PorterDuff.Mode.SRC_IN);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        // 開啟離屏圖層
        int sc = canvas.saveLayer(0, 0, getWidth(), getHeight(), null,
                Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG |
                Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG |
                Canvas.CLIP_TO_LAYER_SAVE_FLAG);

        rectF.set(0, 0, getWidth(), getHeight());
        // 1. 繪製圓角矩形遮罩
        canvas.drawRoundRect(rectF, radius, radius, paint);

        // 2. 設定 Xfermode:只保留遮罩與圖片重疊部分
        paint.setXfermode(xfermode);

        // 3. 繪製原始圖片(super.onDraw 內部會畫 drawable)
        super.onDraw(canvas);

        // 4. 恢復
        paint.setXfermode(null);
        canvas.restoreToCount(sc);
    }

    /** 供外部動態設定圓角 */
    public void setRadius(float radius) {
        this.radius = radius;
        invalidate();
    }
}

XML 使用範例

<com.example.RoundedImageView
    android:id="@+id/img_avatar"
    android:layout_width="100dp"
    android:layout_height="100dp"
    android:src="@drawable/avatar"
    android:scaleType="centerCrop" />

注意事項

  • saveLayer 較耗效能,避免在列表項目等高頻刷新場景大量使用;可考慮 `BitmapShader` 或 `Canvas.clipPath` 替代。
  • 需關閉硬體加速或在 View 層級關閉:`setLayerType(LAYER_TYPE_SOFTWARE, null)`,否則部分裝置 Xfermode 失效。
  • 圖片縮放模式建議 `centerCrop` 避免留白。

替代方案比較

方案優點缺點
PorterDuffXfermode支援任意形狀遮罩、邊框、陰影需軟體繪製、效能較差
BitmapShader硬體加速友善、效能佳不支援描邊、陰影
Canvas.clipPath簡單、硬體加速支援抗鋸齒效果視裝置而定
CardView + 防裁剪XML 宣告、無代碼僅限矩形圓角、無法自訂形狀
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved