Android自定义View之绘制圆形头像

简介: Android自定义View之绘制圆形头像

前言

做APP应用开发的时候,用户头像肯定是必不可少的,但是90%以上的需求头像都是圆形的。那么,如何通过自定义View的方式实现圆形头像呢,那么,本片博文会告诉你不仅仅是实现过程。一定会有意想不到的收获哦!

最终效果

国际惯例,我们先来看最终实现的效果图

image.gif

自定义RoundImageView继承自ImageView  

public class RoundImageView extends ImageView {
    public RoundImageView(Context context) {
        super(context);
    }
    public RoundImageView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
    }
    public RoundImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }
}

image.gif

不知你是否注意过每当我们继承自View的时候,系统都会提示我们覆盖重写4个构造方法,这里我们只覆盖了三个,然后就开始在每个构造方法中进行初始化,那么,是不是每次都会调用所有的构造方法呢,如果不是,这三个构造方法又会什么时候调用呢?下面我们来通过例子来验证。

使用自定义View无非就两种情况下,第一种就是直接在xml布局中使用,另一种就是在Activity中new出来,下面我们分别使用上述两种方式,为了便于观察我们在三个构造方法中分别加入一行打印。

image.gif

首先我们在xml直接使用,运行打印如下:

com.example.roundimageview D/RoundImageView: RoundImageView: 两个参数的构造方法

然后我们在Activity中,new一个RoundImageView

roundImageView = RoundImageView(this@MainActivity)
roundImageView = RoundImageView(this@MainActivity, null)
roundImageView = RoundImageView(this@MainActivity, null,0)

image.gif

运行打印日志如下:

image.gif

结论:自定义View当在xml中使用,使用的是第二个构造方法,当在Activity中使用时,实例化时传入几个参数调用的就是含有几个参数的构造方法。

实现圆形头像的思想

我始终认为自定义View的难度只在于它的实现思想,通常我们遇到问题的时候,并不是Google不到,而是压根就不知道这个问题该去如何Google,如果知道了问题所产生的原因,其实问题已经迎刃而解了,最怕的是不知道问题为什么会产生。

实现圆形头像的思想一个简单的图就可以表示了。

image.gif

矩形区域是完整的图片,圆形区域就是我们最终显示的头像区域,那么就很简单了,圆形区域与矩形区域相交,取并集区域?在矩形中画一个与矩形长或宽相切的圆,而圆的直径是长或宽较短的一边。

