android 自定义switch控件,android自定义开关控件-SlideSwitch的实例

iphone上有开关控件,很漂亮,其实android4.0以后也有switch控件,但是只能用在4.0以后的系统中,这就失去了其使用价值,而且我觉得它的界面也不是很好看。最近看到了百度魔拍上面的一个控件,觉得很漂亮啊,然后反编译了下,尽管没有混淆过,但是还是不好读,然后就按照自己的想法写了个,功能和百度魔拍类似。

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

94dc9a6cc68df833025f139e48816101.png

一、原理

继承自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滑动开关组件,仿百度魔图滑动开关组件

* 组件分为三种状态:打开、关闭、正在滑动

* 使用方法:

*

SlideSwitch slideSwitch = new SlideSwitch(this);

*slideSwitch.setOnSwitchChangedListener(onSwitchChangedListener);

*linearLayout.addView(slideSwitch);

注:也可以加载在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);

}

}

layout xml

android:layout_width="fill_parent"

android:layout_height="fill_parent"

android:background="#fdfdfd"

android:orientation="vertical"

android:paddingLeft="10dip"

android:paddingRight="10dip" >

android:id="@+id/imageView1"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:src="@drawable/top" />

android:layout_width="fill_parent"

android:layout_height="wrap_content" >

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

android:id="@+id/slideSwitch1"

android:layout_width="116dip"

android:layout_height="46dip"

android:layout_alignParentRight="true"

android:layout_centerVertical="true" />

android:layout_width="fill_parent"

android:layout_height="wrap_content" >

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

android:id="@+id/slideSwitch2"

android:layout_width="116dip"

android:layout_height="46dip"

android:layout_alignParentRight="true"

android:layout_centerVertical="true" />

android:layout_width="fill_parent"

android:layout_height="wrap_content" >

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

android:id="@+id/slideSwitch3"

android:layout_width="116px"

android:layout_height="46px"

android:layout_alignParentRight="true"

android:layout_centerVertical="true" />

android:id="@+id/textViewTip"

android:layout_width="fill_parent"

android:layout_height="wrap_content"

android:gravity="center"

android:text="TextView" />

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android中,可以通过自定义按钮来实现一些特定的样式和功能。在给按钮自定义样式时,可以在构造函数中获取按键的样式和文本集合。具体的实现步骤如下: 1. 在构造函数中获取圆角按钮样式和按钮包含的文本元素。可以通过在构造函数中调用`context.obtainStyledAttributes()`方法来获取属性集合。这个方法的第一个参数是`attrs`,表示属性集合的资源id。然后通过调用`TypedArray`对象的`getString()`方法来获取文本元素的值。最后,记得调用`ta.recycle()`方法释放资源。 2. 创建一个自定义按钮的布局文件,并在`RelativeLayout`布局中添加自定义按钮。可以使用XML属性来设置按钮的属性,如`id`、`layout_width`、`layout_height`等。在`com.example.togglebutton.ui.MyToggleButton`标签中可以设置自定义按钮的特定属性,如宽度、高度和在父布局中的居中位置。 3. 在`MainActivity`类中,通过`setContentView()`方法将布局文件设置为当前活动的布局文件。这样就可以在主活动中显示自定义按钮了。 总结:Android中可以通过自定义按钮来实现特定的样式和功能。可以通过构造函数获取按钮的样式和文本集合,然后在布局文件中添加自定义按钮并在主活动中显示。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [安卓创建自定义按钮](https://blog.csdn.net/landlde/article/details/129889065)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Android自定义控件系列二:自定义开关按钮(一)](https://blog.csdn.net/cyp331203/article/details/40736027)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值