Android Drawable简介&CircleImageView简单实现

来源:互联网 发布:sun官方java教程 pdf 编辑:程序博客网 时间:2024/06/04 17:47

1.概述
圆形头像在很多app上都有使用,实现方式也有很多种。今天我们就先了解下Android drawable的知识点,最后再实现CircleImageView。
先看效果:
这里写图片描述

结合效果图:依次是CirclrImageView , 彩虹圈是整个布局的背景 (LayerDrawable结合ScaleDrawable实现) ,按钮(StateListDrawable)
HelloWord文本(背景添加了TrasitionDrawable)。

2.Drawable简介
Drawable的分类有很多,比较常用的有BitmapDrawable ,ShapeDrawable ,LayerDrawable,StateListDrawable等,一般由于当背景或者显示ImageView。
接下来简单介绍下这几种Drawable。

2.1 BitmapDrawable
这个就是一张图片,其中有几个常用的属性需要理解下。
属性
antialias:抗锯齿功能, 开启此功能是为了让图片看起来更加平滑,开启后图片清晰度也会有一定幅度降低(幅度较小可以忽略)。

dither:防抖动效果,此功能是为了适配图片像素与设备像素不一致时,保证图片的显示效果。 比如:我们设置的图片色彩模式为ARGB_8888,低端设备只支持ARGB_4444或者RGB_565模式时,开启此功能能保证图片较好的显示。

filter:过滤效果,此功能实在图片压缩或者拉伸时,开启可以较好的显示。
BitmapDrawable主要就介绍这三个属性,想了解更全面的可以参考官方api。

2.2 ShapeDrawable
ShapeDrawable 是通过color来构造的图行,通常用于xml中自定义图形图片。
属性
shape: 图形形状,有四种:rectangle oval line ring。这个很好理解。
corners: 角度 ,这个只能用于图形为rectangle的shape,就是设置矩形四个角的角度的。
gradient: 渐变效果,这个属性比较多
angle 渐变角度 0–90范围 0:左—>右 90:下—>上
centerX 渐变中心点x坐标
centerY 渐变中心点y坐标
startColor,centerColor,endCorlor,渐变起始色 中间色 结束色
gradientRadius 渐变半径 需要配合 type(渐变类别) 为radial一起使用
type 渐变类别,右三种 linear(线性) radial(径向) sweep(扫描)
具体效果可以自行体验下。
solid: 填充色 color属性指定色值
stroke: 描边 ,画shap的边框
width 边框宽度
color 边框线条颜色
dashWidth 虚线宽度
dashGap 虚线间距
size: shape大小 ,当shapDrawable作为背景时,这个大小会被拉伸或缩小为view的大小。如:上图,Hello World文本的背景

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="oval"    > <solid     android:color="#FFFFFF"/>  <stroke      android:width="5dp"      android:color="#00FF00"      android:dashWidth="15dp"      android:dashGap="6dp"      /></shape>

2.3 LayerDrawable
层次化的drawable集合,通过组合不同的drawable达到一种叠加效果
在xml中通过layer-list标签使用,可以放多个item,每个item里面可以放shape或者其他drawable资源。 注意这一系列的item都会被拉伸成或压缩成view的大小,所以使用时根据想要的效果来设置gravity top left right bottom属性。如:上图 ,彩虹圈的实现代码

<?xml version="1.0" encoding="utf-8"?><layer-list    xmlns:android="http://schemas.android.com/apk/res/android"    >  <item      android:left="120dp"      android:right="120dp"      android:top="120dp"      android:bottom="120dp"      android:drawable="@drawable/ring1">  </item>  <item      android:left="100dp"      android:right="100dp"      android:top="100dp"      android:bottom="100dp"      android:drawable="@drawable/ring2">  </item>  <item      android:left="80dp"      android:right="80dp"      android:top="80dp"      android:bottom="80dp"      android:drawable="@drawable/ring3">  </item>  <item      android:left="60dp"      android:right="60dp"      android:top="60dp"      android:bottom="60dp"      android:drawable="@drawable/ring4">  </item>  <item      android:left="40dp"      android:right="40dp"      android:top="40dp"      android:bottom="40dp"      android:drawable="@drawable/ring5">  </item>  <item      android:left="20dp"      android:right="20dp"      android:top="20dp"      android:bottom="20dp"      android:drawable="@drawable/ring6">  </item>  <item      android:drawable="@drawable/ring7">  </item></layer-list>

