Drawable 吐血总结

一.Drawable简介

Drawable是对可绘制物件的一般抽象,表示一种图像的概念,在实际开发中常被当做View的背景或者ImageView的图像,一般用xml来构建。(与View不同,没有事件和交互方法)

一般情况下,除了直接使用放在Drawable下的图片,其实的Drawable的用法都和xml相关,我们可以使用shape、layer-list等标签绘制一些背景,还可以通过selector标签定义View的状态的效果等。当然了基本每个标签都对应于一个真正的实体类,关系如下:(图片来自:Cyril Mottier :master_android_drawables)


二.Drawable优势

他使用简单,比自定义VIew的成本要低;其次,非图片类型的Drawable占用的空间较小,可以减小apk大小。

三.Drawable的分类

BitmapDrawable,ShapeDrawable,LayerDrawable,StateListDrawable,Levels,NinePatch,Scale,自定义

四.Drawable原理

setBounds()画在那里由附属View决定  draw(Canvas canvas)

五.自定义Drawable

圆角图片:

public class RoundRectImageDrawable extends Drawable {

    private Paint mPaint;
    private Bitmap mBitmap;

    private RectF rectF;

    public RoundRectImageDrawable(Bitmap bitmap) {
        mBitmap = bitmap;
//着色器 若图片过小使用拉伸形式在x,y上扩展
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);//抗锯齿
        mPaint.setShader(bitmapShader);
        rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
    }

    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        super.setBounds(left, top, right, bottom);
        rectF = new RectF(left, top, right, bottom);
    }


    @Override
    public void draw(Canvas canvas) {
//在30,30位置为圆心的圆弧
        canvas.drawRoundRect(rectF, 30, 30, mPaint);
    }

    @Override
    public int getIntrinsicWidth() {
        return mBitmap.getWidth();
    }

    @Override
    public int getIntrinsicHeight() {
        return mBitmap.getHeight();
    }

    @Override
    public void setAlpha(int alpha) {
        mPaint.setAlpha(alpha);
    }

    @Override
    public void setColorFilter(ColorFilter cf) {
        mPaint.setColorFilter(cf);
    }

    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }

}


圆形图片:

public class CircleImageDrawable extends Drawable {
    private Paint mPaint;
    private int mWidth;
    private Bitmap mBitmap;
    private RectF rectF;
    public CircleImageDrawable(Bitmap bitmap) {
        mBitmap = bitmap;
        BitmapShader bitmapShader = new BitmapShader(bitmap, Shader.TileMode.CLAMP,
                Shader.TileMode.CLAMP);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setShader(bitmapShader);
        rectF = new RectF(0, 0, bitmap.getWidth(), bitmap.getHeight());
        mWidth = Math.min(mBitmap.getWidth(), mBitmap.getHeight());
    }

    @Override
    public void draw(Canvas canvas) {
        canvas.drawCircle(rectF.left+mWidth / 2, rectF.top+mWidth / 2, mWidth / 2, mPaint);
    }
    @Override
    public void setBounds(int left, int top, int right, int bottom) {
        super.setBounds(left, top, right, bottom);
        rectF = new RectF(left, top, right, bottom);
        mWidth = (int)Math.min(rectF.width(), rectF.height());
    }
    @Override
    public int getIntrinsicWidth() {
        return mWidth;
    }
    @Override
    public int getIntrinsicHeight() {
        return mWidth;
    }
    @Override
    public void setAlpha(int alpha) {
        mPaint.setAlpha(alpha);
    }
    @Override
    public void setColorFilter(ColorFilter cf) {
        mPaint.setColorFilter(cf);
    }
    @Override
    public int getOpacity() {
        return PixelFormat.TRANSLUCENT;
    }
}
 Drawable使用方法:

( (ImageView)findViewById(R.id.pic1)).setImageDrawable(new RoundRectImageDrawable(bitmap));
( (ImageView)findViewById(R.id.pic2)).setImageDrawable(new CircleImageDrawable(bitmap));
BitmapDrawable 表达一张图片

android:src 图片的资源id。

android:antialias抗锯齿。

android:dither是否开启抖动效果。让高质量的图片在低质量的屏幕上还能保持较好的显示效果

android:filter当图片被拉伸或者压缩时,开启过滤效果可以保持较好的显示效果。

android:gravity 当图片小于容器尺寸时,可以对图片进行定位。

android:tileMode平铺模式,默认关闭平铺模式disable.repeat表示的简单水平和竖直方向上的平铺效果,

                                mirror:表示在水平和竖直方向上呈现镜面投影。clamp 图片四周的像素会扩散到周围。

ShapeDrawable 通过颜色来构造图形

Shape类型详解:

Shape类型用来绘制几何图形,易用而轻量化。

