Android基础篇-Drawable

在Android中,Drawable是一种用于绘制图形、颜色和位图的对象。它可以作为View的背景、前景或者作为ImageView的图片源。Drawable提供了一种可绘制的对象,可以通过XML或代码来创建、操作和显示,用于实现丰富多彩的界面效果。本文主要对项目中常用的drawable类型进行总结,并提供示例参考。

1.ShapeDrawable(形状Drawable)

ShapeDrawable可以绘制简单的几何图形,可以用来创建简单的形状作为背景,同时可以结合其他类型如LayearDrawable使用实现复杂的背景效果。

标签作用说明
shape定义图形形状,包括rectangle(矩形)、oval(椭圆)、line(直线)、ring(圆环)rectangle是默认值。若设置line必须设置stroke节点,否则报错
solid填充颜色,一种颜色solid和gradient是相反的,若同时设置,后加的标签会覆盖前面的
stroke设置边框的颜色,宽度等width:边框的宽度
color:边框颜色
dashGap:虚线间隔,像素类型
dashWidth:虚线宽度,像素类型
corners设置圆角如果四个角的圆角大小一样,只需设置radius;不一样可单独为四个角设置大小:
- topLeftRadius左上角
- topRightRadius右上角
- bottomLeftRadius左下角
- bottomRightRadius右下角

gradient设置渐变效果三种渐变类型:
- linear线性渐变,默认
- radial发射渐变,起始颜色是圆心颜色
- sweep滚动渐变,360度旋转渐变

2.StateListDrawable(状态列表Drawable)

StateListDrawable根据不同的状态可以切换不同的Drawable,比如按压,选中,获取焦点后显示不同状态图,常用来显示点击或选中item后显示不同的效果。
用于定义选择的状态,根标签是selector,定义item标签作为选择状态显示的drawable。

<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/pressed_bg" android:state_pressed="true"/>
    <item android:drawable="@drawable/focused_bg" android:state_focused="true"/>
    <item android:drawable="@drawable/normal_bg"/>
</selector>

常用属性:

  1. android:state_pressed:当 View 被按下时(按钮或者列表项点击)显示的 Drawable。
  2. android:state_focused:当 View 获得焦点时(常用于android tv中视图元素获取焦点)显示的 Drawable。
  3. android:state_selected:当 View 被选中时(元素点击选择)显示的 Drawable。
  4. android:state_checked:当 View 处于选中状态(如 CheckBox、RadioButton)时显示的 Drawable。
  5. android:state_enabled:当 View 可用时显示的 Drawable。
  6. android:state_activated:当 View 处于激活状态时(通常用于 ListView 或 RecyclerView 中)显示的 Drawable。
  7. android:state_window_focused:当 View 所在窗口获得焦点时显示的 Drawable。

通过shapeDrawable和StateListDrawable绘制本图如下示例的按钮形状背景,获取焦点和点击按压时变色:
image.png
先设置默认状态和有焦点后的drawale:
默认状态drawable:btn_default_bg.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    <!--定义浅白色填充-->
    <solid android:color="#c6d8e1" />
    <!--设置圆角-->
    <corners android:radius="43dp" />
</shape>

变色效果drawable:btn_sel_bg.xml

<shape xmlns:android="http://schemas.android.com/apk/res/android">
    
    <!--设置渐变效果-->
    <gradient
        android:angle="90"
        android:endColor="#4559c8"
        android:startColor="#6d6bd8" />

    <corners android:radius="43dp" />
</shape>

状态设置drawable:btn_selector.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!--按压显示变色效果-->
    <item android:drawable="@drawable/btn_sel_bg" android:state_pressed="true"/>
    <!--有焦点显示变色效果-->
    <item android:drawable="@drawable/btn_sel_bg" android:state_focused="true"/>
    <!--默认效果要放最后-->
    <item android:drawable="@drawable/btn_default_bg"/>
</selector>

主布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <LinearLayout
        android:id="@+id/ll_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="23dp"
        android:orientation="horizontal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent">

        <Button
            android:layout_width="150dp"
            android:layout_height="40dp"
            android:background="@drawable/btn_selector"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:text="Cancel"
            android:textAllCaps="false" />

        <Button
            android:layout_width="150dp"
            android:layout_height="40dp"
            android:layout_marginStart="11dp"
            android:background="@drawable/btn_selector"
            android:focusable="true"
            android:focusableInTouchMode="true"
            android:text="Connect"
            android:textAllCaps="false" />
    </LinearLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

3.LayerDrawable(层叠Drawable)

LayerDrawable可以将多个Drawable绘制在LayerDrawable的不同图层上,最后叠加图层形成一个丰富的图形效果。主要要与实现复杂的图形绘制,叠加背景图标等。列表元素从上到下,后面的drawable会叠加在上一个之上。
实现这个效果,有一个图标,图标外有一个蓝色圆形背景,有的时候设计师不给完整的图标背景,只给你单独的图标,那就需要自己组合成完整的效果。
image.png
设置圆形背景:wifi_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="#22ffff" />
</shape>

设置layerDrawable构成完整图形:wifi.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--底层背景-->
    <item android:drawable="@drawable/wifi_bg" />
    <!--上层图标-->
    <item
        android:bottom="5dp"
        android:drawable="@drawable/home_wifi"
        android:end="5dp"
        android:start="5dp"
        android:top="5dp" />
</layer-list>

