自定义滑动选择按钮

    在平时使用的手机的时候,我们经常会看到这样的按钮,用来改变某种状态,Android上叫ToggleButton,但是系统默认的按钮很难看。现在都流行滑动来改变状态,就像IOS上实现类似功能的按钮。最近在GitHub上看到了有个开源的项目,就研究了一下,实现了相同的功能,效果还是不错的。下面来介绍一下。


 实现这个按钮是使用了自定义View,关于自定义View,之前也写过几篇博客,今天算是用来练练手。废话不多说,先来分析一下,需要哪些自定义的属性

1.按钮的颜色

2.按钮的形状,分为圆形和矩形

3.按钮的状态,即开或者关

定义三个属性,color_themeshapeisOpen,贴一下XML文件

<resources>

    <attr name="themeColor" format="color" />
    <attr name="isOpen" format="boolean" />
    <attr name="shape" format="integer" />

    <declare-styleable name="SlideSwitch">
        <attr name="themeColor" />
        <attr name="isOpen" />
        <attr name="shape" />
    </declare-styleable>

</resources>

  然后来分析一下实现流程,首先OnMeasure,分为矩形和圆形,在OnDraw方法中进行绘制,首先先绘制一个backRect作为整个按钮的滑动背景,然后根据形状在backRect上面是绘制矩形还是圆形。对于手指移动时按钮跟着滑动,可以定义一个frontRect_left变量来改变按钮和背景左边的距离,从而实现滑动。下面来具体实现一下。

onMeasure

@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// TODO Auto-generated method stub
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
		int width = measureDimension(280,widthMeasureSpec);
		int height = measureDimension(140, heightMeasureSpec);
		if(shape == SHAPE_CIRCLE){
			if(width <height)
				width = height*2;
		}
		setMeasuredDimension(width, height);
		initDrawingVal();
	}
	private int measureDimension(int i, int widthMeasureSpec) {
		int result;
		int specMode = MeasureSpec.getMode(widthMeasureSpec);
		int specSize = MeasureSpec.getSize(widthMeasureSpec);
		if(specMode == MeasureSpec.EXACTLY){
			result =specSize;
		}else{
			result = i;
			if(specMode == MeasureSpec.AT_MOST){
				result = Math.min(result, specSize);
			}
		}
		return result;
	}

onDraw

一些初始化


private void initDrawingVal() {
		int width = getMeasuredWidth();
		int height= getMeasuredHeight();

		backRect = new Rect(0,0,width,height);
		min_left = RIM_SIZE;
		if(shape == SHAPE_RECT)
			max_left = width/2;
		else
			max_left = width-(height-2*RIM_SIZE);

		if(isOpen){
			frontRect_left = max_left;
			alpha =255;
		}else{
			frontRect_left = RIM_SIZE;
			alpha=0;
		}
		frontRect_left_begin = frontRect_left;
	}

@Override
	protected void onDraw(Canvas canvas) {
		if(shape == SHAPE_RECT){
			paint.setColor(Color.GRAY);
			canvas.drawRect(backRect, paint);
			paint.setColor(color_theme);
			paint.setAlpha(alpha);
			canvas.drawRect(backRect, paint);

			frontRect = new Rect(frontRect_left,RIM_SIZE,frontRect_left+getMeasuredWidth()/2,getMeasuredHeight()-RIM_SIZE);
			paint.setColor(Color.WHITE);
			canvas.drawRect(frontRect, paint);
		}else{
			//圆形
			int radius;
			radius = backRect.height()/2-RIM_SIZE;
			paint.setColor(Color.GRAY);
			canvas.drawRoundRect(new RectF(backRect), radius, radius, paint);
			paint.setColor(color_theme);
			paint.setAlpha(alpha);
			canvas.drawRoundRect(new RectF(backRect), radius, radius, paint);

			frontRect = new Rect(frontRect_left, RIM_SIZE, frontRect_left+backRect.height()-2*RIM_SIZE, backRect.height()-RIM_SIZE);
			paint.setColor(Color.WHITE);

			canvas.drawRoundRect(new RectF(frontRect), radius, radius, paint);
		}
	}

