我们经常会看到非常多优秀的app上面都有一些非常美丽的控件,用户体验非常好。比方togglebutton就是一个非常好的样例,IOS系统以下那个精致的togglebutton现在在android以下也能够实现了,并且还能够自己定义它的颜色文字背景图,做出各种美丽的开关按键出来。

这里就用到了android里面一个比較经常使用的技术——自己定义控件。

先来看下我们实现的自己定义的togglebutton效果图:

    

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY3NyX3lhbmc=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="">

自己定义控件的步骤:

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的宽和高是非常easy得出来的,高度就是这个控件背景图的宽和高

      

所以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);
}

精巧状态的话,非常easy,依据不同的状态将滑块放置到控件的左边和右边就可以

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;
}

到这里,整个自定义togglebutton的过程就算完了。接下来我们就能够在程序中使用自定义的控件了。

在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

Demo下载

Android应用之——自己定义控件ToggleButton的更多相关文章

  1. Android经常使用自己定义控件(二)

           经常使用的Android自己定义控件分享 http://www.see-source.com//androidwidget/list.html?type=&p=1

  2. Android圆形图片--自己定义控件

    Android圆形图片控件效果图例如以下: 代码例如以下: RoundImageView.java package com.dxd.roundimageview; import android.con ...

  3. Android经常使用自己定义控件

    http://www.see-source.com/androidwidget/list.html

  4. Androd自己定义控件(三)飞翔的小火箭

    在前面的自己定义控件概述中已经跟大家分享了Android开发其中自己定义控件的种类. 今天跟大家分享一个非主流的组合控件. 我们在开发其中,难免须要在不同的场合中反复使用一些控件的组合.而Java的最 ...

  5. Android自定义控件1--自定义控件介绍

    Android控件基本介绍 Android本身提供了很多控件比如我们常用的有文本控件TextView和EditText:按钮控件Button和ImageButton状态开关按钮ToggleButton ...

  6. Android自己定义控件系列二:自己定义开关button(一)

    这一次我们将会实现一个完整纯粹的自己定义控件,而不是像之前的组合控件一样.拿系统的控件来实现.计划分为三部分:自己定义控件的基本部分,自己定义控件的触摸事件的处理和自己定义控件的自己定义属性: 以下就 ...

  7. Android自己定义控件之应用程序首页轮播图

    如今基本上大多数的Android应用程序的首页都有轮播图.就是像下图这种(此图为转载的一篇博文中的图.拿来直接用了): 像这种组件我相信大多数的应用程序都会使用到,本文就是自己定义一个这种组件,能够动 ...

  8. Android自己定义控件(状态提示图表)

    [工匠若水 http://blog.csdn.net/yanbober 转载烦请注明出处.尊重分享成果] 1 背景 前面分析那么多系统源代码了.也该暂停下来歇息一下,趁昨晚闲着看见一个有意思的需求就操 ...

  9. 【Android】自己定义控件——仿天猫Indicator

    今天来说说类似天猫的Banner中的小圆点是怎么做的(图中绿圈部分) 在学习自己定义控件之前,我用的是很二的方法,直接在布局中放入多个ImageView,然后代码中依据Pager切换来改变图片.这样的 ...

随机推荐

  1. 使用Aliyun Docker 容器镜像/注册表服务

    1.前往阿里云容器镜像服务创建相关资源. 2.登录你的仓库,账户名+公共地址 docker login --username=xxxxxxxxx@aliyun.com registry.cn-hang ...

  2. Keras简单使用

    Keras简单使用在keras中建立模型测试自己的图片一些有用的函数(持续更新) Keras简单使用 在keras中建立模型 相对于自己写机器学习相关的函数,keras更能快速搭建模型,流程如下: 通 ...

  3. 运维自动化-Ansible

    前言 天天说运维,究竟是干什么的?先看看工作流程呗.一般来说,运维工程师在一家企业里属于个位数的岗位,甚至只有一个.面对生产中NNN台服务器,NN个人员,工作量也是非常大的.所以嘛,图中的我好歹也会配 ...

  4. [Offer收割]编程练习赛33

    矩阵游戏II 把每列的数字加起来当一行处理.因为每次操作两列,所以最后最多剩下一个负数.如果负数的个数是偶数,直接所有数字的绝对值加起来即可:若负数个数为奇数,把所有数的绝对值加起来减去其中最小的绝对 ...

  5. (转)vue router 如何使用params query传参,以及有什么区别

    写在前面: 传参是前端经常需要用的一个操作,很多场景都会需要用到上个页面的参数,本文将会详细介绍vue router 是如何进行传参的,以及一些小细节问题.有需要的朋友可以做一下参考,喜欢的可以点波赞 ...

  6. javascript学习中自己对作用域和作用域链理解

    在javascript学习中作用域和作用域链还是相对难理解些,下面我关于javascript作用域和作用域链做一下详细介绍,给各位初学者答疑解惑. 首先我们介绍一下什么是作用域?  从字面上理解就是起 ...

  7. sql多表关联

    inner join(等值连接) 只返回两个表中联结字段相等的行 left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有 ...

  8. 8 Python+Selenium操作测试对象

    [环境信息] Python3.6+selenium3.0.2+Firefox50.0+win7 [操作方法] 1.清除输入框内容:clear() 2.单击一个按钮:click() 3.返回元素尺寸:s ...

  9. Ubuntu 16.04 安装python3.6 环境并设置为默认

    1.添加python3.6安装包,并且安装 sudo apt-get install software-properties-common 2.下载python3.6 sudo add-apt-rep ...

  10. JavaScript 事件对内存和性能的影响

    程序代码: <%-- Created by IntelliJ IDEA. User: 乔克叔叔 Date: 2017/12/26 Time: 16:45 To change this templ ...