编码实现

    • 获取原有头像的bitmap

       首先我们需要获取设置头像的bitmap,我们可以直接通过API来获取设置的图片资源,

    drawable = this.getDrawable();

    image.gif

     再将图片资源转化为bitmap

     首先我们判断drawable是否为空,如果为空说明用户没有设置,抛出资源未找到的异常。

    if (drawable == null) {
        throw new Resources.NotFoundException("Image resource not set");
    }

    image.gif

     如果不为空,我们创建一个与图片资源大小相等的bitmap,并将bitmap绘制出来,代码如下所示:

    bitmap = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(),
            Bitmap.Config.ARGB_8888);
    Canvas canvas = new Canvas(bitmap);
    drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
            drawable.getIntrinsicHeight());
    drawable.draw(canvas);

    image.gif

      • 绘制圆形bitmap

          通过上面的代码,我们得到了原有的bitmap图像,紧接着我们需要绘制圆形的bitmap,与上面类似,首先创建一个和bitmap大小一致的位图

      circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);

      image.gif

      我们画一个与bitmap等大的矩形

      Paint paint = new Paint();
      Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
      canvas.drawRect(rect,paint);
      RectF rectF = new RectF(rect);

      image.gif

       将较短的一边设置圆的半径

      float roundRa = 0.0f;
      if (bitmap.getWidth() > bitmap.getHeight()) {
          roundRa = bitmap.getHeight() / 2.0f;
      } else {
          roundRa = bitmap.getWidth() / 2.0f;
      }

      image.gif

        设置paint和canvas属性

      paint.setAntiAlias(true);
      canvas.drawARGB(0, 0, 0, 0);
      paint.setColor(Color.WHITE);
      paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

      image.gif

      canvas.drawARGB将绘制裁剪设为透明,paint.setXfermode中的PorterDuffXfermode类很强大,后面我们会单独一篇文章讲解。

      最终我们重新将bitmap绘制出来即可

      canvas.drawBitmap(bitmap, rect, rect, paint);

      image.gif

      绘制部分完整代码如下所示:

      * 获取圆形裁剪的bitmap
       *
       * @param bitmap 原bitmap
       */
      private Bitmap getCircleBitmap(Bitmap bitmap) {
          circleBitmap = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
          Canvas canvas = new Canvas(circleBitmap);
          Paint paint = new Paint();
          Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight());
          RectF rectF = new RectF(rect);
          float roundRa = 0.0f;
          if (bitmap.getWidth() > bitmap.getHeight()) {
              roundRa = bitmap.getHeight() / 2.0f;
          } else {
              roundRa = bitmap.getWidth() / 2.0f;
          }
          paint.setAntiAlias(true);
          canvas.drawARGB(0, 0, 0, 0);
          paint.setColor(Color.GRAY);
          canvas.drawRoundRect(rectF, roundRa, roundRa, paint);
          paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
          canvas.drawBitmap(bitmap, rect, rect, paint);
          return circleBitmap;
      }

      image.gif

        • 设置最终的bitmap

           得到bitma后我们直接重新设置即可显示

        setImageBitmap(getCircleBitmap(bitmap));

        image.gif

          本实例较为简单,就不贴所有代码了,如有需要留言邮箱即可,如有纰漏之处,欢迎指正!晚安!

          9.15 22:17 更新

          代码已上传github:https://github.com/huanglinqing123/RoundImageView

        目录
        相关文章
        |
        1月前
        |
        数据可视化 Android开发 开发者
        安卓应用开发中的自定义View组件
        【10月更文挑战第5天】在安卓应用开发中,自定义View组件是提升用户交互体验的利器。本篇将深入探讨如何从零开始创建自定义View,包括设计理念、实现步骤以及性能优化技巧,帮助开发者打造流畅且富有创意的用户界面。
        76 0
        |
        13天前
        |
        搜索推荐 前端开发 Android开发
        安卓应用开发中的自定义视图实现
        【10月更文挑战第30天】在安卓开发的海洋中,自定义视图是那抹不可或缺的亮色,它为应用界面的个性化和交互体验的提升提供了无限可能。本文将深入探讨如何在安卓平台创建自定义视图,并展示如何通过代码实现这一过程。我们将从基础出发,逐步引导你理解自定义视图的核心概念,然后通过一个实际的代码示例,详细讲解如何将理论应用于实践,最终实现一个美观且具有良好用户体验的自定义控件。无论你是想提高自己的开发技能,还是仅仅出于对安卓开发的兴趣,这篇文章都将为你提供价值。
        |
        14天前
        |
        Android开发 开发者 UED
        安卓开发中自定义View的实现与性能优化
        【10月更文挑战第28天】在安卓开发领域,自定义View是提升应用界面独特性和用户体验的重要手段。本文将深入探讨如何高效地创建和管理自定义View,以及如何通过代码和性能调优来确保流畅的交互体验。我们将一起学习自定义View的生命周期、绘图基础和事件处理,进而探索内存和布局优化技巧,最终实现既美观又高效的安卓界面。
        28 5
        |
        22天前
        |
        缓存 数据处理 Android开发
        在 Android 中使用 RxJava 更新 View
        【10月更文挑战第20天】使用 RxJava 来更新 View 可以提供更优雅、更高效的解决方案。通过合理地运用操作符和订阅机制,我们能够轻松地处理异步数据并在主线程中进行 View 的更新。在实际应用中,需要根据具体情况进行灵活运用,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在 Android 中使用 RxJava 更新 View 的技巧和方法,为开发高质量的 Android 应用提供有力支持。
        |
        22天前
        |
        缓存 调度 Android开发
        Android 在子线程更新 View
        【10月更文挑战第21天】在 Android 开发中,虽然不能直接在子线程更新 View,但通过使用 Handler、AsyncTask 或 RxJava 等方法,可以实现子线程操作并在主线程更新 View 的目的。在实际应用中,需要根据具体情况选择合适的方法,并注意相关的注意事项和性能优化,以确保应用的稳定性和流畅性。可以通过不断的实践和探索,进一步掌握在子线程更新 View 的技巧和方法,为开发高质量的 Android 应用提供支持。
        30 2
        |
        23天前
        |
        XML 前端开发 Android开发
        Android面试高频知识点(3) 详解Android View的绘制流程
        Android面试高频知识点(3) 详解Android View的绘制流程
        Android面试高频知识点(3) 详解Android View的绘制流程
        |
        26天前
        |
        XML 前端开发 Android开发
        Android面试高频知识点(3) 详解Android View的绘制流程
        Android面试高频知识点(3) 详解Android View的绘制流程
        24 2
        |
        4天前
        |
        搜索推荐 Android开发 开发者
        探索安卓开发中的自定义视图:打造个性化UI组件
        【10月更文挑战第39天】在安卓开发的世界中,自定义视图是实现独特界面设计的关键。本文将引导你理解自定义视图的概念、创建流程,以及如何通过它们增强应用的用户体验。我们将从基础出发,逐步深入,最终让你能够自信地设计和实现专属的UI组件。
        |
        6天前
        |
        Android开发 Swift iOS开发
        探索安卓与iOS开发的差异和挑战
        【10月更文挑战第37天】在移动应用开发的广阔舞台上,安卓和iOS这两大操作系统扮演着主角。它们各自拥有独特的特性、优势以及面临的开发挑战。本文将深入探讨这两个平台在开发过程中的主要差异,从编程语言到用户界面设计,再到市场分布的不同影响,旨在为开发者提供一个全面的视角,帮助他们更好地理解并应对在不同平台上进行应用开发时可能遇到的难题和机遇。
        |
        8天前
        |
        XML 存储 Java
        探索安卓开发之旅:从新手到专家
        【10月更文挑战第35天】在数字化时代,安卓应用的开发成为了一个热门话题。本文旨在通过浅显易懂的语言,带领初学者了解安卓开发的基础知识,同时为有一定经验的开发者提供进阶技巧。我们将一起探讨如何从零开始构建第一个安卓应用,并逐步深入到性能优化和高级功能的实现。无论你是编程新手还是希望提升技能的开发者,这篇文章都将为你提供有价值的指导和灵感。