监听onTouch事件

@Override
	public boolean onTouchEvent(MotionEvent event) {
		int action = event.getAction();
		switch (action) {
		case MotionEvent.ACTION_DOWN:
			eventStartX = (int)event.getRawX();
			break;
		case MotionEvent.ACTION_MOVE:
			eventLastX = (int)event.getRawX();
			diffX = eventLastX-eventStartX;
			int tem = diffX+frontRect_left_begin;
			tem = (tem>max_left?max_left:tem);
			tem = tem<min_left?min_left:tem;
			if(tem >=min_left&&tem<=max_left){
				frontRect_left = tem;
				alpha = (int)(255*(float)tem/(float)max_left);
				invalidateView();
			}
			break;
		case MotionEvent.ACTION_UP:
			int wholeX = (int)(event.getX()-eventStartX);
			frontRect_left_begin = frontRect_left;
			boolean toRight = frontRect_left>max_left/2?true:false;
			//点击事件,改变状态
			if(Math.abs(wholeX)<3){
				toRight =!toRight;
			}
			moveToDest(toRight);
			break;
		}
		return true;
	}

当我们手指up的时候,滑块需要自己滑动到制定是位置并且动态的改变alpha,可以开一个线程,动态的改变frontRect_left实现,并通过handle来通知listener改变。

private void moveToDest(final boolean toRight) {
		final Handler handler = new Handler(){

			@Override
			public void handleMessage(Message msg) {
				if(msg.what ==1){
					listener.open();
				}else{
					listener.close();
				}
			}
		};

		new Thread(new Runnable() {

			@Override
			public void run() {
				if(toRight){
					while(frontRect_left <=max_left){
						alpha = (int)(255*(float)frontRect_left/(float)max_left);
						invalidateView();
						frontRect_left+=3;
						try {
							Thread.sleep(3);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					alpha = 255;
					frontRect_left = max_left;
					isOpen = true;
					if(listener !=null)
						handler.sendEmptyMessage(1);
					frontRect_left_begin = max_left;

				}else{
					while(frontRect_left >=min_left){
						alpha = (int)(255*(float)frontRect_left/(float)max_left);
						invalidateView();
						frontRect_left -=3;
						try {
							Thread.sleep(3);
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					alpha = 0;
					frontRect_left = min_left;
					isOpen = false;
					if(listener!=null)
						handler.sendEmptyMessage(0);
					frontRect_left_begin = min_left;
				}

			}
		})
		.start();

	}

然后暴漏出几个方法给外部调用。

public void setState(boolean isopen){
		this.isOpen = isopen;
		invalidateView();
		initDrawingVal();
		if(listener!=null){
			listener.open();
		}else{
			listener.close();
		}
	}
	public void setShapeType(int shapeType){
		this.shape = shapeType;
	}

再定义一个listener来监听状态的改变


public interface SlideListener{
		public void open();
		public void close();
	}
public void setSlideListener(SlideListener listener){
		this.listener = listener;
	}

最后贴一下mainactivity的代码

public class MainActivity extends Activity implements SlideListener {

	TextView txt;
	SlideSwitch slide;
	SlideSwitch slide2;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		slide = (SlideSwitch) findViewById(R.id.swit);
		slide2 = (SlideSwitch) findViewById(R.id.swit2);

		slide.setState(false);
		txt = (TextView) findViewById(R.id.txt);
		slide.setSlideListener(this);
	}

	@Override
	public void open() {
		// TODO Auto-generated method stub
		txt.setText(" is opend ");
	}

	@Override
	public void close() {
		// TODO Auto-generated method stub
		txt.setText(" is close ");
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值