2.4 StateListDrawable
这个也是drawable的集合,每个drawable 表示view的一种状态。
在xml中通过selector标签使用,通常给按钮设置点击效果时使用。
如上图的 Hello Button

<?xml version="1.0" encoding="utf-8"?><selector xmlns:android="http://schemas.android.com/apk/res/android"><item    android:state_pressed="true"   >  <shape      android:shape="rectangle"      >    <corners        android:radius="10dp"        />    <solid        android:color="#F09"        />  </shape></item>  <item>    <shape        android:shape="rectangle"        >      <corners          android:radius="10dp"          />      <solid          android:color="#F129"          />    </shape>  </item></selector>

2.5 TransitionDrawable
这个也是drawable集合,用于实现view的淡入淡出的效果。没特殊属性。
如上如点击按钮 hello world文本会startTransition()

<?xml version="1.0" encoding="utf-8"?><transition xmlns:android="http://schemas.android.com/apk/res/android">  <item android:drawable="@drawable/back"/>  <item android:drawable="@drawable/back01"/>  <item android:drawable="@drawable/back02"/></transition>

三个back drawable就是色值不一致的虚线圆圈(如:back)

<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="http://schemas.android.com/apk/res/android"    android:shape="oval"    > <solid     android:color="#FFFFFF"/>  <stroke      android:width="5dp"      android:color="#00FF00"      android:dashWidth="15dp"      android:dashGap="6dp"      /></shape>

代码中开启

TransitionDrawable drawable = (TransitionDrawable) tv.getBackground();drawable.startTransition(1500); //参数:完成整个效果的时间

2.6 ScaleDrawable
可缩放的drawable
属性
scaleGravity: 相当于shape的gravity
scaleWidth: 宽度缩放比例 (百分制)
scaleHeight: 高度缩放比例 (百分制)

缩放等级 0–10000, 0表示完全缩放 也就是不可见了, 10000表示不缩放
如上图,对彩虹圈进行缩放 比例原图* 90%

<?xml version="1.0" encoding="utf-8"?><scale    xmlns:android="http://schemas.android.com/apk/res/android"    android:drawable="@drawable/layer"    android:scaleHeight="10%"    android:scaleWidth="10%"    android:scaleGravity="center"></scale>代码中使用ScaleDrawable scaleDrawable = (ScaleDrawable) layout.getBackground();scaleDrawable.setLevel(1);xml中使用android:background="@drawable/scale"

最终效果其实是近似60%,准确值应该是90% * 99.99%。

其他还有很多drawable类型,由于不常使用,就不介绍了。

掌握了以上系统提供的drawable,已经可以满足日常基本需求了,但是想要个性化,还得自定义。接下来快速实现简单的CircleImageVie.

CircleImageVIew 实现:
思路
1.自定义view 集成Imageview,重写ondraw方法
2.根据大小缩放图片, 依次画圆形和图片(重点:设置画笔属性 使图片结合起来)
关键代码:
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));
当然这个不是写死的,如果先画圆形 再画图形就用SRC_IN ,意思就是取2层的交集部分,并且显示上层,也就是后画的。 反之就用DST_IN, 意思是取2层交集,显示下层。实现代码如下

