自定义View(二-番外8)

来源:互联网 发布:gsm无线网络优化 编辑:程序博客网 时间:2024/06/16 21:40

From AigeStudio(http://blog.csdn.net/aigestudio)Power by Aige

跟着爱哥打天下

自定义控件其实很简单8:

自定义一个方形布局(省略……),主要是因为个人看懂了,然后里面充满了计算且实际应用价值没有,所以就不敲了。

这里我们也可以自定义属于自己的xml属性,方法非常非常简单,首先需要我们在declare-styleable标签下定义我们的各类属性:

<!-- http://blog.csdn.net/aigestudio -->  <declare-styleable name="SquareLayout">      <attr name="my_gravity" format="enum">          <enum name="left" value="0" />          <enum name="right" value="1" />          <enum name="center" value="2" />          <enum name="top" value="3" />          <enum name="bottom" value="4" />      </attr>  </declare-styleable> 

一般情况下,declare-styleable的定义存放在values/attr.xml文件中,属性定义好了我们就该在布局中使用这些属性,使用方法也很简单,比如我们在SquareLayout的Button中应用my_gravity属性:

<Button      xmlns:aigestudio="http://schemas.android.com/apk/res/com.aigestudio.customviewdemo"      aigestudio:my_gravity="left" /> 

在使用自定义属性前声明我们包内的命名空间即可,你可以直接写在布局文件的根布局下,命名空间的声明有两种写法,上面是其一,其格式如下:

xmlns:你想要的名字="http://schemas.android.com/apk/res/完整包名" 

第二种方式如果你是用的是Studio,IDE则会提示你使用该方式:

xmlns:你想要的名字="http://schemas.android.com/apk/res-auto"  

都可以,最后就是从xml中获取这些属性了,我们可以直接简单地通过带有AttributeSet对象的构造方法来获取:

public class SquareLayout extends ViewGroup {      // 省去无数代码…………      public static class LayoutParams extends MarginLayoutParams {          public int mGravity;// 对齐方式          public LayoutParams(MarginLayoutParams source) {              super(source);          }          public LayoutParams(android.view.ViewGroup.LayoutParams source) {              super(source);          }          public LayoutParams(Context c, AttributeSet attrs) {              super(c, attrs);              /*              * 获取xml对应属性              */              TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.SquareLayout);              mGravity = a.getInt(R.styleable.SquareLayout_my_gravity, 0);          }          public LayoutParams(int width, int height) {              super(width, height);          }      }  }  

通过Context的obtainStyledAttributes方法注入AttributeSet对象和我们资源文件中定义的declare-styleable属性获取一个TypedArray对象,我们通过这个TypedArray对象各种相应的方法来获取参数值,本来呢我之前写了很长的篇幅来给大家介绍这其中的过程,后来发现实在太繁琐太多干脆删了重写旨在教会大家如何用即可。Android支持如下十种不同类型的属性定义:

<!-- http://blog.csdn.net/aigestudio -->  <declare-styleable name="AttrView">      <!-- 引用资源 -->      <attr name="image" format="reference" />      <!-- 颜色 -->      <attr name="text_color" format="color" />      <!-- 布尔值 -->      <attr name="text_display" format="boolean" />      <!-- 尺寸大小 -->      <attr name="temp1" format="dimension" />      <!-- 浮点值 -->      <attr name="temp2" format="float" />      <!-- 整型值 -->      <attr name="temp3" format="integer" />      <!-- 字符串 -->      <attr name="text" format="string" />      <!-- 百分比 -->      <attr name="alpha" format="fraction" />      <!-- 枚举 -->      <attr name="text_align" format="integer">          <enum name="left" value="0" />          <enum name="right" value="1" />          <enum name="center" value="2" />      </attr>      <!-- 位运算 -->      <attr name="text_optimize" format="integer">          <flag name="anti" value="0x001" />          <flag name="dither" value="0x002" />          <flag name="linear" value="0x004" />      </attr>  </declare-styleable>  

name都是我乱取的不要在意,主要看后面的format,这些类型都很好理解,它们在TypedArray中都有各种对应或重载的方法,比如获取color的getColor方法,上面我们获取int的getInt等等,这里对大家来说比较新颖的是fraction百分比这个类型,其在TypedArray的对应方法如下:

getFraction(int index, int base, int pbase, float defValue)  

第一个参数很好理解表示我们定义的属性资源ID,最后一个参数呢也和前面的getInt类似,主要是这第二、三个参数,其作用是分开来的,当我们在xml中使用百分比属性时有两种写法,一种是标准的10%而另一种是带p的10%p:

aigestudio:alpha="10%"  aigestudio:alpha="10%p" 

当属性值为10%的时候base参数起作用,我们此时获取的参数值就等于(10% * base),而pbase参数则无效,同理当属性值为10%p时参数值就等于(10% * pbase)而base无效,Just it。还有两个比较类似的类型:枚举和位运算,这两个类型也很好理解,枚举嘛就是从众多的选项中选一个,而位运算则可以选多个并通过“|”组合各种结果:

aigestudio:text_optimize="anti|dither"  

这种写法相信大家也很常见,比如layout_gravity属性就可以以类似的方式多选,这种方式有一个好处就是我们不用在属性声明中定义太多的值,上面的text_optimize属性只有三个对应值,但是在code中我们可以以位运算的方式组合这三个参数值:

/*  * 画笔优化的标识位们  */  private static final int OPTIMIZE_ANTI = 0x001, OPTIMIZE_DITHER = 0x002, OPTIMIZE_LINEAR = 0x004, OPTIMIZE_ANTI_DITHER = 0x003, OPTIMIZE_ANTI_LINEAR = 0x005, OPTIMIZE_DITHER_LINEAR = 0x006, OPTIMIZE_ALL = 0x007;  

通过三个参数值的位运算我们实质上就得到了7种不同的结果,Just it。xml属性值的定义不难不多用几次就会就不多说了,上面呢我们通过自定义的属性mGravity来尝试定义子元素相对于父容器的对其方式,而事实上Android提供给我们一个简便的方法去计算这玩意,Android定义了Gravity类来实现我们对对其方式的计算,其中定义了大量的常量值定义不同对其方式,比如什么左对齐、右对齐、水平居中乱七八糟的等等,也提供了多个方法来实现计算,使用方式呢也不难,比如上面的布局参数我们换成如下方式:

/**  *   * @author AigeStudio {@link http://blog.csdn.net/aigestudio}  * @since 2015/1/23  *   */  public class SquareLayout extends ViewGroup {      // 省去无数代码…………      public static class LayoutParams extends MarginLayoutParams {          public int mGravity = Gravity.LEFT | Gravity.RIGHT;// 对齐方式          // 省去没变的代码…………      }  }  

而在我们的xml属性定义中则可以直接使用android:layout_gravity这样的name而无需定义类型值:

<declare-styleable name="SquareLayout">      <attr name="android:layout_gravity" />  </declare-styleable>  

这样则表示我们的属性使用的Android自带的标签,之后我们只需根据布局文件中layout_gravity属性的值调用Gravity类下的方法去计算对齐方式则可,Gravity类下的方法很好用,为什么这么说呢?因为其可以说是无关布局的,拿最简单的一个来说:

public static void apply(int gravity, int w, int h, Rect container, Rect outRect)  

第一个参数表示我们的对其方式值,第二三个参数呢则表示我们要对齐的元素,这里通俗地说就是我们父容器下的子元素,而container参数表示的则是我们父容器的矩形区域,最后一个参数是接收计算后子元素位置区域的矩形对象,随便new个传进去就行,可见apply方式是根据矩形区域来计算对其方式的,所以说非常好用,我们只需在onLayout方法中确定出父容器的矩形区域就可以轻松地计算出子元素根据对其方式出现在父容器中的矩形区域,这一个过程留给大家自行尝试,我就不多说了,TMD说的太多,又忘了上一节的那个问题了、肏!!!!好吧,下一节再说那个问题,哦!对了,还有一个擦边球的东西忘了讲,在Android很多的布局控件中都会重写这么一个方法:

@Override  public boolean shouldDelayChildPressedState() {      return false;  }  

并且都会一致地返回false,其作用是告诉framework我们当前的布局不是一个滚动的布局


原创粉丝点击