您的位置:首页 > 移动开发 > Android开发

自定义view_开关按钮

2015-05-24 23:46 323 查看
注:源自传智播客视频教程

现整理此案例,以供日后自己或大家学习、参考:

android自定义view实现的简单demo

实现效果:





1.点击按钮可以改变开关的状态

2.拖动按钮可以改变开关的状态

此为完整代码下载链接:

http://download.csdn.net/detail/wang725/8734937

1.新建一个实现View的MyToggleButton类

<pre name="code" class="java">package com.example.togglebtn;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;

public class MyToggleButton extends View implements OnClickListener {

/**
* 作为背景的图片
*/
private Bitmap backgroudBitmap;

/**
* 可以滑动的图片
*/
private Bitmap slideBtm;

private Paint paint;

/**
* 滑动按钮的左边值
*/
private float slideBtn_left;

/**
* @param context
* @param attrs
* @param defStyleAttr
*/
public MyToggleButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// TODO Auto-generated constructor stub
}

/**
* 在布局文件中声明的view,创建时系统自动调用
* @param context
* @param attrs
*/
public MyToggleButton(Context context, AttributeSet attrs) {
super(context, attrs);
// TODO Auto-generated constructor stub
}

/**
* 在代码里面创建对象的时候使用此构造方法
* @param context
*/
public MyToggleButton(Context context) {
super(context);
// TODO Auto-generated constructor stub
}

/**
* view对象显示在屏幕上 有几个重要步骤
* 1、构造方法创建对象
* 2、测量view的大小 onMeasure
* 3、确定view的位置,view自身有一些建议权,决定权在父view手中 onLayout();
* 4、绘制view的内容 onDraw(Canvas);
*/

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
initView();
/**
* 设置当前view的大小
* width : 当前view的宽度(单位:像素)
* height : 当前view的高度(单位:像素)
*/
setMeasuredDimension(backgroudBitmap.getWidth(), backgroudBitmap.getHeight());
}

/**
* 自定义view的时候 作用不大
* 确定位置的时候调用此方法
*/
//	@Override
//	protected void onLayout(boolean changed, int left, int top, int right,
//			int bottom) {
//		super.onLayout(changed, left, top, right, bottom);
//	}

/**
* 当前开关状态
*/
private boolean currentState = false;

/**
* 绘制当前view的内容
*/
@Override
protected void onDraw(Canvas canvas) {
//		super.onDraw(canvas);
// 绘制背景
/**
* backgroundBitmap 要绘制的图片
* left 图片的左边界
* top 图片的上边届
* paint 绘制图片使用的画笔
*/
canvas.drawBitmap(backgroudBitmap, 0, 0, paint);
// 绘制可滑动的按钮
canvas.drawBitmap(slideBtm, slideBtn_left, 0, paint);
}

/**
* 初始化
*/
private void initView() {
backgroudBitmap  = BitmapFactory.decodeResource(getResources(), R.drawable.switch_background);
slideBtm = BitmapFactory.decodeResource(getResources(), R.drawable.slide_button);

// 画笔
paint = new Paint();
paint.setAntiAlias(true);// 打开抗锯齿

// 添加点击事件监听
setOnClickListener(this);
}

/**
* 判断是否发生拖动
* 若拖动了,就不再响应onlick事件
*/
private boolean isDrag = false;

/**
* 点击事件
* onclick事件在view.onTouchEvent事件中被解析
* 系统对onclick事件的解析 过于简陋 只要有down时间 和 up事件 系统即认为发生了click事件
*/
@Override
public void onClick(View v) {
// 若果没有拖动才执行改变状态的动作
if(!isDrag) {
currentState = !currentState;
flushState();
}
}

/**
* 刷新当前状态
*/
private void flushState() {
if(currentState) {
slideBtn_left = backgroudBitmap.getWidth() -  slideBtm.getWidth();
} else {
slideBtn_left = 0;
}
/**
* 刷新当前view 会导致onDraw方法的执行
* Invalidate the whole view. If the view is visible,
*	onDraw(android.graphics.Canvas) will be called at some point in the future. This must be called from a UI thread.
*	To call from a non-UI thread, call postInvalidate().
*/
invalidate();
}

/**
* down 事件时的x值
*/
private int firstX;

/**
* touch 事件的上一个x的值
*/
private int lastX;

@Override
public boolean onTouchEvent(MotionEvent event) {
super.onTouchEvent(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
firstX = lastX = (int) event.getX();
isDrag =false;
break;

case MotionEvent.ACTION_MOVE:
// 判断是否发生拖动
if(Math.abs(event.getX() - firstX) > 5) {
isDrag = true;
}

// 计算手指在屏幕上移动的距离
int dis = (int) (event.getX() - lastX);
// 将本次的位置 设置给lastX
lastX = (int) event.getX();
//			if(lastX >= backgroudBitmap.getWidth() - )

// 根据手指移动的距离,改变图片slideBtn_left的位置
slideBtn_left = slideBtn_left + dis;
break;
case MotionEvent.ACTION_UP:
// 在发生拖动的情况下,根据最后的位置,判断当前开关的状态
if(isDrag) {
if(slideBtn_left > (backgroudBitmap.getWidth() - slideBtm.getWidth())/2) {
slideBtn_left = backgroudBitmap.getWidth() - slideBtm.getWidth();
currentState = true;
} else {
slideBtn_left = 0;
currentState = false;
}
}
break;
default:
break;
}
flushView();
return true;
}

/**
* 刷新当前view
*/
private void flushView() {
/**
* 对slideBtn_left 的值进行判断,确保其在河里的位置  0 <= slideBtn_left <= maxLeft
*/
int maxLeft = backgroudBitmap.getWidth() - slideBtm.getWidth();
// 1 确保slideBtn_left 大于0
slideBtn_left = (slideBtn_left>0)?slideBtn_left:0;
// 2 确保slideBtn_left 小于 maxLeft
slideBtn_left = (slideBtn_left<maxLeft)?slideBtn_left:maxLeft;
// 刷新当前视图 导致 onDraw方法执行
invalidate();
}
}



2.activity_main.xml,在不居中引用自定义的view

<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"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.togglebtn.MainActivity" >

<com.example.togglebtn.MyToggleButton
android:id="@+id/mytogglebtn"
android:layout_centerInParent="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>

</RelativeLayout>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息