就是很像开关的那种控件,它只有两个状态:on和off:在IOS中,有个UISwitch控件,其效果图,如下:
在android4.0里面,添加了一个和这个类似的控件:Switch,很形象,开关。效果图如下:
其类关系图如下:
类的概述: Switch是一个可以在两种状态切换的开关控件。用户可以拖动"thumb"来回选择,也可以像选择复选框一样点击切换Switch的状态。 主要方法:
getTextOff()、getTextOn()、 setTextOff()、setTextOn()这四个方法比较简单,就是设定和获取非选中和选中状态下的文本值。 onMeasure():测量控件宽高,供绘图时使用。 onTouchEvent(MotionEvent ev)实现这一方法传递触摸屏运动事件。 setChecked()设置Switch的状态(选中,非选中) setSwitchTextAppearance()设置字体大小 setSwitchTextTypefaces设置字体格式 看看google官方在/frameworks/base/core/res/res/values/styles.xml的一个定义:
[java]
view plain
copy
可以在main.xml中这样定义:
[java]
view plain
copy
当Switch状态切换时:
[java]
view plain
copy
************************************************************************************************************************** 1)Android从4.0开始提供了switch的滑动开关效果组件,但是之前版本却没有 (2)很多时候我们写程序,都希望把有用的通用的通用的东西封装起来,以便以后重用。 本文根据组件开发思想,首先介绍android自定义控件,然后将自定义的控件封装为jar包。最为实现了一个滑动开关的例子。最后效果如图所示: 下面是开发步骤: 1.android自定义控件 自定义控件过程:建立一个应用程序,新建一个类,该类继承View类,并实现参数为(Context context,AttributeSet attrs)的构造函数,定义控件对应的xml布局文件,定义控件的属性文件attrs 2.封装为jar包 封装jar包有两种方法,一是在新建工程的时候就勾选Mark this project as a library 这样建立的就是库文件,但是这样的话建立项目的时候不利于调式,因此使用的二种方法;第二种方法是在建立调试好项目后将,选择项目右键——>属性——>在左边面板中选择Android,在面板中勾选Is Library 3.switchview实例 声明:本例子是在别人的基础上更改而来的部分代码版权属于他人 (1)建立工程switchview2 建立类SwitchView,SwitchView继承自LinearLayout (2)新建布局文件switch_view.xml <?xml version="1.0" encoding="utf-8"?> <ImageButton <LinearLayout <TextView <TextView </RelativeLayout> 布局文件包括外边框sv_container,滑动块iv_switch_cursor,以及显示文本的两个TextView (3)在res->values文件夹下新建立控件的属性文件attrs.xml,里面建立了一个name为SwitchView的declare-styleable来自定义属性,属性包括当开关返回的是true时显示的文本,为false显示的文本,常见的是“是否”、“男女”等二选一的地方。container_Hight、container_Width、container_Background是表示的是背景高度、宽度、背景图或颜色,cursor_Hight、cursor_Width、cursor_Background表示的是滑动块的高度、宽度、背景图或颜色,这里背景一般都是用图片,因为颜色表示不出效果来,最终滑动开关的效果关键也要靠这些属性综合决定。 <?xml version="1.0" encoding="utf-8"?> (4)重构SwitchView方法。方法必须包含AttributeSet属性attrs,attrs通过context.obtainStyledAttributes(attrs, R.styleable.SwitchView);方法建立TypedArray与attrs.xml中的SwitchView对应,然后就可以为相应的控件赋值。 public SwitchView(Context context, AttributeSet attrs) { //设置滑动开关的显示文本 (5)按照第二步的方法封装为jar包 4.实例应用 新建一个工程项目SwitchViewExample,建立一个Activity类MainActivity.class 在项目的属性中选择Android,点击Add添加SwitcView的库 或着在项目SwitchView2项目的bin下面将switchview2.jar拷贝靠SwitchViewExample项目下的libs文件夹下面,通过添加外部jar包引用的方式加载进来。 在MainActivity对应的布局文件中添加前面自定义的控件,并设置对应的属性 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" <com.jiesai.ljp.switchview.SwitchView </RelativeLayout> 在MainActivity类中可以实例化一个SwitchView,通过switchView.isChecked();可以判断滑动开关选择的是什么项,然后想做什么就可以随便了 public class MainActivity extends Activity { @Override @Override } *************************************************************************************************************************** 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);
}}
// 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_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> |
switch控件分析
最新推荐文章于 2023-02-16 14:42:06 发布