美文网首页
Android Drawable类型集合

Android Drawable类型集合

作者: 遇见编程 | 来源:发表于2024-08-25 12:10 被阅读0次

    Drawable

    1.BitmapDrawable

    位图图像。Android支持三种格式的位图文件:.png(首选)、.jpg(可接受)、.gif(不建议)。我们可以直接使用文件名作为资源 ID 来引用位图文件,也可以在 XML 文件中创建别名资源 ID,这就叫做 XML位图。

    <1> 使用xml位图

    <?xml version="1.0" encoding="utf-8"?>
    <bitmap xmlns:android="http://schemas.android.com/apk/res/android"
        android:antialias="true"
        android:gravity="fill"
        android:src="@drawable/ic_launcher_background"
        android:tileMode="disabled"/>
    

    关于<bitmap> 属性:

    1. android:src:引用可绘制对象资源,必备。

    2. android:tileMode:定义平铺模式。当平铺模式启用时,位图会重复,且注意:一旦平铺模式启用, android:gravity 属性就将会被忽略。定义平铺属性的值必须是以下值之一:

      • disabled:不平铺位图,默认值。
      • clamp:当着色器绘制范围超出其原边界时复制边缘颜色。
      • repeat:水平和垂直重复着色器的图像。
      • mirror:水平和垂直重复着色器的图像,交替镜像图像以使相邻图像始终相接。

      注意:在平铺模式启用时android:gravity属性将被忽略。

    3. android:gravity:定义位图的重力属性,当位图小于容器时,可绘制对象在其容器中放置的位置。

      • top:将对象放在其容器顶部,不改变其大小。

      • bott****om:将对象放在其容器底部,不改变其大小。

      • left:将对象放在其容器左边缘,不改变其大小。

      • right:将对象放在其容器右边缘,不改变其大小。

      • center_vertical:将对象放在其容器的垂直中心,不改变其大小。

      • fill_vertical:按需要扩展对象的垂直大小,使其完全适应其容器。

      • center_horizontal:将对象放在其容器的水平中心,不改变其大小。

      • fill_horizontal:按需要扩展对象的水平大小,使其完全适应其容器。

      • center:将对象放在其容器的水平和垂直轴中心,不改变其大小。

      • fill:按需要扩展对象的垂直大小,使其完全适应其容器。这是默认值。

      • clip_vertical:可设置为让子元素的上边缘和/或下边缘裁剪至其容器边界的附加选项。裁剪基于垂直重力:顶部重力裁剪上边缘,底部重力裁剪下边缘,任一重力不会同时裁剪两边。

      • clip_horizontal:可设置为让子元素的左边和/或右边裁剪至其容器边界的附加选项。裁剪基于水平重力:左边重力裁剪右边缘,右边重力裁剪左边缘,任一重力不会同时裁剪两边。

    <2>通过代码来实现,即BitmapDrawable

     binding.bitmapDrawableInclude.apply {
        tv1.setText(R.string.bitmap_drawable)
        tv1.background = ContextCompat.getDrawable(requireContext(), R.drawable.bitmap_drawable)
        tv2.setText(R.string.bitmap_drawable)
    
        val bitmap = BitmapFactory.decodeResource(resources, R.drawable.nick)
        val bitmapShape = BitmapDrawable(resources, bitmap)
        tv2.background = bitmapShape
    }
    

    2.LayerDrawable

    图层列表(LayerDrawable):是可绘制对象列表组成的可绘制对象。列表中的每个可绘制对象均按照列表顺序绘制,列表中的最后一个可绘制对象绘于顶部。

    每个可绘制对象由单一<layer-list> 元素内的<item>元素表示。

    <1>XML

    <?xml version="1.0" encoding="utf-8"?>
    <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item>
            <bitmap android:src="@drawable/nick" />
        </item>
        <item
            android:bottom="150dp"
            android:left="0dp"
            android:right="250dp"
            android:top="0dp">
            <shape android:shape="oval">
                <solid android:color="@color/royal_blue" />
            </shape>
        </item>
        <item
            android:bottom="75dp"
            android:left="125dp"
            android:right="125dp"
            android:top="75dp">
            <shape android:shape="oval">
                <solid android:color="@color/indian_red" />
            </shape>
        </item>
        <item
            android:bottom="0dp"
            android:left="250dp"
            android:right="0dp"
            android:top="150dp">
            <shape android:shape="oval">
                <solid android:color="@color/yellow" />
            </shape>
        </item>
    
    </layer-list>
    
    1. <layer-list>:必备的根元素。包含一个或多个 <item> 元素。

    2. <item>:是 <layer-list> 元素的子项,其属性支持定义在图层中所处的位置。

    3. <item> 标签属性:

      android:top:整型。顶部偏移(像素)。

      android:right:整型。右边偏移(像素)。

      android:bottom:整型。底部偏移(像素)。

      android:left:整型。左边偏移(像素)。

    <2>代码实现

     binding.layerDrawableInclude.apply {
        tv1.setText(R.string.layer_drawable)
        tv1.background = ContextCompat.getDrawable(requireContext(), R.drawable.layer_drawable)
        tv2.setText(R.string.layer_drawable)
    
        val itemLeft = GradientDrawable().apply {
            setColor(ContextCompat.getColor(requireContext(), R.color.royal_blue))
            setSize(50.px, 50.px)
            shape = GradientDrawable.OVAL
        }
        val itemCenter = GradientDrawable().apply {
            setColor(ContextCompat.getColor(requireContext(), R.color.indian_red))
            shape = GradientDrawable.OVAL
        }
        val itemRight = GradientDrawable().apply {
            setColor(ContextCompat.getColor(requireContext(), R.color.yellow))
            shape = GradientDrawable.OVAL
        }
        val arr = arrayOf(
            ContextCompat.getDrawable(requireContext(), R.drawable.nick)!!,
            itemLeft,
            itemCenter,
            itemRight
        )
        val ld = LayerDrawable(arr).apply {
            setLayerInset(1, 0.px, 0.px, 250.px, 150.px)
            setLayerInset(2, 125.px, 75.px, 125.px, 75.px)
            setLayerInset(3, 250.px, 150.px, 0.px, 0.px)
        }
        tv2.background = ld
    }
    

    3.StateListDrawable

    状态列表(StateListDrawable):会根据对象状态,使用多个不同的图像来表示同一个图形。

    <1> XML

    <?xml version="1.0" encoding="utf-8"?>
    <selector xmlns:android="http://schemas.android.com/apk/res/android" android:constantSize="false">
        <item android:drawable="@drawable/nick" android:state_pressed="false" />
        <item android:drawable="@drawable/basketball" android:state_pressed="true" />
    </selector>
    

    其中的属性:

    1. <selector>:必备的根元素。包含一个或多个 <item> 元素。

      2.<item>:定义在某些状态期间使用的可绘制对象,必须是 <selector> 元素的子项。其属性:

    • android:drawable:引用可绘制对象资源,必备。

    • android:state_pressed:布尔值。是否按下对象(例如触摸/点按某按钮)。

    • android:state_checked:布尔值。是否选中对象。

    • android:state_enabled:布尔值。是否能够接收触摸或点击事件。

    <2> 代码

     binding.stateListDrawableTv.apply {
        setOnClickListener {
            Log.e(TAG, "stateListDrawableTv: isPressed = $isPressed")
        }
    }
    
    val sld = StateListDrawable().apply {
        addState(
            intArrayOf(android.R.attr.state_pressed),
            ContextCompat.getDrawable(requireContext(), R.drawable.basketball)
        )
        addState(StateSet.WILD_CARD, ContextCompat.getDrawable(requireContext(), R.drawable.nick))
    }
    binding.stateListDrawableTv2.apply {
        background = sld
        setOnClickListener {
            Log.e(TAG, "stateListDrawableTv2: isPressed = $isPressed")
        }
    }
    

    4.LevelListDrawable

    级别列表(LevelListDrawable):管理可绘制对象列表,每个可绘制对象都有设置Level等级限制,当使用setLevel时,会加载级别列表中android:maxLevel值大于或等于传递至方法的值的可绘制对象资源。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <level-list xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item
            android:drawable="@drawable/nick"
            android:maxLevel="1" />
    
        <item
            android:drawable="@drawable/tom1"
            android:maxLevel="2" />
    
        <item
            android:drawable="@drawable/tom2"
            android:maxLevel="3" />
    
        <item
            android:drawable="@drawable/tom3"
            android:maxLevel="4" />
    
        <item
            android:drawable="@drawable/tom4"
            android:maxLevel="5" />
    
        <item
            android:drawable="@drawable/tom5"
            android:maxLevel="6" />
    
        <item
            android:drawable="@drawable/tom6"
            android:maxLevel="7" />
    
        <item
            android:drawable="@drawable/tom7"
            android:maxLevel="8" />
    
        <item
            android:drawable="@drawable/tom8"
            android:maxLevel="9" />
    
        <item
            android:drawable="@drawable/tom9"
            android:maxLevel="10" />
    
    </level-list>
    
    1. <level-list>:必备的根元素。包含一个或多个 <item> 元素。

    2. <item>:在特定级别下使用的可绘制对象。

      android:drawable:必备。引用可绘制对象资源。

      android:maxLevel:整型。表示该Item允许的最高级别。

      android:minLevel:整型。表示该Item允许的最低级别。

    <2>代码

    class LevelListDrawableFragment : BaseFragment<FragmentLevelListDrawableBinding>() {
    
        private val lld by lazy {
            LevelListDrawable().apply {
                addLevel(0, 1, getDrawable(R.drawable.nick))
                addLevel(0, 2, getDrawable(R.drawable.tom1))
                addLevel(0, 3, getDrawable(R.drawable.tom2))
                addLevel(0, 4, getDrawable(R.drawable.tom3))
                addLevel(0, 5, getDrawable(R.drawable.tom4))
                addLevel(0, 6, getDrawable(R.drawable.tom5))
                addLevel(0, 7, getDrawable(R.drawable.tom6))
                addLevel(0, 8, getDrawable(R.drawable.tom7))
                addLevel(0, 9, getDrawable(R.drawable.tom8))
                addLevel(0, 10, getDrawable(R.drawable.tom9))
            }
        }
    
        private fun getDrawable(id: Int): Drawable {
            return (ContextCompat.getDrawable(requireContext(), id)
                ?: ContextCompat.getDrawable(requireContext(), R.drawable.nick)) as Drawable
        }
    
        private val levelListDrawable by lazy {
            ContextCompat.getDrawable(requireContext(), R.drawable.level_list_drawable)
        }
    
        override fun initView() {
    
            binding.levelListDrawableInclude.apply {
                tv1.setText(R.string.level_list_drawable)
                tv1.background = levelListDrawable
                tv2.setText(R.string.level_list_drawable)
    
                tv2.background = lld
            }
    
            binding.seekBar.apply {
                //init level
                levelListDrawable?.level = progress
                lld.level = progress
                //add listener
                setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                    override fun onProgressChanged(
                        seekBar: SeekBar?,
                        progress: Int,
                        fromUser: Boolean
                    ) {
                        levelListDrawable?.level = progress
                        lld.level = progress
                        Log.e(TAG, "onProgressChanged: progreess = $progress")
                    }
    
                    override fun onStartTrackingTouch(seekBar: SeekBar?) {
    
                    }
    
                    override fun onStopTrackingTouch(seekBar: SeekBar?) {
    
                    }
                })
            }
    
        }
    }
    

    5.TransitionDrawable

    转换可绘制对象(TransitionDrawable):可在两种可绘制对象资源之间交错淡出。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <transition xmlns:android="http://schemas.android.com/apk/res/android">
    
        <item
            android:id="@+id/ship"
            android:drawable="@drawable/nick" />
    
        <item
            android:id="@+id/plane"
            android:drawable="@drawable/basketball" />
    
    </transition>
    

    其中的属性:

    1. <transition>:必备的根元素。包含一个或多个 <item>元素。

    2. <item>:转换部分的可绘制对象。

      android:drawable:必备。引用可绘制对象资源。

      android:top、android:bottom、android:left、android:right:整型。偏移量(像素)。

    注意:不能超过两个Item,调用 startTransition向前转换,调用 reverseTransition 向后转换。

    <2>代码

    class TransitionDrawableFragment : BaseFragment<FragmentTransitionDrawableBinding>() {
    
        private var isShow = false
        private lateinit var bgDrawable: TransitionDrawable
        private lateinit var manualDrawable: TransitionDrawable
    
        override fun initView() {
            binding.transitionDrawableInclude.apply {
                tv1.setText(R.string.transition_drawable)
                tv1.background =
                    ContextCompat.getDrawable(requireContext(), R.drawable.transition_drawable)
                tv2.setText(R.string.transition_drawable)
    
                bgDrawable = tv1.background as TransitionDrawable
                val drawableArray = arrayOf(
                    ContextCompat.getDrawable(requireContext(), R.drawable.nick),
                    ContextCompat.getDrawable(requireContext(), R.drawable.basketball)
                )
                manualDrawable = TransitionDrawable(drawableArray)
                tv2.background = manualDrawable
            }
        }
    
        private fun setTransition() {
            if (isShow) {
                bgDrawable.reverseTransition(1500)
                manualDrawable.reverseTransition(3000)
            } else {
                bgDrawable.startTransition(1500)
                manualDrawable.startTransition(3000)
            }
        }
    
        override fun onResume() {
            super.onResume()
            setTransition()
            isShow = !isShow
        }
    }
    

    6.InsetDrawable

    插入可绘制对象(InsetDrawable):以指定距离插入其他可绘制对象,当视图需要小于视图实际边界的背景时,此类可绘制对象很有用。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <inset xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/nick"
        android:insetTop="50dp"
        android:insetLeft="150dp">
    
    </inset>
    

    <inset>:必备。根元素。

    android:drawable:必备。引用可绘制对象资源。

    android:insetTop、android:insetBottom、android:insetLeft、android:insetRight:尺寸。插入的,表示为尺寸

    <2>代码

    binding.insetDrawableInclude.apply {
        tv1.setText(R.string.inset_drawable)
        tv1.background = ContextCompat.getDrawable(requireContext(), R.drawable.inset_drawable)
        tv2.setText(R.string.inset_drawable)
    
        val insetDrawable = InsetDrawable(
            ContextCompat.getDrawable(requireContext(), R.drawable.nick),
            0f, 0f, 0.5f, 0.25f
        )
        tv2.background = insetDrawable
    }
    

    7.ClipDrawable

    裁剪可绘制对象(ClipDrawable):根据level等级对可绘制对象进行裁剪,可以根据level与gravity来控制子可绘制对象的宽度与高度。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <clip xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/nick"
        android:clipOrientation="horizontal"
        android:gravity="center">
    
    </clip>
    
    1. <clip>:必备。根元素。

    2. android:drawable:必备。引用可绘制对象资源。

    3. android:clipOrientation:裁剪方向。

      horizontal:水平裁剪。

      vertical:垂直裁剪。

    4. android:gravity:重力属性。

    最后通过设置level等级来实现裁剪,level 默认级别为 0,即完全裁剪,使图像不可见。当级别为 10,000 时,图像不会裁剪,而是完全可见。

    <2>代码

    class ClipDrawableFragment : BaseFragment<FragmentClipDrawableBinding>() {
    
        private val clipDrawable by lazy {
            ContextCompat.getDrawable(requireContext(), R.drawable.clip_drawable)
        }
        private val manualClipDr1awable by lazy {
            ClipDrawable(
                ContextCompat.getDrawable(requireContext(), R.drawable.nick),
                Gravity.CENTER,
                ClipDrawable.VERTICAL
            )
        }
    
        override fun initView() {
            binding.clipDrawableInclude.apply {
                tv1.setText(R.string.clip_drawable)
                tv1.background = clipDrawable
                tv2.setText(R.string.clip_drawable)
                tv2.background = manualClipDrawable
            }
    
            //level 默认级别为 0,即完全裁剪,使图像不可见。当级别为 10,000 时,图像不会裁剪,而是完全可见。
            binding.seekBar.apply {
                //init level
                clipDrawable?.level = progress
                manualClipDrawable.level = progress
                //add listener
                setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                    override fun onProgressChanged(
                        seekBar: SeekBar?,
                        progress: Int,
                        fromUser: Boolean
                    ) {
                        clipDrawable?.level = progress
                        manualClipDrawable.level = progress
                    }
    
                    override fun onStartTrackingTouch(seekBar: SeekBar?) {
    
                    }
    
                    override fun onStopTrackingTouch(seekBar: SeekBar?) {
    
                    }
    
                })
            }
        }
    
    }
    

    8.ScaleDrawable

    缩放可绘制对象(ScaleDrawable):根据level等级来更改其可绘制对象大小。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <scale xmlns:android="http://schemas.android.com/apk/res/android"
        android:drawable="@drawable/nick"
        android:scaleWidth="100%"
        android:scaleHeight="100%"
        android:scaleGravity="center">
    
    </scale>
    

    其属性:

    • <scale>:必备。根元素。

      • android:drawable:必备。引用可绘制对象资源。

      • android:scaleGravity:指定缩放后的重力位置。

      • android:scaleHeight:百分比。缩放高度,表示为可绘制对象边界的百分比。值的格式为 XX%。例如:100%、12.5% 等。

      • android:scaleWidth:百分比。缩放宽度,表示为可绘制对象边界的百分比。值的格式为 XX%。例如:100%、12.5% 等。

    <2>代码

     binding.scaleDrawableInclude.apply {
        tv1.setText(R.string.scale_drawable)
        tv1.background = ContextCompat.getDrawable(requireContext(), R.drawable.scale_drawable)
        tv2.setText(R.string.scale_drawable)
    
        val scaleDrawable = ScaleDrawable(
            ContextCompat.getDrawable(requireContext(), R.drawable.nick),
            Gravity.CENTER,
            1f,
            1f
        )
        tv2.background = scaleDrawable
    
        binding.seekBar.apply {
            //init level
            tv1.background.level = progress
            scaleDrawable.level = progress
            //add listener
            setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
                override fun onProgressChanged(
                    seekBar: SeekBar?,
                    progress: Int,
                    fromUser: Boolean
                ) {
                    tv1.background.level = progress
                    scaleDrawable.level = progress
                    Log.e(TAG, "onProgressChanged: progreess = $progress")
                }
    
                override fun onStartTrackingTouch(seekBar: SeekBar?) {
    
                }
    
                override fun onStopTrackingTouch(seekBar: SeekBar?) {
    
                }
    
            })
        }
    }
    

    9.ShapeDrawable

    形状可绘制对象(ShapeDrawable):通过XML来定义各种形状的可绘制对象。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
    
        <corners
            android:topLeftRadius="20dp"
            android:topRightRadius="20dp" />
    
        <solid android:color="@color/royal_blue" />
    
        <stroke
            android:width="3dp"
            android:color="@color/purple_200"
            android:dashWidth="10dp"
            android:dashGap="5dp" />
    
    </shape>
    

    其属性:

    1. <shape>:必备。根元素。

      • android:shape:定义形状的类型。

        • rectangle:默认形状,填充包含视图的矩形。

        • oval:适应包含视图尺寸的椭圆形状。

        • line:跨越包含视图宽度的水平线。此形状需要 元素定义线宽。

        • ring:环形。

      • android:innerRadius:尺寸。环内部(中间的孔)的半径。

      • android:thickness:尺寸。环的厚度。

    1. <corners>:圆角,仅当形状为矩形时适用。

      • android:radius:尺寸。所有角的半径。如果想要设置单独某个角,可以使用 android:topLeftRadius、android:topRightRadius、android:bottomLeftRadius、android:bottomRightRadius。
    1. <padding>:设置内边距。

      • android:left:尺寸。设置左内边距。同样还有 android:right、android:top、android:bottom供选择。
    1. <size>:形状的大小。

      • android:height:尺寸。形状的高度。

      • android:width:尺寸。形状的宽度。

    1. <solid>:填充形状的纯色。

      • android:color:颜色。
    1. <stroke>:形状的笔画

      • android:width:尺寸。线宽。

      • android:color:颜色。线的颜色。

      • android:dashGap:尺寸。短划线的间距。虚线效果。

      • android:dashWidth:尺寸。每个短划线的大小。虚线效果。

    <2>代码

    class ShapeDrawableFragment : BaseFragment<FragmentShapeDrawableBinding>() {
    
        override fun initView() {
            binding.shapeDrawableInclude.apply {
                tv1.setText(R.string.shape_drawable)
                tv1.background = ContextCompat.getDrawable(requireContext(), R.drawable.shape_drawable)
                tv2.setText(R.string.shape_drawable)
    
                val roundRectShape =
                    RoundRectShape(
                        floatArrayOf(20f.px, 20f.px, 20f.px, 20f.px, 0f, 0f, 0f, 0f),
                        null,
                        null
                    )
                tv2.background = MyShapeDrawable(roundRectShape)
            }
        }
    
        /**
         * TODO: //使用 GradientDrawable 效果更好
         */
        class MyShapeDrawable(shape: Shape) : ShapeDrawable(shape) {
            private val fillPaint = Paint().apply {
                style = Paint.Style.FILL
                color = Color.parseColor("#4169E1")
            }
            private val strokePaint = Paint().apply {
                style = Paint.Style.STROKE
                color = Color.parseColor("#FFBB86FC")
    //            strokeCap = Paint.Cap.ROUND
    //            strokeJoin = Paint.Join.ROUND
                strokeMiter = 10f
                strokeWidth = 5f.px
                pathEffect = DashPathEffect(floatArrayOf(10f.px, 5f.px), 0f)
            }
    
            override fun onDraw(shape: Shape?, canvas: Canvas?, paint: Paint?) {
                super.onDraw(shape, canvas, paint)
                shape?.draw(canvas, fillPaint)
                shape?.draw(canvas, strokePaint)
            }
        }
    
    }
    

    10.GradientDrawable

    渐变可绘制对象(GradientDrawable):如其名,实现渐变颜色效果。其实也是属于ShapeDrawable。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="oval">
    
        <gradient
            android:endColor="#BBFFFF"
            android:gradientRadius="50%p"
            android:startColor="#00F5FF"
            android:type="radial" />
    
    </shape>
    
    1. <shape>:必备。根元素。

    2. gradient:表示渐变的颜色。

      • android:angle:整型。表示渐变的角度。0 表示为从左到右,90 表示为从上到上。注意:必须是 45 的倍数。默认值为 0。

      • android:centerX:浮点型。表示渐变中心相对 X 轴位置 (0 - 1.0)。 android:centerY同理。

      • android:startColor:颜色。起始颜色。 android:endColor、android:centerColor分别表示结束颜色与中间颜色。

      • android:gradientRadius:浮点型。渐变的半径。仅在 android:type="radial" 时适用。

      • android:type:渐变的类型。

      • linear:线性渐变。默认为该类型。

      • radial:径向渐变,也就是雷达式渐变,起始颜色为中心颜色。

      • sweep:流线型渐变。

    <2>代码

     binding.gradientDrawableInclude.apply {
        tv1.setText(R.string.gradient_drawable)
        tv1.background =
            ContextCompat.getDrawable(requireContext(), R.drawable.gradient_drawable)
        tv2.setText(R.string.gradient_drawable)
    
        val gradientDrawable = GradientDrawable().apply {
            shape = GradientDrawable.OVAL
            gradientType = GradientDrawable.RADIAL_GRADIENT
            colors = intArrayOf(Color.parseColor("#00F5FF"), Color.parseColor("#BBFFFF"))
            gradientRadius = 100f.px
        }
        tv2.background = gradientDrawable
    }
    

    11.AnimationDrawable

    动画可绘制对象(AnimationDrawable):用于创建逐帧动画的可绘制对象。

    <1>xml

    <?xml version="1.0" encoding="utf-8"?>
    <animation-list xmlns:android="http://schemas.android.com/apk/res/android">
        <item
            android:drawable="@drawable/nick"
            android:duration="1000" />
        <item
            android:drawable="@drawable/basketball"
            android:duration="1000" />
    
    </animation-list>
    
    1. <animation-list>:必备。根元素。

    2. <item>:每一帧的可绘制对象。

      • android:drawable:必备。引用可绘制对象资源。

      • android:duration:该帧的持续时间,单位为毫秒。

      • android:oneshot:布尔值。代表是否只单次展示该动画,默认为false。

    <2>代码

    class AnimationDrawableFragment : BaseFragment<FragmentAnimationDrawableBinding>() {
        private val animationDrawable by lazy {
            ContextCompat.getDrawable(
                requireContext(),
                R.drawable.animation_drawable
            ) as AnimationDrawable
        }
    
        override fun initView() {
            binding.animationDrawableInclude.apply {
                tv1.setText(R.string.animation_drawable)
                tv1.background = animationDrawable
                tv2.setText(R.string.animation_drawable)
    
                animationDrawable.start()
    
                val animationDrawable = AnimationDrawable().apply {
                    ContextCompat.getDrawable(requireContext(), R.drawable.nick)
                        ?.let { addFrame(it, 1000) }
                    ContextCompat.getDrawable(requireContext(), R.drawable.basketball)
                        ?.let { addFrame(it, 1000) }
                }
                tv2.background = animationDrawable
                animationDrawable.start()
            }
        }
    
    }
    

    2.多动画联动

    class AnimatedVectorDrawableFragment : BaseFragment<FragmentAnimatedVectorDrawableBinding>() {
        override fun initView() {
            (binding.vectorDrawableIv.drawable as Animatable).start()
    
    
            //如果你想对 VectorDrawable (也就是binding.vectorDrawableIv2.drawable) 做动画处理,你需要使用 AnimatedVectorDrawable
            //不然你会发现报错信息 Method setScaleX() with type float not found on target class class android.graphics.drawable.VectorDrawable
            //refer link:https://stackoverflow.com/a/32007436/11641198
            val iv = binding.vectorDrawableIv2
            val an1 = ObjectAnimator.ofFloat(iv, "scaleX", 0f, 1f).apply {
                duration = 3000
                repeatCount = ValueAnimator.INFINITE
                repeatMode = ValueAnimator.REVERSE
            }
            val an2 = ObjectAnimator.ofFloat(iv, "scaleY", 0f, 1f).apply {
                duration = 3000
                repeatCount = ValueAnimator.INFINITE
                repeatMode = ValueAnimator.REVERSE
            }
            AnimatorSet().apply {
                duration = 3000
                playTogether(an1, an2)
                start()
            }
        }
    }
    

    12.自定义 Drawable

    package com.drawable.learning.fragment.custom.line_chart
    
    import android.graphics.*
    import android.graphics.drawable.Drawable
    import com.drawable.learning.tools.px
    
    /**
     * @author jere
     *
     * Draws a mesh dotted background
     */
    class BgGridDrawable : Drawable() {
        private val lineCount = 4
        private val columnCount = 5
        private val path: Path = Path()
    
        private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            style = Paint.Style.STROKE
            strokeWidth = 1f.px
            color = Color.parseColor("#80B5B5B5")
            pathEffect = DashPathEffect(floatArrayOf(5f.px, 5f.px, 5f.px, 5f.px), 0f)
        }
    
        private var pixelX = 0f
        private var pixelY = 0f
        override fun draw(canvas: Canvas) {
            for (i in 0 until lineCount) {
                pixelY = (bounds.top + bounds.height() / lineCount * i).toFloat()
                path.moveTo(bounds.left.toFloat(), pixelY)
                path.lineTo(bounds.right.toFloat(), pixelY)
                canvas.drawPath(path, paint)
            }
            for (i in 0 until columnCount) {
                pixelX = (bounds.left + bounds.width() / columnCount * i).toFloat()
                path.moveTo(pixelX, bounds.top.toFloat())
                path.lineTo(pixelX, bounds.bottom.toFloat())
                canvas.drawPath(path, paint)
            }
        }
    
        override fun setAlpha(alpha: Int) {
            paint.alpha = alpha
        }
    
        override fun getOpacity(): Int {
            return when (paint.alpha) {
                0xff -> PixelFormat.OPAQUE
                0x00 -> PixelFormat.TRANSPARENT
                else -> PixelFormat.TRANSLUCENT
            }
        }
    
        override fun setColorFilter(colorFilter: ColorFilter?) {
            paint.colorFilter = colorFilter
        }
    
    }
    
    package com.drawable.learning.fragment.custom.line_chart
    
    import android.graphics.*
    import android.graphics.drawable.Drawable
    import com.drawable.learning.fragment.BaseFragment
    import com.drawable.learning.databinding.FragmentLineChartBinding
    import com.drawable.learning.tools.px
    
    /**
     * @author jere
     *
     * drawing line chart
     */
    class LineChartFragment : BaseFragment<FragmentLineChartBinding>() {
        override fun initView() {
            binding.customDrawableTv.apply {
                background = MyDrawable()
            }
        }
    
        class MyDrawable : Drawable() {
            private val bgDrawable = BgGridDrawable()
    
            private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
                style = Paint.Style.FILL_AND_STROKE
                strokeWidth = 2f.px
                color = Color.parseColor("#96CDCD")
            }
    
            //hard code the points of the line chart
            private val path = Path()
    
            private fun calculatePath() {
                path.apply {
                    reset()
                    moveTo(bounds.left.toFloat(), bounds.bottom.toFloat())
                    lineTo(bounds.left.toFloat(), 150f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.05f, 200f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.1f, 130f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.15f, 250f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.2f, 80f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.25f, 220f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.3f, 200f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.35f, 30f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.4f, 240f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.45f, 260f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.5f, 160f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.55f, 100f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.6f, 80f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.65f, 20f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.7f, 150f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.75f, 170f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.8f, 320f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.85f, 220f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.9f, 300f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 0.95f, 120f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 1f, 360f)
                    lineTo(bounds.left.toFloat() + bounds.width() * 1f, bounds.bottom.toFloat())
                }
            }
    
            override fun draw(canvas: Canvas) {
                paint.shader = null
                calculatePath()
    
                canvas.drawRect(
                    bounds.left.toFloat(),
                    bounds.top.toFloat(),
                    bounds.right.toFloat(),
                    bounds.bottom.toFloat(),
                    paint
                )
    
                bgDrawable.bounds = bounds
                bgDrawable.draw(canvas)
    
    
    //            paint.apply {
    //                style = Paint.Style.STROKE
    //                strokeWidth = 2f.px
    //                color = Color.WHITE
    //            }
    //            canvas.drawPath(path, paint)
    
                //draw the shader for path
                path.close()
                paint.apply {
                    style = Paint.Style.FILL
                    shader = LinearGradient(
                        bounds.left.toFloat(), bounds.top.toFloat(),
                        bounds.left.toFloat(), bounds.bottom.toFloat(),
                        intArrayOf(Color.parseColor("#FF6A6A"), Color.TRANSPARENT),
                        null,
                        Shader.TileMode.CLAMP
                    )
                }
                canvas.drawPath(path, paint)
            }
    
            override fun setAlpha(alpha: Int) {
                paint.alpha = alpha
            }
    
            override fun getOpacity(): Int {
                return when (paint.alpha) {
                    0xff -> PixelFormat.OPAQUE
                    0x00 -> PixelFormat.TRANSPARENT
                    else -> PixelFormat.TRANSLUCENT
                }
            }
    
            override fun setColorFilter(colorFilter: ColorFilter?) {
                paint.colorFilter = colorFilter
            }
    
        }
    
    }
    
    <?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"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".fragment.custom.line_chart.LineChartFragment">
    
        <TextView
            android:id="@+id/customDrawableTv"
            android:layout_width="300dp"
            android:layout_height="200dp"
            android:layout_marginTop="50dp"
            android:gravity="start|center_horizontal"
            android:text="@string/line_chart"
            android:textColor="@color/white"
            android:textSize="20sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    package com.drawable.learning.fragment.custom.ball
    
    import android.graphics.*
    import android.graphics.drawable.Drawable
    import com.drawable.learning.tools.px
    
    /**
     * @author jere
     */
    class BallDrawable : Drawable() {
        private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            style = Paint.Style.FILL
            color = Color.parseColor("#D2691E")
        }
    
        private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            style = Paint.Style.STROKE
            strokeWidth = 1f.px
            color = Color.BLACK
        }
    
        override fun draw(canvas: Canvas) {
            val radius = bounds.width().toFloat() / 2
            canvas.drawCircle(
                bounds.width().toFloat() / 2,
                bounds.height().toFloat() / 2,
                radius,
                paint
            )
    
            //the vertical line of the ball
            canvas.drawLine(
                bounds.width().toFloat() / 2,
                0f,
                bounds.width().toFloat() / 2,
                bounds.height().toFloat(),
                linePaint
            )
            //the transverse line of the ball
            canvas.drawLine(
                0f,
                bounds.height().toFloat() / 2,
                bounds.width().toFloat(),
                bounds.height().toFloat() / 2,
                linePaint
            )
    
            val path = Path()
            val sinValue = kotlin.math.sin(Math.toRadians(45.0)).toFloat()
            //left curve
            path.moveTo(radius - sinValue * radius,
                radius - sinValue * radius
            )
            path.cubicTo(radius - sinValue * radius,
                radius - sinValue * radius,
                radius,
                radius,
                radius - sinValue * radius,
                radius + sinValue * radius
            )
            //right curve
            path.moveTo(radius + sinValue * radius,
                radius - sinValue * radius
            )
            path.cubicTo(radius + sinValue * radius,
                radius - sinValue * radius,
                radius,
                radius,
                radius + sinValue * radius,
                radius + sinValue * radius
            )
            canvas.drawPath(path, linePaint)
        }
    
        override fun setAlpha(alpha: Int) {
            paint.alpha = alpha
        }
    
        override fun getOpacity(): Int {
            return when (paint.alpha) {
                0xff -> PixelFormat.OPAQUE
                0x00 -> PixelFormat.TRANSPARENT
                else -> PixelFormat.TRANSLUCENT
            }
        }
    
        override fun setColorFilter(colorFilter: ColorFilter?) {
            paint.colorFilter = colorFilter
        }
    }
    
    package com.drawable.learning.fragment.custom.ball
    
    import android.animation.AnimatorSet
    import android.animation.ObjectAnimator
    import android.content.Context
    import android.graphics.Canvas
    import android.graphics.Color
    import android.graphics.Paint
    import android.graphics.Path
    import android.util.AttributeSet
    import android.view.Gravity
    import android.view.MotionEvent
    import android.widget.FrameLayout
    import android.widget.ImageView
    import com.drawable.learning.tools.px
    
    /**
     * @author jere
     */
    class CustomBallMovingSiteView(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) :
        FrameLayout(context, attributeSet, defStyleAttr) {
    
        constructor(context: Context) : this(context, null, 0)
        constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
    
        private lateinit var ballContainerIv: ImageView
        private val ballDrawable = BallDrawable()
        private val radius = 50
    
        private var rippleAlpha = 0
        private var rippleRadius = 10f
    
        private var rawTouchEventX = 0f
        private var rawTouchEventY = 0f
        private var touchEventX = 0f
        private var touchEventY = 0f
        private var lastTouchEventX = 0f
        private var lastTouchEventY = 0f
    
        private val ripplePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            isDither = true
            color = Color.RED
            style = Paint.Style.STROKE
            strokeWidth = 2f.px
            alpha = rippleAlpha
        }
    
        init {
            initView(context, attributeSet)
        }
    
        private fun initView(context: Context, attributeSet: AttributeSet?) {
            //generate a ball by dynamic
            ballContainerIv = ImageView(context).apply {
                layoutParams = LayoutParams(radius * 2, radius * 2).apply {
                    gravity = Gravity.CENTER
                }
    
                setImageDrawable(ballDrawable)
                //setBackgroundColor(Color.BLUE)
            }
    
            addView(ballContainerIv)
            setWillNotDraw(false)
        }
    
        override fun onTouchEvent(event: MotionEvent?): Boolean {
            lastTouchEventX = touchEventX
            lastTouchEventY = touchEventY
    
            event?.let {
                rawTouchEventX = it.x
                rawTouchEventY = it.y
                touchEventX = it.x - radius
                touchEventY = it.y - radius
            }
    
            ObjectAnimator.ofFloat(this, "rippleValue", 0f, 1f).apply {
                duration = 1000
                start()
            }
    
            val path = Path().apply {
                moveTo(lastTouchEventX, lastTouchEventY)
                quadTo(
                    lastTouchEventX,
                    lastTouchEventY,
                    touchEventX,
                    touchEventY
                )
            }
    
            val oaMoving = ObjectAnimator.ofFloat(ballContainerIv, "x", "y", path)
            val oaRotating = ObjectAnimator.ofFloat(ballContainerIv, "rotation", 0f, 360f)
    
            AnimatorSet().apply {
                duration = 1000
                playTogether(oaMoving, oaRotating)
                start()
            }
    
            return super.onTouchEvent(event)
        }
    
        fun setRippleValue(currentValue: Float) {
            rippleRadius = currentValue * radius
            rippleAlpha = ((1 - currentValue) * 255).toInt()
            invalidate()
        }
    
        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
            ripplePaint.alpha = rippleAlpha
            //draw ripple for click event
            canvas?.drawCircle(rawTouchEventX, rawTouchEventY, rippleRadius, ripplePaint)
        }
    }
    
    /**
     * @author jere
     */
    class MoveBallFragment : BaseFragment<FragmentMoveBallBinding>() {
    
        override fun initView() {
    
        }
    
    }
    
    <?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"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".fragment.custom.ball.MoveBallFragment">
    
        <com.drawable.learning.fragment.custom.ball.CustomBallMovingSiteView
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
    
        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/try_click_screen"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
    package com.drawable.learning.fragment.custom.stroke
    
    import android.graphics.*
    import android.graphics.drawable.Drawable
    import com.drawable.learning.tools.px
    
    class BubbleChatRectDrawable : Drawable() {
        private val pathPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.parseColor("#ECF6ED")
            style = Paint.Style.FILL
        }
    
        private val padding = 2f.px
    
        private var paddingStart = 30f.px
        private var paddingBottom = 20f.px
    
        private val outPath = Path()
        private val inPath = Path()
    
        override fun draw(canvas: Canvas) {
    
            bounds.apply {
    
                //外边框
                pathPaint.color = Color.parseColor("#2BDEA8")
                canvas.drawRoundRect(
                    left.toFloat(),
                    top.toFloat(),
                    right.toFloat(),
                    bottom.toFloat() - paddingBottom,
                    5f.px,
                    5f.px,
                    pathPaint
                )
    
                //内边框
                pathPaint.color = Color.parseColor("#ECF6ED")
                canvas.drawRoundRect(
                    left.toFloat() + padding,
                    top.toFloat() + padding,
                    right.toFloat() - padding,
                    bottom.toFloat() - paddingBottom - padding,
                    5f.px,
                    5f.px,
                    pathPaint
                )
    
                outPath.reset()
                outPath.moveTo(bounds.left + paddingStart, bottom - paddingBottom - padding)
                outPath.lineTo(bounds.left + paddingStart + 10f.px, bottom - paddingBottom + 13f.px)
                outPath.lineTo(bounds.left + paddingStart + 20f.px, bottom - paddingBottom - padding)
                outPath.close()
                pathPaint.color = Color.parseColor("#2BDEA8")
                canvas.drawPath(outPath, pathPaint)
    
                inPath.reset()
                inPath.moveTo(
                    bounds.left + paddingStart + padding,
                    bottom - paddingBottom - padding * 2
                )
                inPath.lineTo(
                    bounds.left + paddingStart + 10f.px,
                    bottom - paddingBottom + 13f.px - padding * 2
                )
                inPath.lineTo(
                    bounds.left + paddingStart - padding + 20f.px,
                    bottom - paddingBottom - padding * 2
                )
                inPath.close()
                pathPaint.color = Color.parseColor("#ECF6ED")
                canvas.drawPath(inPath, pathPaint)
            }
    
        }
    
        override fun setAlpha(alpha: Int) {
            pathPaint.alpha = alpha
        }
    
        override fun setColorFilter(colorFilter: ColorFilter?) {
            pathPaint.colorFilter = colorFilter
        }
    
        override fun getOpacity(): Int {
            return when (pathPaint.alpha) {
                0xff -> PixelFormat.OPAQUE
                0x00 -> PixelFormat.TRANSPARENT
                else -> PixelFormat.TRANSLUCENT
            }
        }
    
    }
    
    package com.drawable.learning.fragment.custom.stroke
    
    import android.animation.ValueAnimator
    import android.content.Context
    import android.graphics.*
    import android.util.AttributeSet
    import android.util.Log
    import android.view.View
    import android.view.animation.LinearInterpolator
    import androidx.lifecycle.DefaultLifecycleObserver
    import androidx.lifecycle.LifecycleOwner
    import com.drawable.learning.tools.px
    
    class HighlightAnimView(context: Context, attributeSet: AttributeSet?, defStyleAttr: Int) :
        View(context, attributeSet, defStyleAttr), DefaultLifecycleObserver {
        private val TAG = "HighlightAnimView"
    
        constructor(context: Context) : this(context, null, 0)
        constructor(context: Context, attributeSet: AttributeSet?) : this(context, attributeSet, 0)
    
        private var percent = 0f
    
        private var realValueAnimator: ValueAnimator =
            ValueAnimator.ofFloat(0f, 1f).apply {
                interpolator = LinearInterpolator()
                repeatCount = ValueAnimator.INFINITE
                repeatMode = ValueAnimator.RESTART
                duration = 600
                addUpdateListener {
                    it.animatedValue.toString().toFloat().let { valuePercent ->
                        percent = valuePercent
    //                    Log.e(TAG, "percent = $percent: ")
                    }
                    postInvalidate()
                }
            }
    
        private fun startAnim() {
            Log.e(TAG, "startAnim: realValueAnimator.isRunning = ${realValueAnimator.isRunning}")
            if (!realValueAnimator.isRunning) {
                realValueAnimator.start()
            }
        }
    
        private fun stopAnim() {
            Log.e(TAG, "stopAnim: realValueAnimator.isRunning = ${realValueAnimator.isRunning}")
            if (realValueAnimator.isRunning) {
                realValueAnimator.cancel()
            }
    
        }
    
        override fun onResume(owner: LifecycleOwner) {
            super.onResume(owner)
            Log.e(TAG, "onResume: ")
            startAnim()
        }
    
        override fun onPause(owner: LifecycleOwner) {
            super.onPause(owner)
            Log.e(TAG, "onPause: ")
            stopAnim()
        }
    
        override fun onStop(owner: LifecycleOwner) {
            super.onStop(owner)
            Log.e(TAG, "onStop: ")
            stopAnim()
        }
    
    
        private val dashPathEffect by lazy {
            DashPathEffect(floatArrayOf(5f.px, 5f.px, 5f.px, 5f.px), 1f)
        }
    
        private val linePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
            color = Color.parseColor("#FFE524")
            style = Paint.Style.STROKE
            strokeWidth = 5f.px
            pathEffect = dashPathEffect
        }
    
        private val topPath = Path()
        private val rightPath = Path()
        private val bottomPath = Path()
        private val leftPath = Path()
    
        private val distance = 10f.px
    
        override fun onDraw(canvas: Canvas?) {
            super.onDraw(canvas)
    
            topPath.reset()
            topPath.moveTo(distance * percent, 0f)
            topPath.lineTo(width.toFloat(), 0f)
            canvas?.drawPath(topPath, linePaint)
    
            rightPath.reset()
            rightPath.moveTo(width.toFloat(), distance * percent)
            rightPath.lineTo(width.toFloat(), height.toFloat())
            canvas?.drawPath(rightPath, linePaint)
    
            bottomPath.reset()
            bottomPath.moveTo(width.toFloat() - distance * percent, height.toFloat())
            bottomPath.lineTo(0f, height.toFloat())
            canvas?.drawPath(bottomPath, linePaint)
    
            leftPath.reset()
            leftPath.moveTo(0f, height.toFloat() - distance * percent)
            leftPath.lineTo(0f, 0f)
            canvas?.drawPath(leftPath, linePaint)
        }
    
    }
    
    package com.drawable.learning.fragment.custom.stroke
    
    import com.drawable.learning.databinding.FragmentHighlightAnimBinding
    import com.drawable.learning.fragment.BaseFragment
    import com.drawable.learning.tools.px
    
    class HighlightAnimFragment : BaseFragment<FragmentHighlightAnimBinding>() {
    
    
        override fun initView() {
            val bubbleChatRectDrawable = BubbleChatRectDrawable()
    
            val intArray = IntArray(2)
            binding.testIv.getLocationOnScreen(intArray)
    
            bubbleChatRectDrawable.setBounds(
                intArray[0],
                intArray[1],
                (intArray[0] + 200f.px).toInt(),
                (intArray[1] + 100f.px).toInt()
            )
            binding.testIv.background = bubbleChatRectDrawable
    
            lifecycle.addObserver(binding.noteSav)
            lifecycle.addObserver(binding.sav)
    
        }
    
    }
    
    <?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:layout_width="match_parent"
        android:layout_height="match_parent">
    
        <TextView
            android:id="@+id/noteTv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="20dp"
            android:padding="10dp"
            android:text="@string/please_note"
            android:textSize="16sp"
            android:textStyle="bold"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <com.drawable.learning.fragment.custom.stroke.HighlightAnimView
            android:id="@+id/noteSav"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@android:color/transparent"
            app:layout_constraintBottom_toBottomOf="@id/noteTv"
            app:layout_constraintEnd_toEndOf="@id/noteTv"
            app:layout_constraintStart_toStartOf="@id/noteTv"
            app:layout_constraintTop_toTopOf="@id/noteTv" />
    
        <ImageView
            android:id="@+id/noteNickIv"
            android:layout_width="160dp"
            android:layout_height="100dp"
            android:scaleType="fitXY"
            android:src="@drawable/nick"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="0.3" />
    
        <com.drawable.learning.fragment.custom.stroke.HighlightAnimView
            android:id="@+id/sav"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_margin="-20dp"
            android:background="@android:color/transparent"
            app:layout_constraintBottom_toBottomOf="@id/noteNickIv"
            app:layout_constraintEnd_toEndOf="@id/noteNickIv"
            app:layout_constraintStart_toStartOf="@id/noteNickIv"
            app:layout_constraintTop_toTopOf="@id/noteNickIv" />
    
        <ImageView
            android:id="@+id/testIv"
            android:layout_width="200dp"
            android:layout_height="100dp"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_marginStart="100dp"
            android:layout_marginBottom="50dp"/>
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    13.其他:

    abstract class BaseFragment<B : ViewBinding> : Fragment() {
    
        private var _binding: B? = null
        val binding
            get() = _binding!!
    
        val TAG = this.javaClass.simpleName
    
        override fun onCreateView(
            inflater: LayoutInflater,
            container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
            val type = (javaClass.genericSuperclass as ParameterizedType).actualTypeArguments[0] as Class<B>
            val method = type.getDeclaredMethod(
                "inflate",
                LayoutInflater::class.java,
                ViewGroup::class.java,
                Boolean::class.java
            )
            _binding = method.invoke(null, layoutInflater, container, false) as B
            return binding.root
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            initView()
        }
    
        abstract fun initView()
    
    }
    

    https://github.com/JereChen11/Drawable_Learning

    相关文章

      网友评论

          本文标题:Android Drawable类型集合

          本文链接:https://www.haomeiwen.com/subject/fdonkjtx.html