Android开发艺术探索(5) --- Drawable

Drawable表示的是一种可以在Canvas上进行绘制的抽象概念,它的种类有很多,最常见的颜色和图片都可以是一个Drawable

1. Drawable简介

使用方式:

  1. 定义xml,然后通过@Drawable引入布局
  2. Java代码:new一个所需Drawable并set相关属性,最后加载到布局中。
  • 使用getIntrinsicWidthgetIntrinsicHeight两个方法能获得Drawable的宽高
  • 但是并不是每一个Drawable都有内部的宽高(eg:颜色)

2. Drawable分类

2.1 BitmapDrawable

  • 最简单的Drawable,表示一张图片
  • XML描述
<?xml version="1.0" encoding="utf-8"?>
<bitmap
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@[package:]drawable/drawable_resource"
    android:antialias="[true | false]"
    android:dither="[true | false]"
    android:filter="[true | false]"
    android:gravity="[top | bottom | left | right |
     center_vertical | fill_vertical | center_horizontal |
      fill_horizontal | center | fill |
       clip_vertical | clip_horizontal]"
    android:mipMap="[true | false]"
    android:tileMode="[disabled | clamp | repeat | mirror]" />
  • 对应<bitmap>标签
  • 基本使用

Drawable/bitmap.xml

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:antialias="true"
    android:dither="true"
    android:filter="true"
    android:gravity="top"
    android:tileMode="mirror"
    android:src="@drawable/enactus"/>

layout/activity_main.xml

<ImageView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:src="@drawable/bitmap"/>
bitmap Demo

2.2 ShapeDrawable

  • 一种常见的Drawable,可以理解为通过颜色来构造图形,既可以是纯色的图形也可以是具有渐变效果的图形
  • shape标签创建的Drawable,但实体类型是GradientDrawable
<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="[rectangle | oval | line | ring]"
    <corners
        android:radius="integer"
        android:topLeftRaidus="integer"
        android:topRightRaidus="integer"
        android:bottomLeftRaidus="integer"
        android:bottomRightRaidus="integer" />
    <gradient
        android:angle="integer"
        android:centerX="integer"
        android:centerY="integer"
        android:centerColor="color"
        android:endColor="color"
        android:gradientRadius="integer"
        android:startColor="color"
        android:type="[linear | radial | sweep]"
        android:useLevel="[true | false]" />
    <padding
        android:left="integer"
        android:top="integer"
        android:right="integer"
        android:bottom="integer" />
    <size
        android:width="integer"
        android:height="integer" />
    <solid
        android:color="color" />
    <stroke
        android:width="integer"
        android:color="color"
        android:dashWidth="integer"
        android:dashGap="integer" />
</shape>
  • 基本使用
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <gradient android:type="radial" android:centerColor="@color/colorPrimaryDark"
        android:startColor="@color/colorPrimary"
        android:angle="45" android:centerY="0" android:centerX="0" android:endColor="@color/colorAccent" android:gradientRadius="200dp"/>
    <stroke android:width="2dp" android:color="#00FF00"
        android:dashGap="5dp" android:dashWidth="5dp"/>
</shape>
ShapeDrawable

2.3 LayerDrawable

  • 对应的XML标签是<layer-list>,它表示一种层次化的Drawable集合
  • 一个layer-list可包含多个item,每个item表示一个Drawable。可在android:drawable中引用一个现有的Drawable资源,也可在<item>中自定义Drawable
  • 默认情况下,layer-list中的所有Drawable都会被缩放至View的大小。可设置Drawable相对于View的上下左右偏移量。另外对于bitmap,需要使用其android:gravity来控制图片的显示效果。
  • layer-list有层次的概念,下面的item会覆盖上面的item。通过合理的分层,可实现一些特殊的叠加效果。
  • 基本使用
<?xml version="1.0" encoding="utf-8"?>
<layer-list
    xmlns:android="http://schemas.android.com/apk/res/android">
<item
    android:drawable="@drawable/shape"
    android:id="@+id/layer_drawable"
    android:top="10dp"
    android:right="10dp"
    android:left="10dp"
    android:bottom="10dp"/>
</layer-list>
LayerDrawable
  • 基本使用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/remoteViews_content"
    android:orientation="vertical">

    <EditText
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:background="@drawable/layer_drwable"/>
</LinearLayout>
<?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"/>
    </shape>
</item>

    <item android:bottom="6dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"/>
        </shape>
    </item>

    <item
        android:bottom="2dp"
        android:left="2dp"
        android:right="2dp">
        <shape android:shape="rectangle">
            <solid android:color="#ffffff"/>
        </shape>
    </item>
</layer-list>
LayerDrawable

2.4 StateListDrawable

  • 对应于<selector>标签,它也表示Drawable集合
  • 每个Drawable都对应着一个View的状态,这样系统就会根据View的状态来选择合适的Drawable
  • 主要用于设置可单机的View的背景,最常见的是Button
  • 系统根据View的当前状态从selector中选择对应的item,每个item对应着一个具体的Drawable,系统自下而上查找,直至匹配到第一条item,如果没有找到,就会选择默认的item,因为默认的item不附带状态,所以它可以匹配任何View的任何状态
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize="[true | false]"
    android:dither="[true | false]"
    android:variablePadding="[true | false]">
    <item
        android:drawable="@[package:]drawable/drawable_resource"
        android:state_pressed="[true | false]"
        android:state_focused="[true | false]"
        android:state_hovered="[true | false]"
        android:state_selected="[true | false]"
        android:state_checkable="[true | false]"
        android:state_checked="[true | false]"
        android:state_enabled="[true | false]"
        android:state_activated="[true | false]"
        android:state_window_focused="[true | false]" />
    <!-- 其他item -->
