iphone上有开关控件,很漂亮,其实androID4.0以后也有switch控件,但是只能用在4.0以后的系统中,这就失去了其使用价值,而且我觉得它的界面也不是很好看。最近看到了百度魔拍上面的一个控件,觉得很漂亮啊,然后反编译了下,尽管没有混淆过,但是还是不好读,然后就按照自己的想法写了个,功能和百度魔拍类似。
下面是百度魔拍的效果和SlIDeSwitch的效果
一、原理
继承自vIEw类,overrIDe其onDraw函数,把两个背景图(一个灰的一个红的)和一个开关图(圆开关)通过canvas画出来;同时overrIDe其ontouchEvent函数,实现滑动效果;最后开启一个线程做动画,实现缓慢滑动的效果。
二、代码
SlIDeSwitch.java
package com.example.hellojni; import androID.content.Context; import androID.content.res.Resources; import androID.graphics.Bitmap; import androID.graphics.BitmapFactory; import androID.graphics.Canvas; import androID.graphics.color; import androID.graphics.Paint; import androID.graphics.Rect; import androID.graphics.Typeface; import androID.util.AttributeSet; import androID.util.Log; import androID.vIEw.MotionEvent; import androID.vIEw.VIEw; import androID.vIEw.VIEwGroup.LayoutParams; /** * SlIDeSwitch 仿iphone滑动开关组件,仿百度魔图滑动开关组件 * 组件分为三种状态:打开、关闭、正在滑动<br/> * 使用方法: * <pre>SlIDeSwitch slIDeSwitch = new SlIDeSwitch(this); *slIDeSwitch.setonSwitchChangedListener(onSwitchChangedListener); *linearLayout.addVIEw(slIDeSwitch); </pre> 注:也可以加载在xml里面使用 * @author scott * */ public class SlIDeSwitch extends VIEw { public static final String TAG = "SlIDeSwitch"; public static final int SWITCH_OFF = 0;//关闭状态 public static final int SWITCH_ON = 1;//打开状态 public static final int SWITCH_SCROliNG = 2;//滚动状态 //用于显示的文本 private String mOnText = "打开"; private String mOffText = "关闭"; private int mSwitchStatus = SWITCH_OFF; private boolean mHasScrolled = false;//表示是否发生过滚动 private int mSrcX = 0,mdstX = 0; private int mBmpWIDth = 0; private int mBmpHeight = 0; private int mThumbWIDth = 0; private Paint mPaint = new Paint(Paint.ANTI_AliAS_FLAG); private OnSwitchChangedListener mOnSwitchChangedListener = null; //开关状态图 Bitmap mSwitch_off,mSwitch_on,mSwitch_thumb; public SlIDeSwitch(Context context) { this(context,null); } public SlIDeSwitch(Context context,AttributeSet attrs) { super(context,attrs); init(); } public SlIDeSwitch(Context context,AttributeSet attrs,int defStyle) { super(context,attrs,defStyle); init(); } //初始化三幅图片 private voID init() { Resources res = getResources(); mSwitch_off = BitmapFactory.decodeResource(res,R.drawable.bg_switch_off); mSwitch_on = BitmapFactory.decodeResource(res,R.drawable.bg_switch_on); mSwitch_thumb = BitmapFactory.decodeResource(res,R.drawable.switch_thumb); mBmpWIDth = mSwitch_on.getWIDth(); mBmpHeight = mSwitch_on.getHeight(); mThumbWIDth = mSwitch_thumb.getWIDth(); } @OverrIDe public voID setLayoutParams(LayoutParams params) { params.wIDth = mBmpWIDth; params.height = mBmpHeight; super.setLayoutParams(params); } /** * 为开关控件设置状态改变监听函数 * @param onSwitchChangedListener 参见 {@link OnSwitchChangedListener} */ public voID setonSwitchChangedListener(OnSwitchChangedListener onSwitchChangedListener) { mOnSwitchChangedListener = onSwitchChangedListener; } /** * 设置开关上面的文本 * @param onText 控件打开时要显示的文本 * @param offText 控件关闭时要显示的文本 */ public voID setText(final String onText,final String offText) { mOnText = onText; mOffText =offText; invalIDate(); } /** * 设置开关的状态 * @param on 是否打开开关 打开为true 关闭为false */ public voID setStatus(boolean on) { mSwitchStatus = ( on ? SWITCH_ON : SWITCH_OFF); } @OverrIDe public boolean ontouchEvent(MotionEvent event) { int action = event.getAction(); Log.d(TAG,"ontouchEvent x=" + event.getX()); switch (action) { case MotionEvent.ACTION_DOWN: mSrcX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: mdstX = Math.max( (int) event.getX(),10); mdstX = Math.min( mdstX,62); if(mSrcX == mdstX) return true; mHasScrolled = true; AnimationTransRunnable aTransRunnable = new AnimationTransRunnable(mSrcX,mdstX,0); new Thread(aTransRunnable).start(); mSrcX = mdstX; break; case MotionEvent.ACTION_UP: if(mHasScrolled == false)//如果没有发生过滑动,就意味着这是一次单击过程 { mSwitchStatus = Math.abs(mSwitchStatus-1); int xFrom = 10,xTo = 62; if(mSwitchStatus == SWITCH_OFF) { xFrom = 62; xTo = 10; } AnimationTransRunnable runnable = new AnimationTransRunnable(xFrom,xTo,1); new Thread(runnable).start(); } else { invalIDate(); mHasScrolled = false; } //状态改变的时候 回调事件函数 if(mOnSwitchChangedListener != null) { mOnSwitchChangedListener.onSwitchChanged(this,mSwitchStatus); } break; default: break; } return true; } @OverrIDe protected voID onSizeChanged(int w,int h,int olDW,int oldh) { super.onSizeChanged(w,h,olDW,oldh); } @OverrIDe protected voID onDraw(Canvas canvas) { super.onDraw(canvas); //绘图的时候 内部用到了一些数值的硬编码,其实不太好, //主要是考虑到图片的原因,图片周围有透明边界,所以要有一定的偏移 //硬编码的数值只要看懂了代码,其实可以理解其含义,可以做相应改进。 mPaint.setTextSize(14); mPaint.setTypeface(Typeface.DEFAulT_BolD); if(mSwitchStatus == SWITCH_OFF) { drawBitmap(canvas,null,mSwitch_off); drawBitmap(canvas,mSwitch_thumb); mPaint.setcolor(color.rgb(105,105,105)); canvas.translate(mSwitch_thumb.getWIDth(),0); canvas.drawText(mOffText,20,mPaint); } else if(mSwitchStatus == SWITCH_ON) { drawBitmap(canvas,mSwitch_on); int count = canvas.save(); canvas.translate(mSwitch_on.getWIDth() - mSwitch_thumb.getWIDth(),0); drawBitmap(canvas,mSwitch_thumb); mPaint.setcolor(color.WHITE); canvas.restoretoCount(count); canvas.drawText(mOnText,17,mPaint); } else //SWITCH_SCROliNG { mSwitchStatus = mdstX > 35 ? SWITCH_ON : SWITCH_OFF; drawBitmap(canvas,new Rect(0,mBmpHeight),(int)mdstX,mSwitch_on); mPaint.setcolor(color.WHITE); canvas.drawText(mOnText,mPaint); int count = canvas.save(); canvas.translate(mdstX,new Rect(mdstX,mBmpWIDth,mBmpWIDth - mdstX,mSwitch_off); canvas.restoretoCount(count); count = canvas.save(); canvas.clipRect(mdstX,mBmpHeight); canvas.translate(mThumbWIDth,0); mPaint.setcolor(color.rgb(105,105)); canvas.drawText(mOffText,mPaint); canvas.restoretoCount(count); count = canvas.save(); canvas.translate(mdstX - mThumbWIDth / 2,mSwitch_thumb); canvas.restoretoCount(count); } } public voID drawBitmap(Canvas canvas,Rect src,Rect dst,Bitmap bitmap) { dst = (dst == null ? new Rect(0,bitmap.getWIDth(),bitmap.getHeight()) : dst); Paint paint = new Paint(); canvas.drawBitmap(bitmap,src,dst,paint); } /** * AnimationTransRunnable 做滑动动画所使用的线程 */ private class AnimationTransRunnable implements Runnable { private int srcX,dstX; private int duration; /** * 滑动动画 * @param srcX 滑动起始点 * @param dstX 滑动终止点 * @param duration 是否采用动画,1采用,0不采用 */ public AnimationTransRunnable(float srcX,float dstX,final int duration) { this.srcX = (int)srcX; this.dstX = (int)dstX; this.duration = duration; } @OverrIDe public voID run() { final int patch = (dstX > srcX ? 5 : -5); if(duration == 0) { SlIDeSwitch.this.mSwitchStatus = SWITCH_SCROliNG; SlIDeSwitch.this.postInvalIDate(); } else { Log.d(TAG,"start Animation: [ " + srcX + "," + dstX + " ]"); int x = srcX + patch; while (Math.abs(x-dstX) > 5) { mdstX = x; SlIDeSwitch.this.mSwitchStatus = SWITCH_SCROliNG; SlIDeSwitch.this.postInvalIDate(); x += patch; try { Thread.sleep(10); } catch (InterruptedException e) { e.printstacktrace(); } } mdstX = dstX; SlIDeSwitch.this.mSwitchStatus = mdstX > 35 ? SWITCH_ON : SWITCH_OFF; SlIDeSwitch.this.postInvalIDate(); } } } public static interface OnSwitchChangedListener { /** * 状态改变 回调函数 * @param status SWITCH_ON表示打开 SWITCH_OFF表示关闭 */ public abstract voID onSwitchChanged(SlIDeSwitch obj,int status); } }
layout xml
<?xml version="1.0" enCoding="utf-8"?> <linearLayout xmlns:androID="http://schemas.androID.com/apk/res/androID" androID:layout_wIDth="fill_parent" androID:layout_height="fill_parent" androID:background="#fdfdfd" androID:orIEntation="vertical" androID:paddingleft="10dip" androID:paddingRight="10dip" > <ImageVIEw androID:ID="@+ID/imageVIEw1" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:src="@drawable/top" /> <relativeLayout androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" > <TextVIEw androID:ID="@+ID/textVIEw1" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_alignParentleft="true" androID:layout_centerVertical="true" androID:text="网络构图" androID:textSize="15sp" /> <com.example.hellojni.SlIDeSwitch androID:ID="@+ID/slIDeSwitch1" androID:layout_wIDth="116dip" androID:layout_height="46dip" androID:layout_alignParentRight="true" androID:layout_centerVertical="true" /> </relativeLayout> <relativeLayout androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" > <TextVIEw androID:ID="@+ID/textVIEw2" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_alignParentleft="true" androID:layout_centerVertical="true" androID:text="保留原图" androID:textSize="15sp" /> <com.example.hellojni.SlIDeSwitch androID:ID="@+ID/slIDeSwitch2" androID:layout_wIDth="116dip" androID:layout_height="46dip" androID:layout_alignParentRight="true" androID:layout_centerVertical="true" /> </relativeLayout> <relativeLayout androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" > <TextVIEw androID:ID="@+ID/textVIEw3" androID:layout_wIDth="wrap_content" androID:layout_height="wrap_content" androID:layout_alignParentleft="true" androID:layout_centerVertical="true" androID:text="拍照声音" androID:textSize="15sp" /> <com.example.hellojni.SlIDeSwitch androID:ID="@+ID/slIDeSwitch3" androID:layout_wIDth="116px" androID:layout_height="46px" androID:layout_alignParentRight="true" androID:layout_centerVertical="true" /> </relativeLayout> <TextVIEw androID:ID="@+ID/textVIEwTip" androID:layout_wIDth="fill_parent" androID:layout_height="wrap_content" androID:gravity="center" androID:text="TextVIEw" /> </linearLayout>
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
总结以上是内存溢出为你收集整理的android自定义开关控件-SlideSwitch的实例全部内容,希望文章能够帮你解决android自定义开关控件-SlideSwitch的实例所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)