Android资料库Android知识库Android

Android样式研究

2017-02-02  本文已影响637人  CokeNello

今天我们来探究一下android的样式。
其实,几乎所有的控件都可以使用 background属性去引用自定义的XML样式,所以研究样式显得特别重要。
先来看一段样式代码:

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape
            android:innerRadiusRatio="10"
            android:shape="ring"
            android:thicknessRatio="9"
            android:useLevel="false">
            <stroke
                android:width="1dp"
                android:color="@android:color/black" />
        </shape>
    </item>
</selector>

说一下一些基本的知识:(我也是刚刚才知道的)

<?xml version="1.0" encoding="utf-8"?>

(一)selector的内属性

xmlns:android="http://schemas.android.com/apk/res/android"

android:visiable

android:autoMirrored

android:constantSize

android:dither

android:enterFadeDuration

android:exitFadeDuration

android:variablePadding

(二)selector下的标签:item标签的内属性

selector标签下只有item标签。
item的标签内属性如下:

都是设置控件在什么状态下的样式:

android:drawable 需要入别的xml,默认是背景图片
android:state_above_achor
android:state_accelerated 硬件加速true时的效果
android:state_activated true被激活时的效果,false未激活时的效果
android:state_active true激活后的效果
android:state_checkable true,当CheckBox能使用时显示该图片
android:state_checked true,当CheckBox选中时显示该图片
android:state_drag_can_accept true 能够 drag 拖拽时图片
android:state_drag_hovered true 能够 drag 鼠标指针移动到该位置图片
android:state_empty
android:state_enabled true,当该组件能使用时显示该图片
android:state_expanded
android:state_first
android:state_****focused true非触摸模式下获得焦点时显示图片
android:state_hovered 鼠标移动到该位置时的样式
android:state_last
android:state_long_pressable 长按的样式
android:state_middle
android:state_multiline
android:state_pressed 按下的样式
android:state_selected 选择时的样式
android:state_single true 只有一个元素显示图片
android:state_window_focused 当此activity获得焦点在最前面时显示该图片

(三)item下的标签

(1)shape标签:

标签内属性:

(A)shape=rectangle: 矩形,默认的形状,可以画出直角矩形、圆角矩形、弧形等

(B)shape=oval: 椭圆形,用得比较多的是画正圆

主要是通过设置padding和size去实现圆的大小,扁正。
  1. 注意,使用radial渐变时,必须指定渐变的半径,即android:gradientRadius属性。

(C)shape=line: 线形,可以画实线和虚线

line主要用于画分割线,是通过stroke和size特性组合来实现的

画线时,有几点特性必须要知道的:

  1. 只能画水平线,画不了竖线;
  2. 线的高度是通过stroke的android:width属性设置的;
  3. size的android:height属性定义的是整个形状区域的高度;
  4. size的height必须大于stroke的width,否则,线无法显示;
  5. 线在整个形状区域中是居中显示的;
  6. 线左右两边会留有空白间距,线越粗,空白越大;
  7. 引用虚线的view需要添加属性android:layerType,值设为”software”,否则显示不了虚线。

(D)shape=ring: 环形,可以画环形进度条

首先,shape根元素有些属性只适用于ring类型,先过目下这些属性吧:

android:innerRadius 内环的半径
android:innerRadiusRatio 浮点型,以环的宽度比率来表示内环的半径,默认为3,表示内环半 径为环的宽度除以3,该值会被android:innerRadius覆盖
android:thickness 环的厚度
android:thicknessRatio 浮点型,以环的宽度比率来表示环的厚度,默认为9,表示环的厚度为环的宽度除以9,该值会被android:thickness覆盖
android:useLevel 一般为false,否则可能环形无法显示,只有作为LevelListDrawable使用时才设为true

(2)layer-list标签:

layer-list经过一系列的item标签,从上到下的顺序,从低到上把item的效果叠加起来。

layer-list可以作为根节点,也可以作为selector中item的子节点。layer-list可以添加多个item子节点,每个item子节点对应一个drawable资源,按照item从上到下的顺序叠加在一起,再通过设置每个item的偏移量就可以看到阴影等效果了。layer-list的item可以通过下面四个属性设置偏移量:

android:top 顶部的偏移量
android:bottom 底部的偏移量
android:left 左边的偏移量
android:right 右边的偏移量