Shape通常用xml文件方式使用,存放在drawable目录下

Shape原理:

draw(Canvas canvas,Paint paint)画Shape

onResize(float width,float height) 设置大小

Shape类型:

使用xml:

RectShape:矩形,直角矩形,圆角矩形

Ring,Line:环形,线行(xml)

OvalShape:椭圆形,圆形

只能使用代码:

PathShape:线形,环形

ArcShape:弧形

Shape的通用类型

图形的形状有四个选项:

android:shape:[rectangle(default),oval,line,ring

另外oval,line必须通过<stroke>标签来指定线的宽度跟颜色信息。

ring的额外属性:

innerRadius:圆环的内半径。

thickness:圆环的厚度,若与thicknessRatio同时存在,以thickness为准。

innerRadiusRatio:内半径占整个drawable的宽度的比例,默认9。

thicknessRatio:厚度占整个drawable的宽度的比例,默认3。

useLevel:一般都应该使用false,否则有可能无法达到预期的显示效果,除非他被当做LevelLisDrawable来使用。

android:corners:圆角半径

int:radius 为四个角同时设定相同的角度,优先级低,会被单独设置的值取代,

单独设置: topLeftRadius,topRight......。

android:gradient:渐变

他与<solid>标签相互排斥,solid表示纯色。

angle:渐变的角度,默认为0,其值必须为45的整数倍,0表示从左到右,90从上到下。

centerX,Y:渐变中心的坐标

startColor centerColor endColor

type:linear 线行渐变 radial 径向渐变 sweep 扫描线渐变

gradientRadius:渐变半径,仅当type="radial"有效

android:solid :纯色填充

color:填充色

android:stroke Shape描边

width:描边的宽度

color:描边的颜色

dashWidth:虚线线段的宽度

dashGap:虚线线段的间隔

android:padding :包含他的View的空白

android:size: 设置ShapeDrawable的固有宽高,但作为View的背景,Shape还是会被拉伸或者缩小为View的大小。

eg:

A:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners android:radius="10dp" />
    <solid android:color="#ff00ff" />
    <padding
        android:bottom="8dp"
        android:left="8dp"
        android:right="8dp"
        android:top="8dp" />
    <size
        android:width="100dp"
        android:height="100dp" />
    <stroke
        android:width="4dp"
        android:color="@android:color/darker_gray"
        android:dashGap="4dp"
        android:dashWidth="40dp" />
</shape>


B:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">

       <padding
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp" />

    <corners android:radius="10dp" />
    <size
        android:width="200dp"
        android:height="200dp" />

    <gradient
        android:angle="0"
        android:centerColor="#00ff00"
        android:centerX="0.5"
        android:centerY="0.5"
        android:endColor="#0000ff"
        android:gradientRadius="100dp"
        android:startColor="#ff0000"
        android:type="radial" />
</shape>

C:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="line">

    <solid android:color="#ff00ff" />

    <padding
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp"
        android:top="2dp" />

    <corners android:radius="10dp" />
    <size

        android:height="20dp" />
    <stroke
        android:width="8dp"
        android:color="#88000000"
        android:dashGap="4dp"
        android:dashWidth="20dp" />

</shape>

xml文件只能显示横线

具体应用情况:把layerType设置为software才能显示虚线.

<ImageView

    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layerType="software"
    android:src="@drawable/line" />

Shape对象放入ShapeDrawable,ShapeDrawable设定画笔的风格

使用代码实现:

环形

final  ImageView oval=(ImageView)   findViewById(R.id.oval);
  oval.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
          oval.setImageResource(R.drawable.oval2);
      }
  });
  shapeDrawable=new ShapeDrawable();
  Path path = new Path();
  path.moveTo(50, 0);
  path.lineTo(0, 50);
  path.lineTo(50, 100);
  path.lineTo(100, 50);
  path.lineTo(50, 0);
  path.close();
  PathShape pathShape = new PathShape(path, 100, 100);

  shapeDrawable = new ShapeDrawable(pathShape);
  shapeDrawable.getPaint().setStyle(Paint.Style.FILL);
  shapeDrawable.getPaint().setColor(Color.BLUE);
 ((ImageView)findViewById(R.id.path)).setBackground(shapeDrawable);
弧形

 arcShape=new ArcShape(180,-270);
  shapeDrawable = new ShapeDrawable(arcShape);
  shapeDrawable.setBounds(0, 0, 100, 150);
  shapeDrawable.getPaint().setStrokeWidth(10);
  shapeDrawable.getPaint().setStyle(Paint.Style.STROKE);
  shapeDrawable.getPaint().setColor(Color.GREEN);

((ImageView)findViewById(R.id.arc)).setBackground(shapeDrawable);
LayerDrawable 一种层次化的drawable集合