public class CirclePic extends ImageView {  private int defaultRadiu = 100;//默认圆形图片  public CirclePic(Context context) {    this(context, null);  }  public CirclePic(Context context, AttributeSet attrs) {    this(context, attrs, 0);  }  public CirclePic(Context context, AttributeSet attrs, int defStyleAttr) {    super(context, attrs, defStyleAttr);    init(attrs);  }  private void init(AttributeSet attrs) {    TypedArray a = getResources().obtainAttributes(attrs,R.styleable.CirclePic);    defaultRadiu = (int) a.getDimension(R.styleable.CirclePic_radiu,defaultRadiu);    a.recycle();  }  @Override protected void onDraw(Canvas canvas) {    Drawable drawable = getDrawable();    if (drawable != null) {      if (drawable instanceof BitmapDrawable && drawable.getIntrinsicWidth() > 0          && drawable.getIntrinsicHeight() > 0) {        Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();        Bitmap circleBitmap = getCircleBitamp(bitmap);        canvas.drawBitmap(circleBitmap, 0, 0, null);      }    } else {      super.onDraw(canvas);    }  }  /**   * 生成圆形bitmap   */  private Bitmap getCircleBitamp(Bitmap bitmap) {    Bitmap circleBitmap = null;    if (bitmap.getWidth() != defaultRadiu || bitmap.getHeight() != defaultRadiu) {      circleBitmap = Bitmap.createScaledBitmap(bitmap, defaultRadiu, defaultRadiu, false);    } else {      circleBitmap = bitmap;    }    Bitmap output = Bitmap.createBitmap(circleBitmap.getWidth(), circleBitmap.getHeight(),        Bitmap.Config.ARGB_8888);    Rect rect = new Rect(0, 0, circleBitmap.getWidth(), circleBitmap.getHeight());    Canvas canvas = new Canvas(output);    Paint paint = new Paint();    paint.setAntiAlias(true);    paint.setDither(true);    canvas.drawCircle(circleBitmap.getWidth() / 2, circleBitmap.getHeight() / 2,        circleBitmap.getWidth() / 2, paint);    //取2层交集部分,只显示上层    paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));    canvas.drawBitmap(circleBitmap, rect, rect, paint);    return output;  }}

利用这个参数大家可以发散脑洞组合出各种图形,下面给出PorterDuffXfermode所有参数说明:
1.PorterDuff.Mode.CLEAR :所绘制不会提交到画布上。
2.PorterDuff.Mode.SRC :显示上层绘制图片
3.PorterDuff.Mode.DST :显示下层绘制图片
4.PorterDuff.Mode.SRC_OVER :正常绘制显示,上下层绘制叠盖。
5.PorterDuff.Mode.DST_OVER :上下层都显示。下层居上显示。
6.PorterDuff.Mode.SRC_IN :取两层绘制交集。显示上层。
7.PorterDuff.Mode.DST_IN :取两层绘制交集。显示下层。
8.PorterDuff.Mode.SRC_OUT :取上层绘制非交集部分。
9.PorterDuff.Mode.DST_OUT :取下层绘制非交集部分。
10.PorterDuff.Mode.SRC_ATOP :取下层非交集部分与上层交集部分
11.PorterDuff.Mode.DST_ATOP :取上层非交集部分与下层交集部分
12.PorterDuff.Mode.XOR :去除两图层交集部分
13.PorterDuff.Mode.DARKEN :取两图层全部区域,交集部分颜色加深
14.PorterDuff.Mode.LIGHTEN :取两图层全部,点亮交集部分颜色
15.PorterDuff.Mode.MULTIPLY :取两图层交集部分叠加后颜色
16.PorterDuff.Mode.SCREEN :取两图层全部区域,交集部分变为透明色

最后看下对比效果图:
这里写图片描述
这里写图片描述

好了,今天就到这。下班开撸,大家有什么想法或者觉得可以改进的地方可以留言,互相学习。
源码地址:
https://github.com/ChenHaoLw/CircleImageView

1 0
原创粉丝点击