View绘制流程之Drawable(二)

2016-08-14  本文已影响143人  狮_子歌歌

Drawable

在上篇笔记中简要的阐述了下个人对Drawable的理解,该篇笔记是对Drawable中的StateListDrawable实践。

StateListDrawable

shape标签只能定义不同的形状,而selector标签则可以根据控件的状态显示不同形状。例如一个按钮常态与按下时的背景形状可以完全不同。有时候改变的不止是背景(包含形状)、图片,还可能是文字颜色。这些需求都可以通过selector标签来实现。

selector

selector可以有一个或者多个子标签item,而相应的状态是在item标签中定义的。定义的xml文件可以作为两种资源使用:drawable和color。作为drawable资源使用时,一般和shape一样放于drawable目录下,item必须指定android:drawable属性;作为color资源使用时,则放于color目录下,item必须指定android:color属性。

子标签的状态属性

控件的drawable XML:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 窗口失去焦点-->
    <item android:drawable="@drawable/bg_btn_lost_window_focused"
          android:state_window_focused="false"/>
    <!-- 不可用时-->
    <item android:drawable="@drawable/bg_btn_disabled"
          android:state_enabled="false"/>
    <!-- 按压时 -->
    <item android:drawable="@drawable/bg_btn_pressed"
          android:state_pressed="true"/>
    <!-- 被选中时-->
    <item android:drawable="@drawable/bg_btn_selected"
          android:state_selected="true"/>

    <!-- 被激活时-->
    <item android:drawable="@drawable/bg_btn_activated"
          android:state_activated="true"/>

    <!-- 获取焦点时-->
    <item android:drawable="@drawable/bg_btn_focused"
          android:state_focused="true"/>

    <!-- 默认状态-->
    <item android:drawable="@drawable/bg_btn_normal" />

</selector>

字体的颜色XML:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <!-- 当窗口失去焦点时的字体颜色-->
    <item android:color="@android:color/black"
          android:state_window_focused="false"/>
    <!-- 控件不可用时-->
    <item android:color="@android:color/background_light"
          android:state_enabled="false"/>
    <!-- 按压时-->
    <item android:color="@android:color/holo_blue_light"
          android:state_pressed="true"/>
    <!-- 被选择时-->
    <item android:color="@android:color/holo_orange_dark"
          android:state_selected="true"/>
    <!-- 被激活时-->
    <item android:color="@android:color/holo_red_dark"
          android:state_activated="true"/>
    <!-- 默认时的字体颜色-->
    <item android:color="@android:color/black"/>
</selector>

在布局文件中的引用:

<Button
        android:id="@+id/activate_btn"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="12dp"
        android:background="@drawable/bg_btn_selector"
        android:text="no activated"
        android:textColor="@color/text_btn_selector"/>

效果显示如下:

StateListDrawable.gif

注意

ListView的Item样式设置

有两种设置方式,一种是在ListView标签里设置android:listSelector属性,另一种是在ListItem的布局layout里设置android:background。两者有很大的区别:

如果你的自定义ListViewItem中有Button、ImageButton或者Checkable的子类控件的话,那么默认focus是交给了子控件,而ListView的Item能被选中的基础是它能获取Focus。所以常常当点击item时变化的是子控件,item本身的点击没有响应。
解决方案:

第三种方法是最实用的,descendantFocusability属性可以设置一个控件如何处理触摸事件,
该属性是当一个为view获取焦点时,定义viewGroup和其子控件两者之间的关系。其值有:

其原理是这样一来ListItem的Layout(根View)就屏蔽了所有子控件获取Focus的权限,如此就可以顺利的响应onItemClickListener中的onItenClick()方法了。

窗口焦点

这次实践中涉及到了焦点问题,自己测试了下。发现问题比较复杂,给自己留个作业,什么是窗口焦点,点击控件会得到焦点,几个控件能同时得到焦点吗,焦点和事件传递有关系吗?即使我采用上面的blocksDescendants属性,发现ListView的item并没有获取到焦点(通过item.isFoucsed()来判断),这是为什么?

View如何获取焦点

Android新启动Activity,dialog或者其他窗体中中包含EditText, 新启动的activity的焦点默认在EditText上,这是android系统会弹出软键盘,挤压activity本来的界面,影响美观。
因此最好在新窗体创建时,最好在onCreate()方法中将焦点放在另一个view上. view使用requestFocus()焦点,但是如果让button或者textView之类控件直接使用requestFocus()方法,则无法获取焦点,焦点会依然在editText上。
只能在使用View的requestFocus()方法之前调用下面2个方法,view才可获取焦点:

  1. view.setFocusable(true);
  2. view.setFocusableInTouchMode(true);
  3. 然后调用 requestFocus()即可获取焦点。

遇到的问题

  1. 通过selector标签定义的color资源与value目录下的color.xml资源有什么区别,有时间去看看color资源讲解
  2. 导入项目,需要更改gradle-wapper文件的最后一项gradle版本,进入项目后可能需要更改build.gradle(module:app)里面的buildToolVersion和build.gradle(Project:name)里面的gradle依赖版本。

参考

文献文献2文献3文献4

上一篇 下一篇

猜你喜欢

热点阅读