StateListDrawable使用详解

drawable state系列文章
XML类型的drawable图片的解析处理过程

StateListDrawable使用详解

详解refreshDrawableList()的执行流程

Checkable Views

Android中自定义drawable states

===============================================

前面介绍了XML类型的drawable图片的解析处理过程 ,我们知道,以xml定义的drawable文件其实对应的就是一个StateListDrawable实例,StateListDrawable是Drawable的子类,所以下面还是决定好好说说StateListDrawable。

还是举前面的那个例子:

1、在res/drawable文件下创建selector.xml,示例代码如下:

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

2、编写布局文件,为布局文件中的ImageButton设置selector,示例代码如下:

<?xml version="1.0" encoding="utf-8"?>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_height="wrap_content" 
    android:layout_width="fill_parent">  
    <Button 
        android:id="@+id/title_IB"
        android:layout_height="wrap_content" 
        android:layout_width="wrap_content" 
        android:background="@drawable/selector" 
        android:layout_marginRight="4dp" 
        android:layout_centerVertical="true">
    </Button>  
</RelativeLayout>

通过前面XML类型的drawable图片的解析处理过程 的分析,我们知道,selector.xml会被解析成一个StateListDrawable对象,在StateListDrawable的内部有一个StateListState对象,在StateListState对象里面有一个mStateSets的二维数组,StateListState的父类DrawableContainerState里面有一个mDrawables的图片数组,还是把这个类图的图片贴出来。

这里写图片描述

在我们解析xml的时候,首先得到第一个item,然后把item里面的状态放进一个一维数组stateSet,把drawable对应的图片也解析出来,接着就把这个一维数组stateSet放入mStateSets的二维数组的第0项,把drawable图片放入mDrawables数组的第0项,这样这个状态集合与图片资源通过下标进行了对应,接着就是xml文件中的第二个item,同样的方法把状态集合和图片资源放入mStateSets的二维数组和mDrawables数组的第1项,以此类推。这样整个xml的drawable和StateListDrawable就对应起来了。

上面所说的是系统帮我们处理的整个过程,这个过程在上面的文章XML类型的drawable图片的解析处理过程 中详细的介绍过,下面我们要做的就是我们怎样手动的用代码来写个StateListDrawable,并且同样实现上面xml定义drawable的功能。

我们直接写代码,然后进行分析。

//初始化一个空对象
StateListDrawable stalistDrawable = new StateListDrawable();
//获取对应的属性值 Android框架自带的属性 attr
int pressed = android.R.attr.state_pressed;
int focused = android.R.attr.state_focused;

