您的位置:首页 > 移动开发 > Android开发

Android实战简易教程<四十五>(SlideSwitch-好看又实用的开关按钮)

2015-09-26 11:23 645 查看
开关按钮也是在项目中经常用到的控件,github上有开源的项目,我们研究下它的使用方法:

1.SlideButton.java:

[java] view
plaincopy

/*

* Copyright (C) 2015 Quinn Chen

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package com.leaking.slideswitch;



import android.animation.Animator;

import android.animation.AnimatorListenerAdapter;

import android.animation.ValueAnimator;

import android.animation.ValueAnimator.AnimatorUpdateListener;

import android.content.Context;

import android.content.res.TypedArray;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.graphics.Rect;

import android.graphics.RectF;

import android.os.Bundle;

import android.os.Looper;

import android.os.Parcelable;

import android.support.v4.view.MotionEventCompat;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.view.View;

import android.view.animation.AccelerateDecelerateInterpolator;



import com.example.slideswitch.R;



public class SlideSwitch extends View {



public static final int SHAPE_RECT = 1;

public static final int SHAPE_CIRCLE = 2;

private static final int RIM_SIZE = 6;

private static final int DEFAULT_COLOR_THEME = Color.parseColor("#ff00ee00");

// 3 attributes

private int color_theme;

private boolean isOpen;

private int shape;

// varials of drawing

private Paint paint;

private Rect backRect;

private Rect frontRect;

private RectF frontCircleRect;

private RectF backCircleRect;

private int alpha;

private int max_left;

private int min_left;

private int frontRect_left;

private int frontRect_left_begin = RIM_SIZE;

private int eventStartX;

private int eventLastX;

private int diffX = 0;

private boolean slideable = true;

private SlideListener listener;



public interface SlideListener {

public void open();



public void close();

}



public SlideSwitch(Context context, AttributeSet attrs, int defStyleAttr) {

super(context, attrs, defStyleAttr);

listener = null;

paint = new Paint();

paint.setAntiAlias(true);

TypedArray a = context.obtainStyledAttributes(attrs,

R.styleable.slideswitch);

color_theme = a.getColor(R.styleable.slideswitch_themeColor,

DEFAULT_COLOR_THEME);

isOpen = a.getBoolean(R.styleable.slideswitch_isOpen, false);

shape = a.getInt(R.styleable.slideswitch_shape, SHAPE_RECT);

a.recycle();

}



public SlideSwitch(Context context, AttributeSet attrs) {

this(context, attrs, 0);

}



public SlideSwitch(Context context) {

this(context, null);

}



@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int width = measureDimension(280, widthMeasureSpec);

int height = measureDimension(140, heightMeasureSpec);

if (shape == SHAPE_CIRCLE) {

if (width < height)

width = height * 2;

}

setMeasuredDimension(width, height);

initDrawingVal();

}



public void initDrawingVal() {

int width = getMeasuredWidth();

int height = getMeasuredHeight();



backCircleRect = new RectF();

frontCircleRect = new RectF();

frontRect = new Rect();

backRect = new Rect(0, 0, width, height);

min_left = RIM_SIZE;

if (shape == SHAPE_RECT)

max_left = width / 2;

else

max_left = width - (height - 2 * RIM_SIZE) - RIM_SIZE;

if (isOpen) {

frontRect_left = max_left;

alpha = 255;

} else {

frontRect_left = RIM_SIZE;

alpha = 0;

}

frontRect_left_begin = frontRect_left;

}



public int measureDimension(int defaultSize, int measureSpec) {

int result;

int specMode = MeasureSpec.getMode(measureSpec);

int specSize = MeasureSpec.getSize(measureSpec);

if (specMode == MeasureSpec.EXACTLY) {

result = specSize;

} else {

result = defaultSize; // UNSPECIFIED

if (specMode == MeasureSpec.AT_MOST) {

result = Math.min(result, specSize);

}

}

return result;

}



@Override

protected void onDraw(Canvas canvas) {

if (shape == SHAPE_RECT) {

paint.setColor(Color.GRAY);

canvas.drawRect(backRect, paint);

paint.setColor(color_theme);

paint.setAlpha(alpha);

canvas.drawRect(backRect, paint);

frontRect.set(frontRect_left, RIM_SIZE, frontRect_left

+ getMeasuredWidth() / 2 - RIM_SIZE, getMeasuredHeight()

- RIM_SIZE);

paint.setColor(Color.WHITE);

canvas.drawRect(frontRect, paint);

} else {

// draw circle

int radius;

radius = backRect.height() / 2 - RIM_SIZE;

paint.setColor(Color.GRAY);

backCircleRect.set(backRect);

canvas.drawRoundRect(backCircleRect, radius, radius, paint);

paint.setColor(color_theme);

paint.setAlpha(alpha);

canvas.drawRoundRect(backCircleRect, radius, radius, paint);

frontRect.set(frontRect_left, RIM_SIZE, frontRect_left

+ backRect.height() - 2 * RIM_SIZE, backRect.height()

- RIM_SIZE);

frontCircleRect.set(frontRect);

paint.setColor(Color.WHITE);

canvas.drawRoundRect(frontCircleRect, radius, radius, paint);

}

}



@Override

public boolean onTouchEvent(MotionEvent event) {

if (slideable == false)

return super.onTouchEvent(event);

int action = MotionEventCompat.getActionMasked(event);

switch (action) {

case MotionEvent.ACTION_DOWN:

eventStartX = (int) event.getRawX();

break;

case MotionEvent.ACTION_MOVE:

eventLastX = (int) event.getRawX();

diffX = eventLastX - eventStartX;

int tempX = diffX + frontRect_left_begin;

tempX = (tempX > max_left ? max_left : tempX);

tempX = (tempX < min_left ? min_left : tempX);

if (tempX >= min_left && tempX <= max_left) {

frontRect_left = tempX;

alpha = (int) (255 * (float) tempX / (float) max_left);

invalidateView();

}

break;

case MotionEvent.ACTION_UP:

int wholeX = (int) (event.getRawX() - eventStartX);

frontRect_left_begin = frontRect_left;

boolean toRight;

toRight = (frontRect_left_begin > max_left / 2 ? true : false);

if (Math.abs(wholeX) < 3) {

toRight = !toRight;

}

moveToDest(toRight);

break;

default:

break;

}

return true;

}



/**

* draw again

*/

