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/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

发表回复

登录后才能评论