android自定義開關控制元件-SlideSwitch
轉自:http://blog.csdn.net/singwhatiwanna/article/details/9254309
1.效果
iphone上有開關控制元件,很漂亮,其實android4.0以後也有switch控制元件,但是隻能用在4.0以後的系統中,這就失去了其使用價值,而且我覺得它的介面也不是很好看。最近看到了百度魔拍上面的一個控制元件,覺得很漂亮啊,然後反編譯了下,儘管沒有混淆過,但是還是不好讀,然後就按照自己的想法寫了個,功能和百度魔拍類似。
下面是百度魔拍的效果和SlideSwitch的效果
apk下載地址:http://home.ustc.edu.cn/~voa/res/HelloJni.apk
2.原理
繼承自view類,override其onDraw函式,把兩個背景圖(一個灰的一個紅的)和一個開關圖(圓開關)通過canvas畫出來;同時override其onTouchEvent函式,實現滑動效果;最後開啟一個執行緒做動畫,實現緩慢滑動的效果。
3. 程式碼
//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, 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);
- drawBitmap(canvas, null, null, mSwitch_thumb);
- 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);
- mPaint.setColor(Color.WHITE);
- canvas.drawText(mOnText, 17, 20, mPaint);
- int count = canvas.save();
- canvas.translate(mDstX, 0);
- drawBitmap(canvas, new Rect(mDstX, 0, mBmpWidth, mBmpHeight),
- new Rect(0, 0, mBmpWidth - mDstX, mBmpHeight), mSwitch_off);
- canvas.restoreToCount(count);
- count = canvas.save();
- canvas.clipRect(mDstX, 0, mBmpWidth, mBmpHeight);
- canvas.translate(mThumbWidth, 0);
- mPaint.setColor(Color.rgb(105, 105, 105));
- canvas.drawText(mOffText, 0, 20, mPaint);
- canvas.restoreToCount(count);
- count = canvas.save();
- canvas.translate(mDstX - mThumbWidth / 2, 0);
- drawBitmap(canvas, null, null, mSwitch_thumb);
- canvas.restoreToCount(count);
- }
- }
- 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();
- }
- 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);
- }
- }
- <?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自定義控制元件——自定義屬性Android控制元件
- Android自定義控制元件之自定義組合控制元件Android控制元件
- Qt自定義開關按鈕控制元件QT控制元件
- Android自定義控制元件之自定義屬性Android控制元件
- C#自定義控制元件—轉換開關C#控制元件
- android:建立自定義控制元件Android控制元件
- (Android自定義控制元件)Android自定義狀態提示圖表Android控制元件
- Android自定義組合控制元件之自定義屬性Android控制元件
- 【Android】自定義樹形控制元件Android控制元件
- android 自定義控制元件 自定義屬性詳細介紹Android控制元件
- Android 自定義實現switch開關按鈕Android
- Android右滑關閉Activity介面功能-自定義控制元件實現Android控制元件
- Android自定義控制元件之自定義ViewGroup實現標籤雲Android控制元件View
- Android開發之自定義隨機驗證碼控制元件Android隨機控制元件
- Android 自定義輪播圖片控制元件Android控制元件
- Android自定義下拉重新整理控制元件Android控制元件
- Android圓形圖片--自定義控制元件Android控制元件
- Android 控制元件架構與自定義控制元件詳解Android控制元件架構
- Android 自定義Switch開關按鈕的樣式Android
- 從Android到ReactNative開發(三、自定義原生控制元件支援)AndroidReact控制元件
- Android 從0開始自定義控制元件之 ViewRoot 與 DecorView (五)Android控制元件View
- Android開發自定義控制元件實現一個餅狀圖Android控制元件
- Android開發自定義控制元件實現一個折線圖Android控制元件
- 自定義view————開關buttonView
- Android自定義控制元件 帶文字提示的SeekBarAndroid控制元件
- Android自定義多宮格解鎖控制元件Android控制元件
- Android自定義View--翻書控制元件(一)AndroidView控制元件
- Android自定義控制元件之基本原理Android控制元件
- Android自定義控制元件系列之基礎篇Android控制元件
- Android自定義控制元件模仿iOS滑塊SwitchButtonAndroid控制元件iOS
- 自定義Switch控制元件控制元件
- 自定義控制元件ViewPager控制元件Viewpager
- 控制元件自定義位置控制元件
- 如何自定義控制元件控制元件
- 從 Android 到 React Native 開發(三、自定義原生控制元件支援)AndroidReact Native控制元件
- 4. 自定義控制元件(4) --- 自定義屬性控制元件
- Android 自定義控制元件 ViewPager頭部指示器控制元件 ViewPagerBelowIndicatorAndroid控制元件ViewpagerIndicator
- 【組合控制元件】android自定義控制元件之帶文字的ImageView控制元件AndroidView