private void invalidateView() {

if (Looper.getMainLooper() == Looper.myLooper()) {

invalidate();

} else {

postInvalidate();

}

}



public void setSlideListener(SlideListener listener) {

this.listener = listener;

}



public void moveToDest(final boolean toRight) {

ValueAnimator toDestAnim = ValueAnimator.ofInt(frontRect_left,

toRight ? max_left : min_left);

toDestAnim.setDuration(500);

toDestAnim.setInterpolator(new AccelerateDecelerateInterpolator());

toDestAnim.start();

toDestAnim.addUpdateListener(new AnimatorUpdateListener() {



@Override

public void onAnimationUpdate(ValueAnimator animation) {

frontRect_left = (Integer) animation.getAnimatedValue();

alpha = (int) (255 * (float) frontRect_left / (float) max_left);

invalidateView();

}

});

toDestAnim.addListener(new AnimatorListenerAdapter() {

@Override

public void onAnimationEnd(Animator animation) {

if (toRight) {

isOpen = true;

if (listener != null)

listener.open();

frontRect_left_begin = max_left;

} else {

isOpen = false;

if (listener != null)

listener.close();

frontRect_left_begin = min_left;

}

}

});

}



public void setState(boolean isOpen) {

this.isOpen = isOpen;

initDrawingVal();

invalidateView();

if (listener != null)

if (isOpen == true) {

listener.open();

} else {

listener.close();

}

}



public void setShapeType(int shapeType) {

this.shape = shapeType;

}



public void setSlideable(boolean slideable) {

this.slideable = slideable;

}



@Override

