iphone上有開關控件,很漂亮,其實android4.0以後也有switch控件,但是隻能用在4.0以後的系統中,這就失去了其使用價值,而且我覺得它的界面也不是很好看。最近看到了百度魔拍上面的一個控件,覺得很漂亮啊,然後反編譯了下,盡管沒有混淆過,但是還是不好讀,然後就按照自己的想法寫了個,功能和百度魔拍類似。
下面是百度魔拍的效果和slideswitch的效果
apk下載下傳位址:http://home.ustc.edu.cn/~voa/res/hellojni.apk
繼承自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);
//初始化三幅圖檔
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);
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;
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);
default:
}
return true;
protected void onsizechanged(int w, int h, int oldw, int oldh)
super.onsizechanged(w, h, oldw, oldh);
protected void ondraw(canvas canvas)
super.ondraw(canvas);
//繪圖的時候 内部用到了一些數值的寫死,其實不太好,
//主要是考慮到圖檔的原因,圖檔周圍有透明邊界,是以要有一定的偏移
//寫死的數值隻要看懂了代碼,其實可以了解其含義,可以做相應改進。
mpaint.settextsize(14);
mpaint.settypeface(typeface.default_bold);
if(mswitchstatus == switch_off)
{
drawbitmap(canvas, null, null, mswitch_off);
drawbitmap(canvas, null, null, mswitch_thumb);
mpaint.setcolor(color.rgb(105, 105, 105));
canvas.translate(mswitch_thumb.getwidth(), 0);
canvas.drawtext(mofftext, 0, 20, mpaint);
else if(mswitchstatus == switch_on)
drawbitmap(canvas, null, null, mswitch_on);
int count = canvas.save();
canvas.translate(mswitch_on.getwidth() - mswitch_thumb.getwidth(), 0);
mpaint.setcolor(color.white);
canvas.restoretocount(count);
canvas.drawtext(montext, 17, 20, mpaint);
else //switch_scroling
mswitchstatus = mdstx > 35 ? switch_on : switch_off;
drawbitmap(canvas, new rect(0, 0, mdstx, mbmpheight), new rect(0, 0, (int)mdstx, mbmpheight), mswitch_on);
canvas.translate(mdstx, 0);
drawbitmap(canvas, new rect(mdstx, 0, mbmpwidth, mbmpheight),
new rect(0, 0, mbmpwidth - mdstx, mbmpheight), mswitch_off);
count = canvas.save();
canvas.cliprect(mdstx, 0, mbmpwidth, mbmpheight);
canvas.translate(mthumbwidth, 0);
canvas.translate(mdstx - mthumbwidth / 2, 0);
public void drawbitmap(canvas canvas, rect src, rect dst, bitmap bitmap)
dst = (dst == null ? new rect(0, 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();
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;
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_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>
android:id="@+id/textview2"
android:text="保留原圖"
android:id="@+id/slideswitch2"
android:id="@+id/textview3"
android:text="拍照聲音"
android:id="@+id/slideswitch3"
android:layout_width="116px"
android:layout_height="46px"
<textview
android:id="@+id/textviewtip"
android:gravity="center"
android:text="textview" />