Android 自定义ImageView实现圆角图片
昨天给学生布置作业,写微信首页,也就是聊天的界面,listView里的item中联系人的头像是圆角的,图形界面如下:


那么我就仔细研究了圆角的具体实现。
那么首先,我想到了第一种实现方案:
1、就是给ImageView定义shape.xml文件,然后用src指定组件背景。那么想到这个方案的时候,我首先了解了一下ImageView的src和background属性。
background会根据ImageView组件给定的长宽进行拉伸,而src就存放的是原图的大小,不会进行拉伸 。src是图片内容(前景),bg是背景,可以同时使用。
这里我一看到可以同时使用,我瞬间就感觉哎,有门,那我就试了一下:
    <ImageView
      android:layout_width="100dp"
      android:layout_height="100dp"
      android:background="@drawable/shape"
      android:src="@mipmap/img_0326" />

这里shape.xml文件定义如下:
     <?xml version="1.0" encoding="utf-8"?>
      <shape xmlns:android="http://schemas.android.com/apk/res/android">
          <solid android:color="@color/colorhuise"/>
          <corners android:radius="20dp"/>
      </shape>

但是实现效果并不理想:方方正正,有棱有角的

我又自己测试了一下,把background改成图片,实现效果如下:


这是一张狗头和微信朋友圈的完美结合......哈哈,闲话少说那么很明显这里得出的结论是如果都设置背景图片的话可以一起使用,但是如果背景定义形状的时候就不起作用了。那么这种方法就不可行了,我们来尝试下一种方法:

2、自定义ImageView实现圆角图片:
这里我们自定义一个ImageView,代码如下:

public class RoundImageView extends ImageView {
  /**
  * 图片的类型,圆形or圆角
  */
  private int type;
  public static final int TYPE_CIRCLE = 0;
  public static final int TYPE_ROUND = 1;
  /**
  * 圆角大小的默认值
  */
  private static final int BODER_RADIUS_DEFAULT = 10;
  /**
  * 圆角的大小
  */
  private int mBorderRadius;

  /**
  * 绘图的Paint
  */
  private Paint mBitmapPaint;
  /**
  * 圆角的半径
  */
  private int mRadius;
  /**
  * 3x3 矩阵,主要用于缩小放大
  */
  private Matrix mMatrix;
  /**
  * 渲染图像,使用图像为绘制图形着色
  */
  private BitmapShader mBitmapShader;
  /**
  * view的宽度
  */
  private int mWidth;
  private RectF mRoundRect;

  public RoundImageView(Context context, AttributeSet attrs) {

    super(context, attrs);
    mMatrix = new Matrix();
    mBitmapPaint = new Paint();
    mBitmapPaint.setAntiAlias(true);

    TypedArray a = context.obtainStyledAttributes(attrs,
    R.styleable.RoundImageView);

    mBorderRadius = a.getDimensionPixelSize(
    R.styleable.RoundImageView_borderRadius, (int) TypedValue
    .applyDimension(TypedValue.COMPLEX_UNIT_DIP,
    BODER_RADIUS_DEFAULT, getResources()
    .getDisplayMetrics()));// 默认为10dp
    type = a.getInt(R.styleable.RoundImageView_type, TYPE_CIRCLE);// 默认为Circle

    a.recycle();
   }