protected void onRestoreInstanceState(Parcelable state) {

if (state instanceof Bundle) {

Bundle bundle = (Bundle) state;

this.isOpen = bundle.getBoolean("isOpen");

state = bundle.getParcelable("instanceState");

}

super.onRestoreInstanceState(state);

}



@Override

protected Parcelable onSaveInstanceState() {

Bundle bundle = new Bundle();

bundle.putParcelable("instanceState", super.onSaveInstanceState());

bundle.putBoolean("isOpen", this.isOpen);

return bundle;

}

}

使用方法:

1.在布局文件中引用控件:

[html] view
plaincopy

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

xmlns:slideswitch="http://schemas.android.com/apk/res/com.example.testlibs"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:background="#ffffffff"

android:gravity="center_horizontal"

android:orientation="vertical"

android:padding="10dip"

tools:context="com.example.testlibs.MainActivity" >



<com.leaking.slideswitch.SlideSwitch

android:id="@+id/swit"

android:layout_width="150dip"

android:layout_height="60dip"

slideswitch:isOpen="true"

slideswitch:shape="rect"

slideswitch:themeColor="#ffee3a00" >

</com.leaking.slideswitch.SlideSwitch>



<TextView

android:id="@+id/txt"

android:layout_width="wrap_content"

android:layout_height="wrap_content" />



<com.leaking.slideswitch.SlideSwitch

android:id="@+id/swit2"

android:layout_width="190dip"

android:layout_height="100dip"

android:layout_marginTop="10dip"

slideswitch:isOpen="true"

slideswitch:shape="circle"

slideswitch:themeColor="#ff0a5a00" >

</com.leaking.slideswitch.SlideSwitch>



<com.leaking.slideswitch.SlideSwitch

android:id="@+id/swit3"

android:layout_width="20dip"

android:layout_height="50dip"

android:layout_marginTop="10dip"

slideswitch:isOpen="true"

slideswitch:shape="circle"

slideswitch:themeColor="#ff73aa00" >

</com.leaking.slideswitch.SlideSwitch>



<com.leaking.slideswitch.SlideSwitch

android:id="@+id/swit4"

android:layout_width="100dip"

android:layout_height="120dip"

android:layout_marginTop="10dip"

slideswitch:isOpen="false"

slideswitch:shape="circle"

slideswitch:themeColor="#f200aa96" >

</com.leaking.slideswitch.SlideSwitch>



<com.leaking.slideswitch.SlideSwitch

android:id="@+id/swit5"

android:layout_width="90dip"

android:layout_height="50dip"

android:layout_marginTop="10dip"

slideswitch:isOpen="true"

slideswitch:shape="rect"

slideswitch:themeColor="#f23331a0" >

</com.leaking.slideswitch.SlideSwitch>



</LinearLayout>

MainActivity.java:

[java] view
plaincopy

/*

* Copyright (C) 2015 Quinn Chen

*

* Licensed under the Apache License, Version 2.0 (the "License");

* you may not use this file except in compliance with the License.

* You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package com.example.testlibs;



import android.app.Activity;

import android.os.Bundle;

import android.widget.TextView;

import android.widget.Toast;



import com.leaking.slideswitch.SlideSwitch;

import com.leaking.slideswitch.SlideSwitch.SlideListener;



public class MainActivity extends Activity implements SlideListener {



TextView txt;

SlideSwitch slide;

SlideSwitch slide2;



@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

slide = (SlideSwitch) findViewById(R.id.swit);

slide2 = (SlideSwitch) findViewById(R.id.swit2);



slide.setState(false);

txt = (TextView) findViewById(R.id.txt);

slide.setSlideListener(this);

}



@Override

public void open() {

txt.setText("first switch is opend, and set the second one is 'slideable'");

Toast.makeText(this, "红色打开!蓝色按钮可调!", Toast.LENGTH_LONG).show();

slide2.setSlideable(true);

}



@Override

public void close() {

txt.setText("first switch is closed,and set the second one is 'unslideable'");

Toast.makeText(this, "红色关闭!蓝色按钮不可调!", Toast.LENGTH_LONG).show();

slide2.setSlideable(false);

}

}

运行代码如下:

下载源码
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