stalistDrawable.addState(new int []{-pressed}, getResources().getDrawable(R.drawable.title_button_back));
stalistDrawable.addState(new int []{pressed}, getResources().getDrawable(R.drawable.title_button_back_h);
stalistDrawable.addState(new int []{-focused }, getResources().getDrawable(R.drawable.title_button_back);
//没有任何状态时显示的图片,我们给它设置我空集合
stalistDrawable.addState(new int []{}, getResources().getDrawable(R.drawable.title_button_back);

上面的“-”负号表示对应的属性值为false

由于我们把上面的整个解析过程已经弄清楚了,那么stalistDrawable.addState里面到底干了什么,我们也可以来看看。

public void addState(int[] stateSet, Drawable drawable) {
    if (drawable != null) {
        mStateListState.addStateSet(stateSet, drawable);
        // in case the new state matches our current state...
        onStateChange(getState());
    }
}

看到没有它里面执行的还是mStateListState的addStateSet方法,这个更我们解析xml文件的做法是一致的.
mStateListState就是一个StateListState对象,StateListState是StateListDrawable的静态内部类,我们来看看具体的实现:

int addStateSet(int[] stateSet, Drawable drawable) {
    final int pos = addChild(drawable);
    mStateSets[pos] = stateSet;
    return pos;
}

它会执行addChild函数,StateListState没有实现这个函数,它直接继承自它的父类DrawableContainerState,DrawableContainerState是DrawableContainer类的静态内部类:

public final int addChild(Drawable dr) {
    final int pos = mNumChildren;

    if (pos >= mDrawables.length) {
        growArray(pos, pos+10);
    }

    dr.setVisible(false, true);
    dr.setCallback(mOwner);

    mDrawables[pos] = dr;
    mNumChildren++;
    mChildrenChangingConfigurations |= dr.getChangingConfigurations();
    mCheckedStateful = false;
    mCheckedOpacity = false;

    mConstantPadding = null;
    mPaddingChecked = false;
    mComputedConstantSize = false;

    return pos;
}

看到没有做法一模一样,同样是把它们放入mStateSets的二维数组和mDrawables数组数组中,现在整个思路应该很清楚了。

下面我们就不使用xml来定义这个drawable,我们直接使用代码来写一个,也可以实现同样的效果:

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_height="wrap_content"
    android:layout_width="fill_parent">
    <Button
    android:id="@+id/title_IB"
    android:layout_height="wrap_content"
    android:layout_width="wrap_content"
    android:layout_marginRight="4dp"
    android:layout_centerVertical="true">
</Button>
</RelativeLayout>

我们可以看到,跟上面的那个布局的区别就是它没有background属性。

MainActivity代码:

package com.xxx.cn.mystatelistdrawable;

import android.app.Activity;
import android.graphics.drawable.StateListDrawable;
import android.os.Bundle;
import android.widget.Button;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Button button = (Button) findViewById(R.id.title_IB);
        button.setBackground(initStateListDrawable());
    }

    private StateListDrawable initStateListDrawable() {
        //初始化一个空对象
        StateListDrawable stalistDrawable = new StateListDrawable();
        //获取对应的属性值 Android框架自带的属性 attr
        int pressed = android.R.attr.state_pressed;
        int focused = android.R.attr.state_focused;

        stalistDrawable.addState(new int []{-pressed}, getResources().getDrawable(R.drawable.title_button_back));
        stalistDrawable.addState(new int []{pressed}, getResources().getDrawable(R.drawable.title_button_back_h));
        stalistDrawable.addState(new int []{-focused }, getResources().getDrawable(R.drawable.title_button_back));
        //没有任何状态时显示的图片,我们给它设置我空集合
        stalistDrawable.addState(new int []{}, getResources().getDrawable(R.drawable.title_button_back));
        return stalistDrawable;
    }
}

参考文章:

Android中View(视图)绘制不同状态背景图片原理深入分析以及StateListDrawable使用详解

  • 1
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Sourcetree是一个非常好用的git客户端,它提供了可视化的界面帮助开发者进行多人协作开发过程中的各种git操作,比如push、pull、add、commit、merge等等。 在使用Sourcetree之前,你需要先下载、安装和配置好环境。然后你可以打开Sourcetree,它会展示一个初始界面,其中包含了本地仓库的相关信息。 Sourcetree是一个强大的工具,但本文只介绍了一些常用的功能,并没有记录一些使用频率较低的功能。工具的目的是帮助我们提高工作效率,所以我们只需要掌握最有用的部分即可。 在正文部分,你可以了解到Sourcetree的各种功能,以及对应的git命令和如何使用这些功能。它详细介绍了各种常用操作,帮助你更好地使用Sourcetree进行版本控制。[1,2] 使用Sourcetree可以很方便地进行分支的检出和关联远程分支。当你使用命令行检出分支后,你还需要执行一些操作来与远程分支进行关联。但是Sourcetree非常友好,当你点击克隆按钮时,它会自动帮助你与远程仓库进行关联。 总之,Sourcetree是一个功能强大且易于使用的git客户端,它为开发者提供了可视化的界面来管理和执行各种git操作,帮助我们更高效地进行协同开发。[1,2,3]<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [Sourcetree 使用详解](https://blog.csdn.net/weixin_43837354/article/details/105936140)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* [SourceTree使用教程图文详解](https://blog.csdn.net/qq_41153943/article/details/120814918)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值