我们经常会看到很多优秀的app上面都有一些很漂亮的控件,用户体验非常好,比如togglebutton就是一个很好的例子,IOS系统下面那个精致的togglebutton如今在android下面也可以实现了,而且还可以自定义它的颜色文字背景图,做出各种漂亮的开关按键出来。这里就用到了android里面一个比较常用的技术——自定义控件。
先来看下我们实现的自定义的togglebutton效果图:
自定义控件的步骤:
1、首先,定义一个类继承View 或者View的子类,这个取决于要定义的控件的类型,本例中,继承自View。
2、继承了View后 就需要重写构造函数,有三个方法,分别是
public MyView(Context context) { super(context); // TODO Auto-generated constructor stub } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); // TODO Auto-generated constructor stub } public MyView(Context context, AttributeSet attrs) { super(context, attrs); // TODO Auto-generated constructor stub这三个方法,根据不同的情况来使用,如果自定义的控件需要设置xml属性那么就要用到第三个构造函数,如果需要设置xml属性并且定义样式,那么就需要实现第二个构造函数,使用其第三个参数defStyleAttr,如果没有以上两点要求,那么直接重写第一个构造函数即可。
这这个demo中,我们实现第一个构造函数即可
public ToggleButton(Context context, AttributeSet attrs) { super(context, attrs); initBitmap();//初始化bitmap }重写构造函数后,接下来就要根据不同控件的要求来选择是否重写onDraw和onMeasure方法了。
如果自定义控件的大小是需要自定义的,比如本例中的togglebutton,那么首先需要重写onMeasure方法,测算出自定义控件的宽和高。
很明显,我们这个togglebutton的宽和高是很容易得出来的,高度就是这个控件背景图的宽和高
所以onMeasure方法重写如下,得到自定义控件的宽和高
/** * 初始化开关图片 */ private void initBitmap() { background = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background); slideBackground = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button_background); }
/** * 设置当前控件的宽和高 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); // 设置开关的宽和高 setMeasuredDimension(background.getWidth(), background.getHeight()); }
得到宽和高后,就需要绘制这个控件了,利用View的onDraw方法
重写onDraw方法,我们可以得到一个参数canvas
void onDraw(Canvas canvas)有了这个canvas对象,就可以很方面的绘制出控件的样子
先绘制控件的背景,因为togglebutton,其实就是一个button在一个背景图上面来回滑动产生不同的效果,所以我们先绘制它的背景。
canvas.drawBitmap(background, 0, 0, null);绘制完背景后,就要绘制小滑块了。小滑块有两种状态,一种是在滑动,另一种是静止状态,这两种状态我们需要分别进行处理。
当小滑块在滑动的时候,背景图是不会变的,而且它滑动到某个时刻的样子也很明确,滑动了多少距离就绘制它在某距离的状态,但是有一种情况需要进行处理,那就是滑块滑出边界的情况,如果是从左边滑出边界,那么就应该将它离左边的距离置为0,也就是不让它继续滑动,同理右边也要进行相应的处理。
滑动过程代码如下:
if(isSliding) { // 正在滑动中 int left = currentX - slideBackground.getWidth() / 2; if(left < 0) { // 当前超出了左边界, 赋值为0 left = 0; } else if(left > (background.getWidth() - slideBackground.getWidth())) { // 当前超出了右边界, 赋值为: 背景的宽度 - 滑动块的宽度 left = background.getWidth() - slideBackground.getWidth(); } canvas.drawBitmap(slideBackground, left, 0, null); }静止状态的话,很容易,根据不同的状态将滑块放置到控件的左边和右边即可
if(currentState) { // 绘制开的状态 canvas.drawBitmap(slideBackground, 0, 0, null); } else { // 绘制关的状态 int left = background.getWidth() - slideBackground.getWidth(); canvas.drawBitmap(slideBackground, left, 0, null); }
上面,我们就完成了自定义一个togglebutton的界面上的操作了,但是togglebutton的作用是用来控制开关的,所以还要对它的一些事件进行处理。
滑动事件的处理,捕获用户的操作,为它设置一个自定义的状态改变监听器
/** * 捕获用户操作的事件 */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: currentX = (int) event.getX(); isSliding = true; break; case MotionEvent.ACTION_MOVE: currentX = (int) event.getX(); break; case MotionEvent.ACTION_UP: isSliding = false; currentX = (int) event.getX(); int center = background.getWidth() / 2; // 当前最新的状态 boolean state = currentX < center; // 如果两个状态不一样并且监听事件不为null if (currentState != state && mOnToggleStateChangeListener != null) { // 调用用户的回调事件 mOnToggleStateChangeListener.onToggleStateChange(state); } currentState = state; break; default: break; } invalidate(); // 此方法被调用会使onDraw方法重绘 return true; }
这里自定义了一个状态改变监听器,用来监听togglebutton的状态改变,然后回调方法,进行相应的处理。
public interface OnToggleStateChangeListener { void onToggleStateChange(boolean state); }
/** * 设置开关的状态 * * @param state */ public void setToggleState(boolean state) { currentState = state; } public boolean getToogleState() { return currentState; } public void setOnToggleStateChangeListener( OnToggleStateChangeListener listener) { mOnToggleStateChangeListener = listener; }
在xml文件中,用全路径名使用自定义控件,然后在java代码中就可以获取到这个自定义控件的对象 和相关的方法了
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.yang.togglebutton.ToggleButton android:id="@+id/togglebutton" android:layout_width="wrap_content" android:layout_height="30dip" android:layout_centerInParent="true" /> <com.yang.togglebutton.ToggleButtonVIPS android:id="@+id/toggle2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/togglebutton" android:layout_centerHorizontal="true" /> </RelativeLayout>
总结一下其实就是几个步骤:
1、继承View或者它的子类,根据不同的情况重写不同的构造函数(必须)
2、重写onMeasure方法,测量控件的大小(非必须)
3、重写onDraw方法,绘制控件(非必须)
4、为控件设置一些自定义方法和监听器(非必须)
5、在xml中使用,或者直接在java代码中使用
转载请注明出处http://blog.csdn.net/csr_yang/article/details/37341221