zoukankan      html  css  js  c++  java
  • Android之Drawable

    Android 中图片和常见的颜色都可以是一个Drawable. Drawable可以方便我们做出一些特殊的UI效果,这一点在UI相关的开发工作中尤其重要。其主要优点有:

    • 使用简单,比自定义View成本要低;
    • 非图片类型的Drawable占用空间小,对减小apk大小有帮助;

    Drawable作为图片的时,内部的宽/高这个参数比较重要,通过getIntrinsicWidth和getIntrinsicHeight这两个方法获得。但作为颜色背景时,是没有宽高概念的,会自动延伸和View的背景大小一样。

     Drawable的分类:常见的有BitmapDrawable、ShapeDrawable、LayerDrawable以及StateListDrawable等。

    1.BitmapDrawable: 表示一张图片,可以直接引用原图片,或者用XML文件来进行描述。一般直接引用原图片。

    2.ShapeDrawabe:  是一种常见的通过颜色来构造的图形,可以是纯色图形,也可以是渐变的图形。这种情况下,用<shape>标签来创建drawable。简单介绍一下它的主要参数:

    <?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:topLeftRadius="integer"
            android:topRightRadius="integer"
            android:bottomLeftRadius="integer"
            android:bottomRightRadius="integer" />
    
        <gradient
            android:angle="integer"
            android:centerX="integer"
            android:centerY="integer"
            android:centerColor="color"
            android:endColor="color"
            android:gradientRadius="integer"
            android:startColor="integer"
            android:type=["linear" | "radial" | "sweep"]
            android:useLevel="true" />
    
        <padding android:left="integer"
            android:right="integer"
            android:top="integer"
            android:bottom="integer" />
    
        <size android:width="integer"
              android:height="integer" />
    
        <solid android:color="color" />
    
        <stroke android:color="color"
            android:width="integer"
            android:dashWidth="integer"
            android:dashGap="integer" />
    </shape>
    shape            

    1.  rectangle 矩形

    2.  oval 椭圆  

    3.  line 横线

    4.  ring 圆环                                                                 

    corners

    1.  圆角半径

    2.  radius的优先级比后面的topLeftRadius,topRightRadius等要低;

    gradient

    和<solid>标签是互斥的,因为solid表示纯色填充。
    angle:渐变的角度,0表示从左到右,90表示从上到下
    centerX:渐变中心的横坐标
    centerY:渐变中心的纵坐标
    centerColor:渐变中心的颜色
    endColor:渐变的结束色
    gradientRadius:渐变半径
    startColor:渐变的起始色
    centerColor:渐变的中间色
    type=["linear" | "radial" | "sweep"]渐变类型:线性渐变,辐射渐变,扫描渐变;默认为线性渐变
    useLevel:一般为false,当drawable为stateListDrawable使用时为true

     padding  表示的不是shape的空白,而是View的空白
     size  设置为shapeDrawable的宽高,但是如果当做背景时,仍然是根据view的大小进行拉伸;
     solid  表示纯色填充
     stroke

     Shape的描边:

     wide:描边宽度

     color:描边颜色

     dashWidth: 虚线描边宽度

     dashGap: 虚线的间隔

    3.LayerDrawable: 对应的是<layer-list>标签开头。是一种层级化的Drawable集合。<item>中可以自定义drawable,也可以引用定义好的drawable资源.

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@drawable/ic_launcher_background"
            android:id="@+id/xxx"
            android:top="integer"
            android:bottom="integer"
            android:left="integer"
            android:right="integer" />
    </layer-list>

    top,bottom,left, right分别表示相对于View的上下左右偏移量。

    下面的Item会覆盖上面的item。在自定义进度条的时候可以用到LayerDrawable。

    比如做一个简单的文本输入框的背景:

    <?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="#fff"/>
            </shape>
        </item>
    
        <item android:bottom="1dp"
            android:left="1dp"
            android:right="1dp">
            <shape android:shape="rectangle">
                <solid android:color="#fff" />
            </shape>
        </item>
    
    </layer-list>

    在布局文件中给EditTextView设置自定义的文本输入框背景,就有了如下效果:

     <EditText
            android:layout_width="300dp"
            android:layout_height="wrap_content"
            android:text="文本框"
            android:background="@drawable/text_imput_drawable"/>

    4.StateListDrawable: 对应<selector>标签,也是一种drawable集合,对应view的状态显示相应的drawable背景。

    View的常见状态
    android:state_pressed 表示按下状态,按下没有松开的状态
    android:state_focused 表示View已经获得焦点
    android:state_selected 表示用户选择了View
    android:state_checked 表示用户选中了View,如CheckBox
    android:state_enabled 表示View当前可用

    一般来说,会从上到下进行selector的匹配,在最后应该设置一个默认的状态,就是不附带任何信息的状态。当item都无法匹配的时候,会选择这个默认状态。

    5.LevelListDrawable: 对应<level-list>标签,同样表示一个Drawable集合,不过有等级,会根据不同的等级进行切换。minLevel和maxLevel,等级的范围为0~10000。当作为View的背景时,可以通过Drawable的setLevel方法来设置不同等级从而切换具体的Drawable。如果作为ImageView的前景Drawable,还可以通过ImageView的setImageLevel方法来切换Drawable。

    6.TransitionDrawable: 对应<transition>标签,用于实现两个Drawable之间的淡入淡出的效果。

    <?xml version="1.0" encoding="utf-8"?>
    <transition xmlns:android="http://schemas.android.com/apk/res/android">
        <item android:drawable="@[package:]drawable/drawable_resource"
            android:id="@[+][package:]id/resource_name"
            android:top="dimension"
            android:left="dimension"
            android:right="dimension"
            android:bottom="dimension" />
    </transition>

    例子:

    定义一个TransitionDrawable,如下图所示:

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

    接着将上面的TransitionDrawable设置为View的背景,也可以在ImageView中直接作为Drawable来使用。

    TextView view = findViewById(R.id.tv);
    TransitionDrawable drawable = (TransitionDrawable) view.getBackground();
    drawable.startTransition(1000);

    通过startTransition和reverseTransition方法来实现淡入淡出的效果以及它的逆过程。

    7.InsetDrawable: 对应<inset>标签,它可以将其它的Drawable内嵌到自己当中,并可以四周留出一定的间距。当一个View希望自己的背景比自己的实际区域小的时候,可以采用InsetDrawable来实现。

    <?xml version="1.0" encoding="utf-8"?>
    <inset xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_launcher_background"
        android:insetTop="dimension"
        android:insetLeft="dimension"
        android:insetRight="dimension"
        android:insetBottom="dimension" />

    一个简单的应用:

    <?xml version="1.0" encoding="utf-8"?>
    <inset xmlns:android="http://schemas.android.com/apk/res/android"
        android:insetTop="15dp"
        android:insetLeft="15dp"
        android:insetRight="15dp"
        android:insetBottom="15dp">
        <shape android:shape="rectangle">
            <solid android:color="#ff0000" />
        </shape>
    </inset>

    8.ScaleDrawable: 对应<scale>标签,它可以根据自己的等级level将指定的Drawable缩放到一定比例,默认等级为0,不显示,所以需要设置等级这一步,等级范围0~10000。

     eg.

    <?xml version="1.0" encoding="utf-8"?>
    <scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/ic_launcher_background" 
        android:scaleHeight="60%"
        android:scaleWidth="60%"
        android:scaleGravity="center">
    </scale>
    TextView view = findViewById(R.id.tv);
    ScaleDrawable drawable = (ScaleDrawable) view.getBackground();
    drawable.setLevel(1);

    9.ClipDrawable: 对应<clip>标签,它可以根据自己的等级level来裁剪另一个Drawable,裁剪方向可以根据android:clipOrientation和android:gravity这两个属性来共同控制。对于ClipDrawable来说,等级0表示完全裁剪,等级10000表示不裁剪。等级设置为8000表示裁剪了2000,裁剪20%。等级越大,表示裁剪的区域越小。

    10.自定义Drawable:Drawabe的使用很单一,一种是作为ImageView中的图片来显示,一种是作为View的背景。大多数情况都是以View的背景的形式出现。

    Drawable的原理比很简单,是通过调用draw方法来绘制背景。例如自定义Drawable的原形背景。

    /**
     * 圆形颜色背景绘制
     */
    public class CircleDrawable extends Drawable{
        private Paint mPaint;
    
        public CircleDrawable(int color){
            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint.setColor(color);
        }
    
        @Override
        public void draw(@NonNull Canvas canvas) {
            final Rect rect = getBounds();
            float cx = rect.exactCenterX();
            float cy = rect.exactCenterX();
            canvas.drawCircle(cx, cy, Math.min(cx, cy), mPaint);
        }
    
        @Override
        public void setAlpha(int alpha) {
            mPaint.setAlpha(alpha);
        }
    
        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
            mPaint.setColorFilter(colorFilter);
        }
    
        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT;
        }
    }
    /**
     * 圆角矩形图片背景
     */
    public class RoundImageDrawable extends Drawable {
        private Paint mPaint;
        private Bitmap mBitmap;
        private RectF mRectF;
    
        public RoundImageDrawable(Bitmap bitmap){
            this.mBitmap = bitmap;
            BitmapShader bitmapShader = new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mPaint.setShader(bitmapShader);
        }
    
        @Override
        public void setBounds(@NonNull Rect bounds) {
            super.setBounds(bounds);
            mRectF = new RectF(bounds.left, bounds.top, bounds.right, bounds.bottom);
        }
    
        @Override
        public void draw(@NonNull Canvas canvas) {
            canvas.drawRoundRect(mRectF, 20, 20, mPaint);
        }
    
        @Override
        public int getIntrinsicHeight() {
            return mBitmap.getHeight();
        }
    
        @Override
        public int getIntrinsicWidth() {
            return mBitmap.getWidth();
        }
    
        @Override
        public void setAlpha(int alpha) {
            mPaint.setAlpha(alpha);
        }
    
        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
            mPaint.setColorFilter(colorFilter);
        }
    
        @Override
        public int getOpacity() {
            return PixelFormat.TRANSLUCENT; //设置透明
        }
    }

     自定义Drawable中,draw, setAlpha,setColorFilter和getOpacity这几个方法必须实现,draw方法最主要,这个方法和View的draw方法类似。当drawable有固定大小的时候最好重写getIntrinsicWidth和getIntrinsicHeight方法,因为它会影响到View的wrap_content布局。如果是颜色填充,没有大小概念,此时返回-1。drawable实际大小可以通过getBounds方法得到,一般和View的大小一样。

  • 相关阅读:
    PAT Advanced 1067 Sort with Swap(0, i) (25分)
    PAT Advanced 1048 Find Coins (25分)
    PAT Advanced 1060 Are They Equal (25分)
    PAT Advanced 1088 Rational Arithmetic (20分)
    PAT Advanced 1032 Sharing (25分)
    Linux的at命令
    Sublime Text3使用指南
    IntelliJ IDEA创建第一个Groovy工程
    Sublime Text3 安装ftp插件
    Sublime Text3配置Groovy运行环境
  • 原文地址:https://www.cnblogs.com/denluoyia/p/8915469.html
Copyright © 2011-2022 走看看