  public RoundImageView(Context context) {

    this(context, null);
  }

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);

  /  **
  * 如果类型是圆形,则强制改变view的宽高一致,以小值为准
  */
    if (type == TYPE_CIRCLE) {
      mWidth = Math.min(getMeasuredWidth(), getMeasuredHeight());
      mRadius = mWidth / 2;
      setMeasuredDimension(mWidth, mWidth);
    }

  }

  /**
  * 初始化BitmapShader
  */
  private void setUpShader() {
    Drawable drawable = getDrawable();
    if (drawable == null) {
      return;
    }

  Bitmap bmp = drawableToBitamp(drawable);
  // 将bmp作为着色器,就是在指定区域内绘制bmp
  mBitmapShader = new BitmapShader(bmp, TileMode.CLAMP, TileMode.CLAMP);
  float scale = 1.0f;
  if (type == TYPE_CIRCLE) {
    // 拿到bitmap宽或高的小值
    int bSize = Math.min(bmp.getWidth(), bmp.getHeight());
    scale = mWidth * 1.0f / bSize;

   } else if (type == TYPE_ROUND) {
    Log.e("TAG",
    "b'w = " + bmp.getWidth() + " , " + "b'h = "
    + bmp.getHeight());
    if (!(bmp.getWidth() == getWidth() && bmp.getHeight() == getHeight())) {
      // 如果图片的宽或者高与view的宽高不匹配,计算出需要缩放的比例;缩放后的图片的宽高,一定要大于我们view的宽高;所以我们这里取大值;
      scale = Math.max(getWidth() * 1.0f / bmp.getWidth(),
      getHeight() * 1.0f / bmp.getHeight());
    }

  }
  // shader的变换矩阵,我们这里主要用于放大或者缩小
  mMatrix.setScale(scale, scale);
  // 设置变换矩阵
  mBitmapShader.setLocalMatrix(mMatrix);
  // 设置shader
  mBitmapPaint.setShader(mBitmapShader);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    Log.e("TAG", "onDraw");
    if (getDrawable() == null) {
      return;
  }
  setUpShader();

  if (type == TYPE_ROUND) {
    canvas.drawRoundRect(mRoundRect, mBorderRadius, mBorderRadius,
    mBitmapPaint);
  } else {
    canvas.drawCircle(mRadius, mRadius, mRadius, mBitmapPaint);
    // drawSomeThing(canvas);
  }
}

  @Override
  protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    // 圆角图片的范围
    if (type == TYPE_ROUND)
      mRoundRect = new RectF(0, 0, w, h);
    }

  /**
  * drawable转bitmap
  *
  * @param drawable
  * @return
  */
  private Bitmap drawableToBitamp(Drawable drawable) {
    if (drawable instanceof BitmapDrawable) {
      BitmapDrawable bd = (BitmapDrawable) drawable;
      return bd.getBitmap();
    }
  int w = drawable.getIntrinsicWidth();
  int h = drawable.getIntrinsicHeight();
  Bitmap bitmap = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888);
  Canvas canvas = new Canvas(bitmap);
  drawable.setBounds(0, 0, w, h);
  drawable.draw(canvas);
  return bitmap;
  }

  private static final String STATE_INSTANCE = "state_instance";
  private static final String STATE_TYPE = "state_type";
  private static final String STATE_BORDER_RADIUS = "state_border_radius";

  @Override
  protected Parcelable onSaveInstanceState() {
    Bundle bundle = new Bundle();
    bundle.putParcelable(STATE_INSTANCE, super.onSaveInstanceState());
    bundle.putInt(STATE_TYPE, type);
    bundle.putInt(STATE_BORDER_RADIUS, mBorderRadius);
    return bundle;
  }

  @Override
  protected void onRestoreInstanceState(Parcelable state) {
    if (state instanceof Bundle) {
      Bundle bundle = (Bundle) state;
      super.onRestoreInstanceState(((Bundle) state)
      .getParcelable(STATE_INSTANCE));
      this.type = bundle.getInt(STATE_TYPE);
      this.mBorderRadius = bundle.getInt(STATE_BORDER_RADIUS);
    } else {
      super.onRestoreInstanceState(state);
  }

}

  public void setBorderRadius(int borderRadius) {
    int pxVal = dp2px(borderRadius);
    if (this.mBorderRadius != pxVal) {
    this.mBorderRadius = pxVal;
    invalidate();
    }
  }

  public void setType(int type) {
    if (this.type != type) {
      this.type = type;
    if (this.type != TYPE_ROUND && this.type != TYPE_CIRCLE) {
      this.type = TYPE_CIRCLE;
    }
    requestLayout();
  }

}

  public int dp2px(int dpVal) {
    return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
      dpVal, getResources().getDisplayMetrics());
  }

}
  那么使用的时候,也比较方便

  <com.zhy.view.RoundImageView
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:layout_margin="10dp"
    android:scaleType="centerCrop"
    android:src="@drawable/img"
    map:borderRadius="60dp"
    map:type="round" >
  </com.zhy.view.RoundImageView>
这里实现效果是圆角的:

这里给大家讲几个其他的用法:根据上面type的类型为circle为第一个圆形效果,为round时实现第二个效果,通过borderRadius属性控制边角的弧度。

3、讲完了自定义,我们再给大家分享一个gitHub上的经典
https://github.com/siyamed/android-shape-imageview
使用方法:
1、添加依赖:
  在build.gradle(Module:app)下添加:
  compile 'com.github.siyamed:android-shape-imageview:0.9.+@aar'

  这里要注意使用的话最小版本要改成9或者以上
  2、添加完成之后从新build一下,引用资源
  3、布局文件中直接使用:
    <com.github.siyamed.shapeimageview.RoundedImageView
      android:layout_width="300dp"
      android:layout_height="300dp"
      android:src="@drawable/qiqiu"
      app:siRadius="20dp"/>
  这里的siRadius就相当于shape.xml里面的radius属性,即控制圆角弧度。这里使用的时候引用app的资源会爆红,解决方法是在最外层布局里面给他添加上引用:
  xmlns:app="http://schemas.android.com/apk/res-auto"
这个超简单的,效果就实现啦:

这里我们只给大家演示了矩形圆角,那其他的效果大家可以直接去gitHub上面去调用具体实现。

