Android Drawable实践

前语

最近看源码、做事情有点累了,抽时刻看了看书,发现很多东西只是看过,却没有去实践,看了基本也就忘了,有些内容真好没那么复杂,就花了点零散时刻试试。

这篇文章是Android中Drawable的实践内容,从《Android开发艺术探究》的第六章下手的,这儿简略记录下。

BitmapDrawable

BitmapDrawable实际便是用来放图片的,下面是例子:

<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_launcher"
    android:antialias="true"
    android:dither="true"
    android:filter="true"
    android:gravity="fill_vertical|left"
    android:mipMap="false"
    android:tileMode="disabled"
     />
<!--
    antialias 抗锯齿
    dither 抖动效果,避免因像素适配问题导致的失真
    filter 过滤作用,避免拉伸或压缩时影响显现作用
    gravity 当图片尺度小于容器尺度时,对图片的定位作用
    mipMap 纹理映射,避免远处图片失真
    tileMode 平铺形式,和gravity抵触,有平铺repeat、镜像mirror、两头扩展
-->

用法也简略,给view的background设置上就行:

<TextView
    android:id="@+id/bitmapDrawable"
    android:text="BitmapDrawable"
    android:background="@drawable/ic_drawable_bitmap"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

显现作用:

Android Drawable实践

NinePatchDrawable

NinePatchDrawable和BitmapDrawable相似,需求留意的是Android Studio中只要png才干转成“.9”格局图片,NinePatchDrawable里边也不能访问mipmap的图片,需求复制到drawable里边去:

<nine-patch xmlns:android="http://schemas.android.com/apk/res/android"
    android:src="@drawable/ic_nine_patch"
    android:dither="true"
     />
<!--
    antialias 抗锯齿
    dither 颤动作用,避免因像素适配问题导致的失真
    filter 过滤作用,避免拉伸或压缩时影响显现作用
    gravity 当图片尺度小于容器尺度时,对图片的定位作用
    mipMap 纹理映射,避免远处图片失真
    tileMode 平铺形式,和gravity抵触,有平铺repeat、镜像mirror、两头扩展
-->

用法相似:

<TextView
    android:id="@+id/ninePatchDrawable"
    android:text="NinePatchDrawable"
    android:background="@drawable/ic_drawable_nine_patch"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

配置:

Android Drawable实践

显现作用:

Android Drawable实践

拉伸的很奇怪,不过没问题hh

ShapeDrawable

ShapeDrawable用的比较多吧,各种背景基本是这个,不多说:

<shape android:shape="rectangle"
    xmlns:android="http://schemas.android.com/apk/res/android" >
    <!--  线  -->
    <stroke
        android:width="3dp"
        android:color="@color/blue"
        android:dashGap="1dp"
        android:dashWidth="2dp"/>
    <!--  实心  -->
    <solid
        android:color="@color/gray"/>
    <!--  圆角  -->
    <corners
        android:topLeftRadius="5dp"
        android:topRightRadius="10dp"
        android:bottomRightRadius="15dp"
        android:bottomLeftRadius="20dp"/>
    <!--  突变(和solid抵触)  -->
    <gradient
        android:type="sweep"
        android:centerY="50%"
        android:centerX="25%"
        android:startColor="@color/red"
        android:centerColor="@color/yellow"
        android:endColor="@color/purple"
        />
    <padding
        android:top="0dp"
        android:left="30dp"
        android:right="30dp"
        android:bottom="20dp"/>
    <size
        android:width="300dp"
        android:height="100dp"
        />
</shape>

运用:

<TextView
    android:id="@+id/shapeDrawable"
    android:text="ShapeDrawable"
    android:background="@drawable/ic_drawable_shape"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

实际作用:

Android Drawable实践

shape的几种类型(rectangle、oval、ring)和gradient的几种类型留意下,突变中心用百分比,其他问题不大。

LayerDrawable

