当android现有的控件不能满足我们的需求的时候,我们一般要自定义自己的控件。
自定义控件的实现并不特别难,关键在理解需求及注意实现的细节。
现在举个例子实现开关按钮的自定义控件。
需求:
1.点击按钮,切换开关状态。
2.拖动按钮,切换开关状态。
注意细节问题:
1.用户拖动控件的时候,有点击屏幕的事件,这个时候注册监听点击事件会被响应。说白了就是拖动和点击混淆了。
即用户明明想拖动的,你却实现了拖动完成+点击。
2.拖动是超越边界。
3.拖动到中途停止拖动,状态无法选择。
解决问题方法:
1.用户拖动控件的距离超过5,认为用户意图是拖动,禁用点击功能;否则,认为用户是点击意图,实现点击功能。
2.拖动位置小于最小位置,设置为0;超过最大位置,设置为最大边界。
3.拖动到中途的位置与中线(昨天起始位置与最大位置的中线)比较,小于中线归为起始状态,大于或等于中线为截止的状态。
@Override
/**
* 测量尺寸时的回调方法 这个方法我以前比较少用所以这里mark
*/
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//super.onMeasure(widthMeasureSpec, heightMeasureSpec);
/**
* 设置当前view的大小
* width :view的宽度
* height :view的高度 (单位:像素)
*/
setMeasuredDimension(backgroundBitmap.getWidth(),backgroundBitmap.getHeight());
}
加上自定义属性(常用于封装组件给自己或他人使用)
首先在res/values/attrs.xml设置
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- 声名属性集的名称 -->
<declare-styleable name="MySwitchBtn">
<!-- 声名一个属性 name是my_background(开关背景图) 类型为 引用类型 引用资源ID -->
<attr name="my_background" format="reference" />
<!-- 声名一个属性 name是my_slide_btn(开关按钮图) 类型为 引用类型 引用资源ID -->
<attr name="my_slide_btn" format="reference" />
<!-- 声名一个属性 name是curr_state (初始开关状态) 类型为 boolean 类型-->
<attr name="curr_state" format="boolean" />
</declare-styleable>
</resources>
在自定义控件类中解析自定义属性
MySwitchBtn.java
//获得自定义的属性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.MySwitchBtn);
//获取自定义属性个数
int N = ta.getIndexCount();
for (int i = 0; i < N; i++) {
<span style="white-space:pre"> </span>/*
<span style="white-space:pre"> </span> * 获得某个属性的ID值
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>int itemId = ta.getIndex(i);
<span style="white-space:pre"> </span>switch (itemId) {
<span style="white-space:pre"> </span>case R.styleable.MySwitchBtn_curr_state:
<span style="white-space:pre"> </span>currState = ta.getBoolean(itemId, false);//获取自定义属性value
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case R.styleable.<span style="font-family: Arial, Helvetica, sans-serif;">MySwitchBtn</span><span style="font-family: Arial, Helvetica, sans-serif;">_my_background:</span>
<span style="white-space:pre"> </span>backgroundId = ta.getResourceId(itemId, -1);//获取背景图片的id
<span style="white-space:pre"> </span>if(backgroundId == -1){
<span style="white-space:pre"> </span>throw new RuntimeException("请设置背景图片");
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>backgroundBitmap = BitmapFactory.decodeResource(getResources(), backgroundId);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>break;
<span style="white-space:pre"> </span>case R.styleable.MySwitchBtn_my_slide_btn:
<span style="white-space:pre"> </span>slideBtnId = ta.getResourceId(itemId, -1);//获取开关图片的id
<span style="white-space:pre"> </span><span style="font-family: Arial, Helvetica, sans-serif;">if(</span><span style="font-family: Arial, Helvetica, sans-serif;">slideBtnId </span><span style="font-family: Arial, Helvetica, sans-serif;">== -1){</span><span style="white-space:pre"></span><pre name="code" class="java"><span> </span>throw new RuntimeException("请设置背景图片");
<span> </span>}
slideBtn = BitmapFactory.decodeResource(getResources(), slideBtnId);
break;
default:
break;
}
}
这样的话我们就完成了这三个自定义控件属性的定义及获取解析。