Android自定義View實現圓形ImageView

一、常見問題

圓形ImageView是Android開發中比較常見的一個需求,但是Android原生的ImageView並不支持直接繪製圓形,所以需要使用自定義View。

下面是一些常見問題:

1、怎樣繪製一個圓形ImageView?

2、怎樣使圓形ImageView具有邊框?

3、怎樣對圓形ImageView進行動畫操作?

二、原理與實現

繪製一個圓形的ImageView可以分為以下幾步:

1、繼承ImageView

2、重寫onDraw方法,在其中繪製一個圓形的Bitmap

3、設置ImageView的ScaleType為CENTER_CROP,保證圖片的寬高比被保持且填充滿整個View

4、可以根據需求在繪製的Bitmap周圍添加邊框或者做動畫效果

下面是代碼示例:

public class CircleImageView extends ImageView {

    private Bitmap mBitmap;
    private Paint mPaint;

    public CircleImageView(Context context) {
        super(context);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            super.onDraw(canvas);
        } else {
            mBitmap = drawableToBitmap(drawable);
            mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2, mPaint);
        }
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();

        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }
}

三、常用功能實現

1、添加邊框

在上面的代碼基礎上,我們可以在繪製Bitmap的周圍添加一些邊框來增強視覺效果。

下面是添加邊框的代碼示例:

public class CircleImageView extends ImageView {

    private Bitmap mBitmap;
    private Paint mPaint;
    private Paint mBorderPaint;
    private int mBorderColor;
    private int mBorderWidth;

    public CircleImageView(Context context) {
        super(context);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.CircleImageView, defStyleAttr, 0);
        mBorderColor = a.getColor(R.styleable.CircleImageView_borderColor, Color.WHITE);
        mBorderWidth = a.getDimensionPixelSize(R.styleable.CircleImageView_borderWidth, 0);
        a.recycle();
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        mBorderPaint = new Paint();
        mBorderPaint.setAntiAlias(true);
        mBorderPaint.setColor(mBorderColor);
        mBorderPaint.setStyle(Paint.Style.STROKE);
        mBorderPaint.setStrokeWidth(mBorderWidth);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            super.onDraw(canvas);
        } else {
            mBitmap = drawableToBitmap(drawable);
            mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mBorderWidth, mPaint);
            canvas.drawCircle(getWidth() / 2, getHeight() / 2, getWidth() / 2 - mBorderWidth / 2, mBorderPaint);
        }
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();

        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }
}

2、添加動畫

我們也可以為這個圓形ImageView添加一些動畫效果,比如旋轉、縮放、漸變等。

下面是旋轉動畫和縮放動畫的代碼示例:

public class CircleImageView extends ImageView {

    private Bitmap mBitmap;
    private Paint mPaint;
    private Matrix mMatrix;
    private float mRotation;
    private float mScale = 1f;

    public CircleImageView(Context context) {
        super(context);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public CircleImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

        mMatrix = new Matrix();
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Drawable drawable = getDrawable();
        if (drawable == null) {
            super.onDraw(canvas);
        } else {
            mBitmap = drawableToBitmap(drawable);
            mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));

            int width = getWidth();
            int height = getHeight();
            int size = Math.min(width, height);

            mMatrix.reset();
            mMatrix.postScale(mScale, mScale);
            mMatrix.postRotate(mRotation, size / 2f, size / 2f);
            mMatrix.postTranslate((width - size) / 2f, (height - size) / 2f);

            canvas.drawCircle(size / 2f, size / 2f, size / 2f, mPaint);
        }
    }

    public void setRotation(float rotation) {
        mRotation = rotation;
        invalidate();
    }

    public void setScale(float scale) {
        mScale = scale;
        invalidate();
    }

    public void rotate(float from, float to, long duration) {
        ObjectAnimator animator = ObjectAnimator.ofFloat(this, "rotation", from, to);
        animator.setDuration(duration);
        animator.start();
    }

    public void scale(float from, float to, long duration) {
        ValueAnimator animator = ValueAnimator.ofFloat(from, to);
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mScale = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
        animator.setDuration(duration);
        animator.start();
    }

    private Bitmap drawableToBitmap(Drawable drawable) {
        if (drawable instanceof BitmapDrawable) {
            return ((BitmapDrawable) drawable).getBitmap();
        }

        int width = drawable.getIntrinsicWidth();
        int height = drawable.getIntrinsicHeight();

        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);

        return bitmap;
    }
}

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/186381.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-27 05:45
下一篇 2024-11-27 05:45

相關推薦

  • Python中自定義函數必須有return語句

    自定義函數是Python中最常見、最基本也是最重要的語句之一。在Python中,自定義函數必須有明確的返回值,即必須要有return語句。本篇文章將從以下幾個方面對此進行詳細闡述。…

    編程 2025-04-29
  • Android ViewPager和ScrollView滑動衝突問題

    Android開發中,ViewPager和ScrollView是兩個常用的控制項。但是當它們同時使用時,可能會發生滑動衝突的問題。本文將從多個方面介紹解決Android ViewPa…

    編程 2025-04-28
  • Android如何點擊其他區域收起軟鍵盤

    在Android應用中,當輸入框獲取焦點彈出軟鍵盤後,我們希望能夠點擊其他區域使軟鍵盤消失,以提升用戶體驗。本篇文章將說明如何實現這一功能。 一、獲取焦點並顯示軟鍵盤 在Andro…

    編程 2025-04-28
  • Python自定義列表

    本文將為大家介紹Python中自定義列表的方法和應用場景。對自定義列表進行詳細的闡述,包括列表的基本操作、切片、列表推導式、列表的嵌套以及列表的排序,希望能夠幫助大家更好地理解和應…

    編程 2025-04-27
  • 如何添加Python自定義模塊?

    Python是一種非常流行的腳本語言,因其易學易用和功能強大而備受歡迎。自定義模塊是Python開發中經常使用的功能之一。本文將從多個方面為您介紹如何添加Python自定義模塊。 …

    編程 2025-04-27
  • Android Studio HUD 實現指南

    本文將會以實例來詳細闡述如何在 Android Studio 中使用 HUD 功能實現菊花等待指示器的效果。 一、引入依賴庫 首先,我們需要在 build.gradle 文件中引入…

    編程 2025-04-27
  • Android和Vue3混合開發方案

    本文將介紹如何將Android和Vue3結合起來進行混合開發,以及其中的優勢和注意事項。 一、環境搭建 在進行混合開發之前,需要搭建好相應的開發環境。首先需要安裝 Android …

    編程 2025-04-27
  • Android Java Utils 可以如何提高你的開發效率

    Android Java Utils 是一款提供了一系列方便實用的工具類的 Java 庫,可以幫助開發者更加高效地進行 Android 開發,提高開發效率。本文將從以下幾個方面對 …

    編程 2025-04-27
  • Android JUnit測試完成程序自動退出決方法

    對於一些Android JUnit測試的開發人員來說,程序自動退出是一個經常面臨的困擾。下面從多個方面給出解決方法。 一、檢查測試代碼 首先,我們應該仔細檢查我們的測試代碼,確保它…

    編程 2025-04-25
  • Android Activity啟動流程

    一、Activity概述 Android應用程序是由許多Activity組成的。一個Activity代表一個屏幕上的窗口。用戶與應用程序交互時,Activity會接收用戶的輸入並處…

    編程 2025-04-25

發表回復

登錄後才能評論