这里设置的top/bottom/start/end用于设置该item距离上下左右的距离,一般在安卓开发用start/end代替left/right,因为涉及到多语言的时候考虑到有的语言比如阿拉伯语言是从右边往左的,也就是RTL,显示效果左右相反,而默认的情况采用的是LTR布局。

4.LevelListDrawable(级别列表Drawable)

levelListDrawable是一个显示不同级别图像的Drawable,每一个级别对应一个Drawable。需要注意的是,系统从上到下匹配,如果找到符合设置的级别,就不会往下查找,匹配以maxLevel优先。

  • maxLevel:最大级别
  • minLevel:最小级别

设置LevelListDrawable:level_bar.xml

<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <!--0-10显示的效果-->
    <item
        android:drawable="@drawable/btn_default_bg"
        android:maxLevel="10"
        android:minLevel="0" />
    <!--10-100显示的效果-->
    <item
        android:drawable="@drawable/btn_sel_bg"
        android:maxLevel="100"
        android:minLevel="10" />
</level-list>

主布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <ImageView
        android:id="@+id/progress"
        android:layout_width="200dp"
        android:layout_height="30dp"
        android:src="@drawable/level_bar"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
//activity中设置该视图级别
val progress = findViewById<ImageView>(R.id.progress)
progress.setImageLevel(10)

5.BitmapDrawable(位图Drawable)

BitmapDrawable可以在应用程序中显示位图图像,可通过xml或java创建和操作。主要特点是比起普通的图像资源文(png,jpg,gif)更加灵活,可以对图像进行平铺,缩放,裁剪等功能。

属性含义及作用
src指定源位图,可以是资源文件、Bitmap对象或文件路径
tileMode指定位图小于显示区域的平铺模式
- repeat:重复平铺
- mirror:镜像平铺
- clamp:大小不变,像素四周扩散
- disabled:关闭平铺
antialias抗锯齿,开启后图片更加平滑
dither抖动效果,开启后提高色彩过滤效果,让高质量图片在低质量的屏幕不失真
filter过滤,提高图片拉伸/压缩后的显示效果
gravity指定位图在显示区域的对齐方式
alpha透明度,取值在0.0-1.0

示例镜像平铺的drawable
资源的bitmapdrawable:music_bitmap_xml

<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
    android:alpha="0.6"
    android:antialias="true"
    android:dither="true"
    android:filter="true"
    android:gravity="bottom"
    android:src="@drawable/music"
    android:tileMode="mirror"/>

主布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <ImageView
        android:id="@+id/progress"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@drawable/music_bitmap" />
</androidx.constraintlayout.widget.ConstraintLayout>

6.InsertDrawable(内边距Drawable)

insertDrawable,顾名思义,就是可以插入drawable,把其他的drawable插入到自己的drawable中,类似于图层叠加,可以用LayerDrawable替代实现,使用率不高。
创建insertDrawabe:insert_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
    android:insetTop="40dp"
    android:insetBottom="60dp">
<!--    insertTop/insertBottom/insertLeft/insertRight指定drawable在显示区域的距离-->
    <!--插入一个shape-->
    <shape xmlns:android="http://schemas.android.com/apk/res/android">
        <solid android:color="#FFFF" />
        <corners android:radius="43dp" />
    </shape>
    <!--再插入一个图片资源-->
    <bitmap android:src="@drawable/music" />
</inset>

主布局文件

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <ImageView
        android:id="@+id/progress"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/grey"
        android:src="@drawable/insert_drawable"/>

</androidx.constraintlayout.widget.ConstraintLayout>

最后是这个效果
image.png

7.ClipDrawable(裁剪Drawable)

ClipDrawable可以将设置的Drawable的显示比例裁剪出另外一张Drawable,可以控制裁剪的方向,通过ClipDrawable的setLevel方法显示drawable的展示空间比例。

属性含义及作用
drawable设置需要裁剪的drawable资源
clipOrientation裁剪方向:horizontal水平,vertical垂直
gravity开始裁剪的地方

创建ClipDrawable:clip_drawable.xml

<?xml version="1.0" encoding="utf-8"?>
<clip xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/btn_sel_bg"
    android:clipOrientation="vertical"
    android:gravity="left">
</clip>

主布局

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/container"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingTop="?attr/actionBarSize">

    <ImageView
        android:id="@+id/progress"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:src="@drawable/clip_drawable"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"/>

</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity

package com.tosmart.launcher.myfile

import android.graphics.drawable.ClipDrawable
import android.os.Bundle
import android.os.Handler
import android.os.Message
import androidx.appcompat.app.AppCompatActivity
import com.tosmart.launcher.myfile.databinding.ActivityMainBinding


class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var mClipDrawable: ClipDrawable

    private var mCurrentProgress = 0

    companion object {
        const val PROGRESS_INCREMENT = 100
        const val MAX_PROGRESS = 10000
    }

    private val handler = object : Handler() {
        override fun handleMessage(msg: Message) {
            if (msg.what == 0) {
                updateProgress()
            }
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        val progress = binding.progress
        mClipDrawable = progress.drawable as ClipDrawable
        mClipDrawable.level = 0

        Thread {
            while (mCurrentProgress < MAX_PROGRESS) {
                try {
                    Thread.sleep(100)
                } catch (e: InterruptedException) {
                    e.printStackTrace()
                }
                mCurrentProgress += PROGRESS_INCREMENT
                handler.sendEmptyMessage(0)
            }
        }.start()

    }

    private fun updateProgress() {
        mClipDrawable.level = mCurrentProgress * 10000 / MAX_PROGRESS
    }
}
  • 12
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值