天天看點

滑動開關按鈕SlideSwich

iphone上有開關控件,很漂亮,其實android4.0以後也有switch控件,但是隻能用在4.0以後的系統中,這就失去了其使用價值,而且我覺得它的界面也不是很好看。最近看到了百度魔拍上面的一個控件,覺得很漂亮啊,然後反編譯了下,盡管沒有混淆過,但是還是不好讀,然後就按照自己的想法寫了個,功能和百度魔拍類似。

下面是百度魔拍的效果和slideswitch的效果

滑動開關按鈕SlideSwich
滑動開關按鈕SlideSwich

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" />  

繼續閱讀