Android 圆角的效果实现的更多相关文章

  1. 【Android源代码下载】收集整理android界面UI效果源码

    在Android开发中,Android界面UI效果设计一直都是很多童鞋关注的问题,今天给大家分享下大神收集整理的多个android界面UI效果,都是源码,都是干货,贡献给各位网友! 话不多说,直接上效 ...

  2. App 图标设计 - 圆角透明效果(0 基础使用 PS)

    App 图标设计 - 圆角透明效果(0 基础使用 PS) 方法: 如果你有些基础,就不必看图文教程了: 1.使用圆角矩形工具选中,设置圆角尺寸[例如:1024*1024 px(圆角:160 px)] ...

  3. android 圆角图片的实现形式

    android 圆角图片的实现形式,包括用第三方.也有系统的.比如makeramen:roundedimageview,系统的cardview , glide .fresco . compile 'c ...

  4. Android ViewPager 动画效果

    找到个不错的开源项目:https://github.com/jfeinstein10/JazzyViewPager Android ViewPager 动画效果   

  5. python实现基于两张图片生成圆角图标效果的方法

    python实现基于两张图片生成圆角图标效果的方法 这篇文章主要介绍了python实现基于两张图片生成圆角图标效果的方法,实例分析了Python使用pil模块进行图片处理的技巧,分享给大家供大家参考. ...

  6. Android圆角布局、天气应用、树状图、日食动画、仿饿了么导航效果等源码

    Android精选源码 Android通用圆角布局源码 Android天气应用源码,界面美观 一个支持定制的树状 Android 自定义View PIN 码专用输入控件,支持任意长度和输入任意数据 A ...

  7. 一行实现QQ群组头像,微信群组,圆角等效果. 并支持url直接加载图片

    说点题外话. Coding中我们总是经历着这么几个过程. 学会使用: 不管是API也好, 开源库也好. 总是在最开始的学会去用. 了解实现原理: 可能会因为一些不兼容, 代码的异常状态的处理不够完美等 ...

  8. Android圆角矩形创建工具RoundRect类

    用于把普通图片转换为圆角图像的工具类RoundRect类(复制即可使用): import android.content.Context; import android.graphics.Bitmap ...

  9. android 圆角按钮和按钮颜色

    1. android 设置圆角按钮后,按下按钮后,还能改变按钮的颜色 <?xml version="1.0" encoding="UTF-8"?> ...

随机推荐

  1. page分页类

    <?php /** file: Page.class.php 完美分页类 Page */ class Page { private $total; //数据表中总记录数 private $lis ...

  2. 安装wampserve之前需要安装vc++2012.

    本人是64位系统下载了wampserver3.0.6之后安装好,启动报错缺少msvcr110.dll. 于是从网上下载了msvcr110.dll放到了windows的syswow64文件夹下,甚至还重 ...

  3. lintcode.177 把排序数组转换为高度最小的二叉搜索树

    把排序数组转换为高度最小的二叉搜索树    描述 笔记 数据 评测 给一个排序数组(从小到大),将其转换为一棵高度最小的排序二叉树. 注意事项 There may exist multiple val ...

  4. Struts2第九篇【OGNL、valueStack详解】

    什么是OGNL表达式? OGNL是Object Graphic Navigation Language 是操作对象属性的开源表达式. Struts2框架使用OGNL作为默认的表达式语言. 为什么我们学 ...

  5. Oracle函数之chr

    chr()函数将ASCII码转换为字符:字符 –> ASCII码:ascii()函数将字符转换为ASCII码:ASCII码 –> 字符: 在oracle中chr()函数和ascii()是一 ...

  6. 【机器学习实战】Machine Learning in Action 代码 视频 项目案例

    MachineLearning 欢迎任何人参与和完善:一个人可以走的很快,但是一群人却可以走的更远 Machine Learning in Action (机器学习实战) | ApacheCN(apa ...

  7. 我和Python

    记不得是年,我在网易云课堂上乱逛,看到了哈佛大学的<计算机编程导论>,这门课讲的正好是Python,讲的啥内容已经记不得多少了,因为是全英文教学,我只能慢慢的看字幕,一集得看个好几遍. 我 ...

  8. angular 自定义指令详解 Directive

    在angular中,Directive,自定义指令的学习,可以更好的理解angular指令的原理,当angular的指令不能满足你的需求的时候,嘿嘿,你就可以来看看这篇文章,自定义自己的指令,可以满足 ...

  9. Mybatis逆向生成Mapper文件

    本文参考博客 http://blog.csdn.net/for_my_life/article/details/51228098 1. 在resources根目录下添加generator.proper ...

  10. 深入理解计算机系统chapter9

    从概念上来讲:虚拟存储器被组织为一个存放在磁盘上的N个连续的字节大小的单元组成的数组. 磁盘上数组的内容被缓存到主存中 1. 读写内存的安全性 物理内存本身是不限制访问的,任何地址都可以读写,而操作系 ...