这四个偏移量和控件的margin设置差不多,都是外间距的效果。如何不设置偏移量,前面的图层就完全挡住了后面的图层,从而也看不到后面的图层效果了。比如上面的例子,Tab背景中的白色背景设置了android:bottom之后才能看到一点红色背景。那么如果偏移量设为负值会怎么样呢?经过验证,偏移超出的部分会被截掉而看不到,不信可以自己试一下。有时候这很有用,比如当我想显示一个半圆的时候。

另外,关于item的用法,也做下总结:

根节点不同时,可设置的属性是会不同的,比如selector下,可以设置一些状态属性,而在layer-list下,可以设置偏移量;
就算父节点同样是selector,放在drawable目录和放在color目录下可用的属性也会不同,比如drawable目录下可用的属性为android:drawable,在color目录下可用的属性为android:color;
item的子节点可以为任何类型的drawable类标签,除了上面例子中的shape、color、layer-list,也可以是selector,还有其他没讲过的bitmap、clip、scale、inset、transition、rotate、animated-rotate、lever-list等等。

for example,以下是一个白色背景,有灰色阴影的矩形框。

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <layer-list>
            <!-- 灰色阴影 -->
            <item
                android:left="1dp"
                android:top="2dp">
                <shape>
                    <size android:width="20dp" android:height="10dp"/>
                    <solid android:color="@android:color/darker_gray" />
                    <corners android:radius="10dp" />
                </shape>
            </item>
            <!-- 白色前景 -->
            <item
                android:bottom="2dp"
                android:right="1dp">
                <shape>
                    <solid android:color="#FFFFFF" />
                    <corners android:radius="10dp" />
                </shape>
            </item>
        </layer-list>
    </item>
</selector>

(3)bitmap标签

主要可以通过bitmap标签对图片做一些设置,如平铺、拉伸或保持图片原始大小,也可以指定对齐方式。

(4)nine-patch标签

点九图片文件扩展名为:.9.png,通过点九图片可以做局部拉伸,比如,一张圆角矩形图片,我们不想让它的四个边角都被拉伸从而导致模糊失真,使用点九图就可以控制拉伸区域,让四个边角保持完美显示。

画点九图一般用Android SDK工具集里的draw9patch工具,只需要在四条边画黑线就可以了,

使用nine-patch标签可以对点九图片做一些设置处理,不过可设置的属性并不多:

(5)color标签

color标签是drawable里最简单的标签了,只有一个属性:android:color,指定颜色值。这个标签一般很少用,因为基本都可以通过其他更方便的方式定义颜色。另外,颜色值一般都在colors.xml文件中定义,其根节点为resources。

(6)inset标签

使用inset标签可以对drawable设置边距,其用法和View的padding类似,只不过padding是设置内容与边界的距离,而inset则可以设置背景drawable与View边界的距离。inset标签的可设置属性如下:

(7)clip标签

使用clip标签可以对drawable进行裁剪,在做进度条时很有用。通过设置level值控制裁剪多少,level取值范围为0~10000,默认为0,表示完全裁剪,图片将不可见;10000则完全不裁剪,可见完整图片。看看clip标签可以设置的属性:

level的设置需要在代码中动态去设置:

1 . 定义clip.xml:

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

2 . 在ImageView中引用:

<ImageView
    android:id="@+id/img"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/bg_img"
    android:src="@drawable/clip" />

3 . 在代码中设置level:

ImageView img = (ImageView) findViewById(R.id.img);
img.getDrawable().setLevel(5000); //level范围值0~10000

(7)scale标签

(8)level-list标签

当需要在一个View中显示不同图片的时候,比如手机剩余电量不同时显示的图片不同,level-list就可以派上用场了。level-list可以管理一组drawable,每个drawable设置一组level范围,最终会根据level值选取对应的drawable绘制出来。level-list通过添加item子标签来添加相应的drawable,其下的item只有三个属性:

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/battery_low"
        android:maxLevel="10"
        android:minLevel="0" />
    <item
        android:drawable="@drawable/battery_below_half"
        android:maxLevel="50"
        android:minLevel="10" />
    <item
        android:drawable="@drawable/battery_over_half"
        android:maxLevel="99"
        android:minLevel="50" />
    <item
        android:drawable="@drawable/battery_full"
        android:maxLevel="100"
        android:minLevel="100" />
</level-list>

那么,当电量剩下10%时则可以设置level值为10,将会匹配第一张图片:

img.getDrawable().setLevel(10);

item的匹配规则是从上到下的,当设置的level值与前面的item的level范围匹配,则采用。一般item的添加按maxLevel从小到大排序下来,此时minLevel可以不用指定也能匹配到。如上面代码就可以简化如下:

<?xml version="1.0" encoding="utf-8"?>
<level-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:drawable="@drawable/battery_low"
        android:maxLevel="10" />
    <item
        android:drawable="@drawable/battery_below_half"
        android:maxLevel="50" />
    <item
        android:drawable="@drawable/battery_over_half"
        android:maxLevel="99" />
    <item
        android:drawable="@drawable/battery_full"
        android:maxLevel="100" />
</level-list>

但不能反过来将android:maxLevel=”100″的item放在最前面,那样所有电量都只匹配第一条了。

(9)transition标签

transition其实是继承自layer-list的,只是,transition只能管理两层drawable,另外提供了两层drawable之间切换的方法,切换时还会有淡入淡出的动画效果。示例代码如下:

<?xml version="1.0" encoding="utf-8"?>
<transition xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@drawable/on" />
    <item android:drawable="@drawable/off" />
</transition>

transition标签生成的Drawable对应的类为TransitionDrawable,要切换时,需要主动调用TransitionDrawable的startTransition()方法,参数为动画的毫秒数,也可以调用reverseTransition()方法逆向切换。

((TransitionDrawable)drawable).startTransition(500); //正向切换,即从第一个drawable切换到第二个
((TransitionDrawable)drawable).reverseTransition(500); //逆向切换,即从第二个drawable切换回第一个

(10)rotate标签

使用rotate标签可以对一个drawable进行旋转操作,在shape篇讲环形时最后举了个进度条时就用到了rotate标签。另外,比如你有一张箭头向上的图片,但你还需要一个箭头向下的图片,这时就可以使用rotate将向上的箭头旋转变成一张箭头向下的drawable。
先看看rotate标签的一些属性吧:

示例代码如下,目标是将一张箭头向上的图片转180度,转成一张箭头向下的图片:

<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/ic_arrow"
    android:fromDegrees="0"
    android:pivotX="50%"
    android:pivotY="50%"
    android:toDegrees="180" />

将它引用到ImageView里,发现图片根本没有转变。其实,要让它可以旋转,还需要设置level值。level取值范围为010000,应用到rotate,则与fromDegreestoDegrees相对应,如上面例子的角度范围为0~180,那么,level取值0时,则旋转为0度;level为10000时,则旋转180度;level为5000时,则旋转90度。因为level默认值为0,所以图片没有转变。那么,我们想转180度,其实可以将fromDegrees设为180,而不设置toDegrees,这样,不用再在代码里设置level图片就可以旋转180了。

(11)animation-list标签

通过animation-list可以将一系列drawable构建成帧动画,就是将一个个drawable,一帧一帧的播放。通过添加item子标签设置每一帧使用的drawable资源,以及每一帧持续的时间。示例代码如下:

<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:drawable="@drawable/anim1"
        android:duration="1000" />
    <item
        android:drawable="@mipmap/anim2"
        android:duration="1000" />
    <item
        android:drawable="@mipmap/anim3"
        android:duration="1000" />
</animation-list>

注意:
1.必须要把 animated-list 设置成主标签
2.只有通过 andorid:src 引用才可以,也就是button类的控件不能这样设置动画
3.如果控件没有效果,需在代码中这样设置:

        private ImageButton hh;
        hh = (ImageButton) findViewById(R.id.imageButton);
        Drawable drawable = hh.getDrawable();

        if (!((AnimationDrawable) drawable).isRunning()) {
            ((AnimationDrawable) drawable).start();
        }

(12)animated-rotate

rotate标签只是将原有的drawable转个角度变成另一个drawable,它是静态的。而animated-rotate则会让drawable不停地做旋转动画。
animated-rotate可设置的属性只有四个:

<?xml version="1.0" encoding="utf-8"?>
<animated-rotate xmlns:android="http://schemas.android.com/apk/res/android"
    android:drawable="@drawable/img_daisy"
    android:pivotX="50%"
    android:pivotY="50%"
    android:visible="false" />

注意:
1.必须要把 animated-rotate 设置成主标签
2.只有通过 andorid:src 引用才可以,也就是button类的控件不能这样设置动画
3.如果控件没有效果,需在代码中这样设置:

        private ImageButton hh;
        hh = (ImageButton) findViewById(R.id.imageButton);
        Drawable drawable = hh.getDrawable();

        if (!((Animatable) drawable).isRunning()) {
            ((Animatable) drawable).start();
        }
上一篇下一篇

猜你喜欢

热点阅读