LayerDrawable便是放多层item,仿照阴影还挺好用的:

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--  仿照输入框  -->
    <!--  全灰  -->
    <item>
        <shape android:shape="rectangle">
            <solid android:color="@color/gray"/>
        </shape>
    </item>
    <!--  下面留一条灰线,其他全白  -->
    <item android:bottom="30dp" >
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>
    </item>
    <!--  左右留一点,嵌入底部灰线,中心全白  -->
    <item android:bottom="15dp" android:left="15dp" android:right="15dp">
        <shape android:shape="rectangle">
            <solid android:color="@color/white"/>
        </shape>
    </item>
</layer-list>

运用:

<TextView
    android:id="@+id/layerDrawable"
    android:text="LayerDrawable"
    android:background="@drawable/ic_drawable_layer"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

作用:

Android Drawable实践

StateListDrawable

StateListDrawable便是selector标签,用的也挺多吧:

<selector xmlns:android="http://schemas.android.com/apk/res/android"
    android:constantSize="false"
    android:dither="true"
    android:variablePadding="false">
    <!--  constantSize,状况改变,size坚持不变(最大item尺度)  -->
    <!--  constantSize,状况改变,padding跟从改变,否则用最大padding  -->
    <!--  各种状况,pressed、checked、focused、selected、enabled  -->
    <item android:state_pressed="true">
        <shape>
            <solid android:color="@color/gray"/>
        </shape>
    </item>
    <item android:state_focused="true">
        <shape>
            <stroke android:width="3dp" android:color="@color/blue"/>
        </shape>
    </item>
    <!--  一般状况放最终  -->
    <item>
        <shape>
            <stroke android:width="3dp" android:color="@color/gray"/>
        </shape>
    </item>
</selector>

运用,这儿要留意下TextView不处理点击事情:

<TextView
    android:id="@+id/stateListDrawable"
    android:text="StateListDrawable(press)"
    android:background="@drawable/ic_drawable_state_list"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    android:clickable="true"
    android:focusable="true"
    tools:ignore="HardcodedText"
    />

实际作用:

Android Drawable实践

LevelListDrawable

LevelListDrawable能够设置level,设置level后里边会改变:

<level-list xmlns:android="http://schemas.android.com/apk/res/android" >
    <item android:minLevel="0" android:maxLevel="0">
        <shape>
            <solid android:color="@color/gray"/>
        </shape>
    </item>
    <item android:minLevel="1" android:maxLevel="2">
        <shape>
            <solid android:color="@color/yellow"/>
        </shape>
    </item>
    <item android:minLevel="2" android:maxLevel="2">
        <shape>
            <solid android:color="@color/purple"/>
        </shape>
    </item>
    <item android:minLevel="3" android:maxLevel="3">
        <shape>
            <solid android:color="@color/red"/>
        </shape>
    </item>
</level-list>

运用:

<TextView
    android:id="@+id/levelListDrawable"
    android:text="LevelListDrawable: current level = 0"
    android:background="@drawable/ic_drawable_level_list"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

代码:

// 切换level
binding.levelListDrawable.setOnClickListener {
    var level = binding.levelListDrawable.background.level
    level = ++level % 5
    binding.levelListDrawable.background.level = level
    binding.levelListDrawable.text = "LevelListDrawable: current level = $level"
}

作用:

TransitionDrawable

TransitionDrawable有个突变作用:

<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:top="50dp"
        android:bottom="50dp"
        android:left="100dp"
        android:right="100dp"
        >
        <shape>
            <stroke android:width="3dp" android:color="@color/gray"/>
        </shape>
    </item>
    <item>
        <shape>
            <solid android:color="@color/gray"/>
        </shape>
    </item>
</transition>

运用:

<TextView
    android:id="@+id/transitionDrawable"
    android:text="TransitionDrawable(click)"
    android:background="@drawable/ic_drawable_transition"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

代码:

// 发动transition
binding.transitionDrawable.setOnClickListener {
    (binding.transitionDrawable.background as TransitionDrawable).startTransition(1500)
}

实际作用:

InsertDrawable

InsertDrawable便是能包含其他drawable,供给一个padding作用:

<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:insetTop="20dp"
    android:insetBottom="40dp"
    android:insetLeft="10dp"
    android:insetRight="30dp">
    <shape>
        <stroke android:width="3dp" android:color="@color/gray"/>
    </shape>
</inset>

运用:

<TextView
    android:id="@+id/insertDrawable"
    android:text="InsertDrawable"
    android:background="@drawable/ic_drawable_insert"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

实际作用:

Android Drawable实践

ScaleDrawable

ScaleDrawable便是会依据level缩放的drawable:

<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:scaleGravity="center"
    android:scaleWidth="75%"
    android:scaleHeight="75%"
    >
    <shape>
        <solid android:color="@color/gray"/>
    </shape>
</scale>

运用:

<TextView
    android:id="@+id/scaleDrawable"
    android:text="ScaleDrawable: current level = 0"
    android:background="@drawable/ic_drawable_scale"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

代码:

// 设置缩放
binding.scaleDrawable.setOnClickListener {
    var level = binding.scaleDrawable.background.level
    level = (level + 1000) % 10000
    binding.scaleDrawable.background.level = level
    binding.scaleDrawable.text = "ScaleDrawable: current level = $level"
}

实际作用:

ClipDrawable

ClipDrawable会依据level裁切:

<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:clipOrientation="vertical"
    android:gravity="center"
    android:drawable="@drawable/ic_launcher"
    >
</clip>

运用:

<TextView
    android:id="@+id/clipDrawable"
    android:text="ClipDrawable: current level = 0"
    android:background="@drawable/ic_drawable_clip"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

代码:

// 设置裁切
binding.clipDrawable.setOnClickListener {
    var level = binding.clipDrawable.background.level
    level = (level + 1000) % 10000
    binding.clipDrawable.background.level = level
    binding.clipDrawable.text = "ClipDrawable: current level = $level"
}

实际作用:

CustomDrawable

这儿我自己写了一个Drawable,将就看下吧:


import android.graphics.Canvas
import android.graphics.Color
import android.graphics.ColorFilter
import android.graphics.Paint
import android.graphics.PixelFormat
import android.graphics.drawable.Drawable
class CustomStarDrawable: Drawable() {
    private val mPaint: Paint = Paint()
    init {
        mPaint.strokeWidth = 5f
        mPaint.flags = Paint.ANTI_ALIAS_FLAG
        mPaint.style = Paint.Style.FILL
        mPaint.color = Color.GRAY
    }
    override fun draw(canvas: Canvas) {
        // 绘制圆圈
        val num = level / 2000
        val radius = (bounds.bottom - bounds.top) / 4f
        val distance = (bounds.right - bounds.left) / 5f
        when(num) {
            1 -> mPaint.color = Color.RED
            2 -> mPaint.color = Color.YELLOW
            3 -> mPaint.color = Color.BLUE
            4 -> mPaint.color = Color.GREEN
            else -> mPaint.color = Color.GRAY
        }
        // canvas.drawRect(bounds, mPaint)
        for (i in 0 until  num) {
            canvas.drawCircle(distance * i + radius,  2 * radius, radius, mPaint)
        }
    }
    override fun setAlpha(alpha: Int) {
        mPaint.alpha = alpha
        invalidateSelf()
    }
    override fun setColorFilter(colorFilter: ColorFilter?) {
        mPaint.colorFilter = colorFilter
        invalidateSelf()
    }
    @Deprecated("Deprecated in Java",
        ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat")
    )
    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }
    // 默许巨细
    override fun getIntrinsicWidth(): Int {
        return 500
    }
    override fun getIntrinsicHeight(): Int {
        return 100
    }
}

运用:

<TextView
    android:id="@+id/customDrawable"
    android:text="CustomDrawable: current level = 0"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

代码:

// 设置自定义drawable
binding.customDrawable.background = CustomStarDrawable()
binding.customDrawable.setOnClickListener {
    var level = binding.customDrawable.background.level
    level = (level + 2000) % 10000
    binding.customDrawable.background.level = level
    binding.customDrawable.text = "CustomDrawable: current level = $level"
}

实际作用:

RippleDrawable

RippleDrawable水波纹作用,很多点击会用到(留意V21):

<ripple xmlns:android="http://schemas.android.com/apk/res/android"
    android:color="@color/blue"
    android:radius="100dp"
     />
<!-- color,有必要,涟漪的色彩 -->
<!-- radius,涟漪最大的半径 -->

运用:

<TextView
    android:id="@+id/rippleDrawable"
    android:text="RippleDrawable(click)"
    android:background="@drawable/ic_drawable_ripple"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    android:clickable="true"
    android:focusable="true"
    tools:ignore="HardcodedText"
    />

作用:

RotateDrawable

RotateDrawable旋转的,没什么好说的,也和level有关:

<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_launcher"
    android:pivotX="50%"
    android:pivotY="50%"
    android:fromDegrees="0"
    android:toDegrees="180"
    android:visible="true"
    />

运用:

<TextView
    android:id="@+id/rotateDrawable"
    android:text="RotateDrawable: current level = 0"
    android:background="@drawable/ic_drawable_rotate"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    tools:ignore="HardcodedText"
    />

代码:

// 设置旋转drawable
binding.rotateDrawable.setOnClickListener {
    var level = binding.rotateDrawable.background.level
    level = (level + 2000) % 10000
    binding.rotateDrawable.background.level = level
    binding.rotateDrawable.text = "RotateDrawable: current level = $level"
}

实际作用:

AnimateStateListDrawable

AnimateStateListDrawable便是selector加动画,相似的还有好多个,能够加帧动画或者vector动画,下面我就简略试了下(留意v21):

<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 开启状况 -->
    <item
        android:id="@+id/state_on"
        android:state_pressed="true">
        <shape>
            <solid android:color="@color/blue"/>
        </shape>
    </item>
    <!-- 封闭状况 -->
    <item
        android:id="@+id/state_off"
        android:state_pressed="false">
        <shape>
            <stroke android:width="3dp" android:color="@color/gray"/>
        </shape>
    </item>
    <!-- 封闭切换到开启的帧动画 -->
    <transition
        android:fromId="@id/state_off"
        android:toId="@id/state_on">
        <animation-list>
            <item android:duration="200">
                <shape><solid android:color="#000000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#220000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#440000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#660000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#880000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#AA0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#CC0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#EE0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#FF0000FF"/> </shape>
            </item>
        </animation-list>
    </transition>
    <!-- 开启切换到封闭的动画 -->
    <transition
        android:fromId="@id/state_on"
        android:toId="@id/state_off">
        <animation-list>
            <item android:duration="200">
                <shape><solid android:color="#FF0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#EE0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#CC0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#AA0000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#880000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#660000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#440000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#220000FF"/> </shape>
            </item>
            <item android:duration="200">
                <shape><solid android:color="#000000FF"/> </shape>
            </item>
        </animation-list>
    </transition>
</animated-selector>

运用:

<TextView
    android:id="@+id/animateStateListDrawable"
    android:text="AnimateStateListDrawable(press)"
    android:background="@drawable/ic_drawable_animate_state_list"
    android:layout_width="match_parent"
    android:layout_height="80dp"
    android:layout_margin="5dp"
    android:clickable="true"
    android:focusable="true"
    tools:ignore="HardcodedText"
    />

实际作用:

其他

好像还有其他几个,adaptive-icon、animated-rotate、animated-vector、animation-list,animated的都相似,后边有时刻搞下动画,试试vector动画,adaptive-icon好像是和app图标相关的,用到再看。

小结

这儿花了点时刻,试了下各种drawable的运用作用,有的有状况,有的和level相关,有的合作动画,还挺有意思,也自定义了一个依据level增加圆圈的drawable,又学习了!

8点11,下班!