【Android】自訂控制項實現可滑動的開關(switch),androidswitch
~轉載請註明來源:http://blog.csdn.net/u013015161/article/details/46704745
介紹
昨天晚上寫了一個Android的滑動開關, 即SlideSwitch。效果如下:
實現
實現的思路其實很簡單,監聽控制項上的touch事件,並不斷重新整理,讓滑塊在手指的位置上繪出,達到滑塊跟著手指滑動的顯示效果。
先看一下代碼:
SlideSwitch.java (7月3日有修改:在touch事件裡調用onStateChangedListener前增加判空)
package com.incell.view;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;public class SlideSwitch extends View{ private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); //消除鋸齒 boolean isOn = false; float curX = 0; float centerY; //y固定 float viewWidth; float radius; float lineStart; //直線段開始的位置(橫座標,即 float lineEnd; //直線段結束的位置(縱座標 float lineWidth; final int SCALE = 4; // 控制項長度為滑動的圓的半徑的倍數 OnStateChangedListener onStateChangedListener; public SlideSwitch(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } public SlideSwitch(Context context, AttributeSet attrs) { super(context, attrs); } public SlideSwitch(Context context) { super(context); } @Override public boolean onTouchEvent(MotionEvent event) { // TODO Auto-generated method stub curX = event.getX(); if(event.getAction() == MotionEvent.ACTION_UP) { if(curX > viewWidth / 2) { curX = lineEnd; if(false == isOn) { //只有狀態發生改變才調用回呼函數, 下同 if(null != onStateChangedListener) { onStateChangedListener.onStateChanged(true); } isOn = true; } } else { curX = lineStart; if(true == isOn) { if(null != onStateChangedListener) { onStateChangedListener.onStateChanged(false); } isOn = false; } } } /*通過重新整理調用onDraw*/ this.postInvalidate(); return true; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); /*保持寬是高的SCALE / 2倍, 即圓的直徑*/ this.setMeasuredDimension(this.getMeasuredWidth(), this.getMeasuredWidth() * 2 / SCALE); viewWidth = this.getMeasuredWidth(); radius = viewWidth / SCALE; lineWidth = radius * 2f; //直線寬度等於滑塊直徑 curX = radius; centerY = this.getMeasuredWidth() / SCALE; //centerY為高度的一半 lineStart = radius; lineEnd = (SCALE - 1) * radius; } @Override protected void onDraw(Canvas canvas) { // TODO Auto-generated method stub super.onDraw(canvas); /*限制滑動範圍*/ curX = curX > lineEnd?lineEnd:curX; curX = curX < lineStart?lineStart:curX; /*劃線*/ mPaint.setStyle(Paint.Style.STROKE); mPaint.setStrokeWidth(lineWidth); /*左邊部分的線,綠色*/ mPaint.setColor(Color.BLUE); canvas.drawLine(lineStart, centerY, curX, centerY, mPaint); /*右邊部分的線,灰色*/ mPaint.setColor(Color.GRAY); canvas.drawLine(curX, centerY, lineEnd, centerY, mPaint); /*畫圓*/ /*畫最左和最右的圓,直徑為直線段寬度, 即在直線段兩邊分別再加上一個半圓*/ mPaint.setStyle(Paint.Style.FILL); mPaint.setColor(Color.GRAY); canvas.drawCircle(lineEnd, centerY, lineWidth / 2, mPaint); mPaint.setColor(Color.BLUE); canvas.drawCircle(lineStart, centerY, lineWidth / 2, mPaint); /*圓形滑塊*/ mPaint.setColor(Color.LTGRAY); canvas.drawCircle(curX, centerY, radius , mPaint); } /*設定開關狀態改變監聽器*/ public void setOnStateChangedListener(OnStateChangedListener o) { this.onStateChangedListener = o; } /*內部介面,開關狀態改變監聽器*/ public interface OnStateChangedListener { public void onStateChanged(boolean state); }}
注釋應該很詳細了。主要有以下幾點。
1、重寫了onMeasure方法,使控制項高度依賴於控制項的寬度。這樣不論在布局檔案中如何設定,總能保證控制項的寬高比。
2、控制好滑塊的活動範圍
3、定義內部介面OnStateChangedListener,並在自訂控制項裡定義了其對象以及從外部賦值的方法setOnStateChangedListener,以便對開關狀態變更事件進行監聽並調用回調。
使用及Demo
在布局檔案中添加該控制項即可使用。Demo效果為動圖展示效果(demo裡顏色為綠色,動圖為藍色是因為綠色會導致截取gif時出問題,臨時更改的)。
Demo中布局檔案如下:
activity_main.xml:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <com.example.slideswitchexample.SlideSwitch android:id="@+id/slide_switch" android:layout_width="200dp" android:layout_height="wrap_content" android:layout_centerInParent="true"/></RelativeLayout>
Demo中Activity代碼如下:
MainActivity.java
package com.example.slideswitchexample;import com.example.slideswitchexample.SlideSwitch.OnStateChangedListener;import android.app.Activity;import android.os.Bundle;import android.widget.Toast;public class MainActivity extends Activity { SlideSwitch sSwitch; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sSwitch = (SlideSwitch) this.findViewById(R.id.slide_switch); sSwitch.setOnStateChangedListener(new OnStateChangedListener(){ @Override public void onStateChanged(boolean state) { // TODO Auto-generated method stub if(true == state) { Toast.makeText(MainActivity.this, "開關已開啟", 1000).show(); } else { Toast.makeText(MainActivity.this, "開關已關閉", 1000).show(); } } }); }}
點此下載Demo工程
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。