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. 201521123051《Java程序设计》第十四周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. 2. 书面作业 1. MySQL数据库基本操作 建立数据库,将自己的姓名.学号作为一条记录插入.(截图,需出现自 ...

  2. 数据结构与算法->树->2-3-4树的查找,添加,删除(Java)

    代码: 兵马未动,粮草先行 作者: 传说中的汽水枪 如有错误,请留言指正,欢迎一起探讨. 转载请注明出处. 目录 一. 2-3-4树的定义 二. 2-3-4树数据结构定义 三. 2-3-4树的可以得到 ...

  3. 06jQuery-06-AJAX

    1.JS的AJAX AJAX,Asynchronous JavaScript and XML,意思就是用JavaScript执行异步网络请求. 如果要让用户留在当前页面中,同时发出新的HTTP请求,就 ...

  4. Oracle-表被锁住

    1.如果update 某个表,没有报错,等待很久都没结束,那很有可能是表被锁了. 2.查看被锁的对象 select sid,serial#,username,SCHEMANAME,osuser,MAC ...

  5. PHP 动态调整内存限制

    最近公司的一个PHP项目在操作大文件的时候总是抛出这个异常 Fixing PHP Fatal Error: Allowed Memory Size Exhausted 经过一番调试后发现是达到了PHP ...

  6. 【Conclusion】MySQL使用

    MySQL使用 因为数据库实验用到了MySQL,这里对现在已经涉及到的MySQL部分操作做一个简单的小结. 1.安装MySQL 上MySQL的官网下载对应自己OS平台的MySQL安装文件,有在线安装和 ...

  7. java 如何将方法作为传参--多态

    在前段时研究智能算法时,发现如果使用java进行实现的话,往往具体实现过程差不多,但是适应值函数却根据 研究对象的不同发生很大的改变,这样对代码的维护产生很大的阻碍,于是产生的一个疑问:可不可以将适 ...

  8. BZOJ-1050-[HAOI2006]旅行comf(并查集)

    Description 给你一个无向图,N(N<=500)个顶点, M(M<=5000)条边,每条边有一个权值Vi(Vi<30000).给你两个顶点S和T,求 一条路径,使得路径上最 ...

  9. 每周分享之 二 http协议(2)

    本次分享http协议,共分为三部分,这是第二部分,主要讲解请求与响应的字段,以及状态码. 以http/1.1版本的一个完整的请求与响应作为例子 http请求信息由三部分组成 1.请求方法(GET/PO ...

  10. poj1067威佐夫博奕

    取石子游戏 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 31490   Accepted: 10374 Descripti ...