</selector>

基本使用

StateListDrawable stateListDrawable = (StateListDrawable) getResources().getDrawable(R.drawable.state_list_drawable);
Button button = findViewById(R.id.btn);
button.setBackgroundDrawable(stateListDrawable);
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/shape" android:state_pressed="true"/>
</selector>
StateListDrawable

2.5 LevelListDrawable

  • 对应于<level-list>,它同样表示一个Drawable集合,集合中的每个Drawable都有一个等级的概念
  • 根据不同的等级,LevelListDrawable会切换成对应的Drawable
  • 若作为View背景时,可通过DrawablesetLevel()来设置不同的等级来切换具体的Drawable
  • 若作为ImageView的前景,可通过ImageViewsetImageLevel()来切换。

基本使用

final LevelListDrawable levelListDrawable = (LevelListDrawable) getResources().getDrawable(R.drawable.level_list_drawable);
        Button button = findViewById(R.id.btn);
        button.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View view) {
                levelListDrawable.setLevel(1);
            }
        });
        button.setBackgroundDrawable(levelListDrawable);
<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/shape"
        android:maxLevel="1"
        android:minLevel="1"/>
    <item
        android:drawable="@drawable/layer_drwable"
        android:maxLevel="0"/>
</level-list>
LevelListDrawable

2.6 TransitionDrawable

  • 对应于<transition>标签,用于实现两个Drawable之间的淡入淡出效果

基本使用

TextView textView = findViewById(R.id.text);
TransitionDrawable transitionDrawable = (TransitionDrawable)textView.getBackground();
transitionDrawable.startTransition(1000);
<TextView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@+id/text"
        android:background="@drawable/transition_drawable"/>
<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/shape"/>

    <item android:drawable="@color/colorPrimaryDark"/>
</transition>
TransitionDrawable

2.7 InsetDrawable

  • 对应于<inset>标签,它可以将其他Drawable内嵌到自己当中,并可以在四周留出一定的间距
  • 使用场景:View希望自己的北京比自己的实际区域小
    基本使用
<?xml version="1.0" encoding="utf-8"?>
<inset 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@[package:]drawable/drawable_resource"
    android:inset="dimension"
    android:insetTop="dimension"
    android:insetRight="dimension"
    android:insetBottom="dimension"
    android:insetLeft="dimension" />
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetBottom="15dp"
    android:insetLeft="15dp"
    android:insetRight="15dp"
    android:insetTop="15dp">

    <shape>
        <solid android:color="@color/colorPrimaryDark"/>
    </shape>
<!--内嵌到InsetView中-->
</inset>
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/inset_drawable"
        />
InsetView

2.8 ScaleDrawable

  • 对应于<scale>标签,可以根据自己的等级将指定的Drawable缩放到一定的比例
  • 等级0表示ScaleDrawable不可见,为默认值
<?xml version="1.0" encoding="utf-8"?>
<scale 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@[package:]drawable/drawable_resource"
    android:scaleGravity="[top | bottom | left | right |
        center_vertical | center_horizontal | center |
        fill_vertical | fill_horizontal | fill |
        clip_vertical | clip_horizontal]"
    android:scaleWidth="percentage"
    android:scaleHeight="percentage" />

基本使用

ImageView imageView = findViewById(R.id.imageView);
ScaleDrawable scaleDrawable = (ScaleDrawable) imageView.getBackground();
scaleDrawable.setLevel(1);
   <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/scale_drawable"
        />
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:scaleHeight="70%"
    android:scaleWidth="70%"
    android:scaleGravity="center"
    android:drawable="@drawable/enactus">
</scale>
ScaleDrawable

2.9 ClipDrawable

  • 对应于<clip>标签,它可以根据自己当前的等级来裁剪另一个Drawable
  • 通过android:clipOrientationandroid:gravity两个属性来控制裁剪
<?xml version="1.0" encoding="utf-8"?>
<clip 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@[package:]drawable/drawable_resource"
    android:clipOrientation="[vertical | horizontal]"
    android:gravity="[top | bottom | left | right |
        center_vertical | center_horizontal | center |
        fill_vertical | fill_horizontal | fill |
        clip_vertical | clip_horizontal]" />

基本使用

ImageView imageView = findViewById(R.id.imageView);
ClipDrawable clipDrawable = (ClipDrawable) imageView.getDrawable();
clipDrawable.setLevel(5000);
    <ImageView
        android:id="@+id/imageView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/clip_drawable"
        />
<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:drawable="@drawable/enactus"
    android:gravity="bottom">

</clip>
clipDrawable

参考资料:
Android中常用的Drawable

3. 自定义Drawable

  • Drawable的使用范围:一是作为ImageView中的图箱来显示,另外一个就是作为View的背景
  • 核心是Draw方法,可以通过重写Drawable的Draw方法来自定义Drawable
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 日更220 此刻其实有点犯困,因为昨晚熬夜至3点才睡觉,不过今日活动还算圆满。今天晚上爸妈来,于是回家陪他们吃饭。...
    暖心的自由书写阅读 160评论 0 1
  • 一、五险二金指的是什么? 五险:养老保险、医疗保险、失业保险、工伤保险、生育保险,另外还有大病保险; 二金:住房公...
    红尘佛心阅读 15,972评论 2 3
  • 相看两不厌 网上有段子说:教书是一场盛大的暗恋,你费尽心思去爱一群人,结果只感动了自己;学生虐你千万遍,你待学生如...
    篱下絮语阅读 75评论 0 1
  • 当抓取到的图片Url后,如果一张一张的把图片都缓存到本地会占用大量的空间,而且没有什么太大的作用,还是把数据存到数...
    太二道士阅读 2,921评论 0 2