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的大小一样。

  • 相关阅读:
    VUE中全局变量的定义和使用
    Pull Request 工作流——更高效的管理代码
    仓储repository概念
    Mysql存储过程历史表备份
    OpenStack一键安装
    VMware虚拟机设置Win10固定ip
    C#_NPOI_Excel各种设置
    pycharm修改镜像
    C#模拟POST上传文件帮助类(支持https、http)
    Windows安装RabbitMQ
  • 原文地址:https://www.cnblogs.com/denluoyia/p/8915469.html
Copyright © 2011-2022 走看看