对应xml标签是<layer-list>,通过将不同的drawable放置在不同的层上面从而达到一种叠加后的效果。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <solid android:color="#0ac39e"></solid>
        </shape>
    </item>
    <item android:top="1dp" android:bottom="1dp" android:left="1dp" android:right="1dp" android:drawable="@drawable/eve">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"></solid>
        </shape>
    </item>
</layer-list>

StateListDrawable 表示Drawable集合

每一个drawable对应view的一种状态,Android框架为View定义了四种不同的状态,这些状态值的改变会引发View相关操作,例如:更换背景图片、是否发点击事件等; 视图几种不同状态含义见下图:

                             

     

   其中selected和focused的区别有如下几点:

      1,我们通过查看setSelected()方法,来获取相关信息。

        SDK中对setSelected()方法----对于与selected状态有如下说明:

             public void setSelected (boolean selected)

             Since: APILevel 1

             Changes the selection state of this view. Aview can be selected or not. Note that selection is not the same as

        focus. Views are typically selected in the context of an AdapterView like ListView or GridView ;the selected view is 

        the view that is highlighted.

            Parameters selected   true if the view must be selected, false otherwise


           由以上可知:selected不同于focus状态,通常在AdapterView类群下例如ListView或者GridView会使某个View处于

     selected状态,并且获得该状态的View处于高亮状态。

 

    2、一个窗口只能有一个视图获得焦点(focus),而一个窗口可以有多个视图处于”selected”状态中。

 

      总结:focused状态一般是由按键操作引起的;

                pressed状态是由触摸消息引起的;

                selected则完全是由应用程序主动调用setSelected()进行控制。

 

      例如:当我们触摸某个控件时,会导致pressed状态改变;获得焦点时,会导致focus状态变化。于是,我们可以通过这种

   更新后状态值去更新我们对应的Drawable对象了。


使用:

系统会根据View当前的状态从selector中选择对应的item,每个item对应着一个具体的drawable,系统按照从上到下的顺序查找,直至插糟到第一条匹配的item。

[java]  view plain copy print ?
  1. <?xml version="1.0" encoding="utf-8" ?>     
  2. <selector xmlns:android="http://schemas.android.com/apk/res/android">   
  3.   <!-- 触摸时并且当前窗口处于交互状态 -->    
  4.   <item android:state_pressed="true" android:state_window_focused="true" android:drawable= "@drawable/pic1" />  
  5.   <!--  触摸时并且没有获得焦点状态 -->    
  6.   <item android:state_pressed="true" android:state_focused="false" android:drawable="@drawable/pic2" />    
  7.   <!--选中时的图片背景-->    
  8.   <item android:state_selected="true" android:drawable="@drawable/pic3" />     
  9.   <!--获得焦点时的图片背景-->    
  10.   <item android:state_focused="true" android:drawable="@drawable/pic4" />    
  11.   <!-- 窗口没有处于交互时的背景图片 -->    
  12.   <item android:drawable="@drawable/pic5" />   
  13. </selector>  

selector作为color资源时,item指定android:color属性,并放与color目录下


<selector
    xmlns:android="http://schemas.android.com/apk/res/android"

   >


    <item android:color="#0000ff" android:state_pressed="true" />

    <item android:color="#ff0000" android:state_checked="true" />

    <item android:color="#00ffff" android:state_selected="true" />

    <item android:color="#ffff00" android:state_activated="true" />
    <item android:color="#00ff00" android:state_checked="false" />
    <item android:color="#ff00ff" />


</selector>

android:drawable也可以引用@color颜色值

<selector
    xmlns:android="http://schemas.android.com/apk/res/android" >

    <!-- 当前窗口失去焦点时 -->
    <item android:color="#ff0000" android:state_window_focused="false" />
    <!-- 不可用时 -->
    <item android:color="#00ff00" android:state_enabled="false" />
    <!-- 按压时 -->
    <item android:color="#0000ff" android:state_pressed="true" />
    <!-- 被选中时 -->
    <item android:color="#00ffff" android:state_selected="true" />
    <!-- 被激活时 -->
    <item android:color="#ffff00" android:state_activated="true" />
    <!-- 默认时 -->
    <item android:color="#ff00ff" />


</selector>
在ListView的Item里设置StateIistDrawable有两个地方,人选其一:

andriod:listSelector,但默认背景是透明的。

itemView里设置android:background

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/statedrawable"
    android:descendantFocusability="blocksDescendants"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin">
statedrawable.xml

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:enterFadeDuration="1000"
    android:exitFadeDuration="1000"
    >
     <item android:drawable="@drawable/rect90" android:state_pressed="true" />
    <item android:drawable="@drawable/rect0" android:state_pressed="false" />

    <item android:drawable="@drawable/rect315" />


</selector>

先更到这



  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值