android自定义一组按钮,Android自定义View之自定义开关按钮

一、效果展示

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

0818b9ca8b590ca3270a3433284dd417.png

二、相关链接

三、自定义View的具体步骤

1、首先需要写一个类来继承自View(或者View的子类)

2、需要得到view的对象(并初始化变量),那么需要重写构造方法,其中一参的构造方法用于new,二参的构造方法用于xml布局文件使用,三参的构造方法可以传入一个样式。

3、需要设置view的大小,那么需要重写onMeasure方法

4、需要设置view的位置,那么需要重写onLayout方法,但是这个方法在自定义view的时候用的不多,原因主要在于view的位置主要是由父控件来决定

5、需要绘制出所需要显示的view,那么需要重写onDraw方法

6、当控件状态改变的时候,需要重绘view,那么调用invalidate();方法,这个方法实际上会重新调用onDraw方法

7、在这其中,如果需要对view设置点击事件,可以直接调用setOnClickListener方法

8、需要实现触摸拖拽功能,那么需要重写的onTouchEvent方法,基本上是处理ACTION_DOWN、ACTION_MOVE和ACTION_UP事件。

8、在布局中使用此自定义控件

四、自定义开关按钮的思路

1、首先需要定义一个类,继承自View;

2、定义两参数构造方法,在构造函数中初始化视图,在初始化中:获取背景图和按钮转化为bitmap对象,计算最大偏移量=背景图宽 - 按钮宽()。

3、在onMeasure(int widthMeasureSpec, int heightMeasureSpec)方法的内部调用setMeasuredDimension(mBackgroudBitmap.getWidth(), mBackgroudBitmap.getHeight());指定背景如何显示

4、(最关键)对于一个控件需要显示,需要将它绘制出来,这里就需要重写onDraw方法,来将这个控件绘制出。

// 画笔工具

Paint paint = new Paint();

// 初始化一个画笔

paint = new Paint();

// 设置抗锯齿

paint.setAntiAlias(true);

// 1.画出背景图片

canvas.drawBitmap(mBackgroudBitmap, 0, 0, paint);

// 2.画出button按钮(开始位置:当前偏移量,实时更新)

canvas.drawBitmap(mSlidingBitmap, mSlidingCurrentOffset, 0, paint);

5、当控件状态改变的时候,需要刷新view的显示状态,就调用invalidate()方法,这个方法实际上会重新调用onDraw方法来重绘控

6、在定义控件的过程中,如果需要对view设置点击事件,可以直接使用setOnClickListener方法,而不需要写view.setOnClickListener;

onClick和onLongClick是在super.onTouchEvent方法里被调用的,onClick是在ACTION_UP的时候可能被调用,而onLongClick是在ACTION_DOWN的时候可能被调用。

7、需要实现触摸拖拽功能,重写onTouchEvent方法,基本上是处理ACTION_DOWN、ACTION_MOVE和ACTION_UP事件。

/** * 触摸监听 * **关键步骤:1.2.3.4.** *@param event *@return */

@Override

public boolean onTouchEvent(MotionEvent event) {

super.onTouchEvent(event);

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

// 1.记录第一次触摸时按下的X坐标

mStartX = event.getX();

// 按下时恢复开关的点击事件

mIsClickable = true;

break;

case MotionEvent.ACTION_MOVE:

mMoveX = event.getX();

// 2.1如果有移动距离,就视为是触摸,就屏蔽点击事件

if (Math.abs(mMoveX - mStartX) > 0) {

mIsClickable = false;

}

// 2.2如果有移动距离,得到最新的当前距离

mSlidingCurrentOffset += (int) (mMoveX - mStartX);

if (mSlidingCurrentOffset > mSlidingMaxOffset)

mSlidingCurrentOffset = mSlidingMaxOffset;

if (mSlidingCurrentOffset < 0)

mSlidingCurrentOffset = 0;

// 3.重新初始化界面

flushView();

// 4.还原,最新的开始X坐标

mStartX = event.getX();

break;

case MotionEvent.ACTION_UP:

// 抬起的时候,判断松开的位置是哪,来决定开关的状态是打开还是关闭

if (mSlidingCurrentOffset > mSlidingMaxOffset / 2)

mSlidingCurrentOffset = mSlidingMaxOffset;

if (mSlidingCurrentOffset <= mSlidingMaxOffset / 2)

mSlidingCurrentOffset = 0;

// 重新初始化界面

flushView();

break;

}

invalidate();

return true;

}

8、在布局文件中将这个自定义控件定义出来,注意名字要使用全类名;

五、源码

1.activity_main.xml

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

android:layout_width="match_parent"

android:layout_height="match_parent"

tools:context=".MainActivity">

android:id="@+id/customButton"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true" />

2.CustomButton.java

/** *@author Guan *@file com.guan.custombutton *@date 2015/11/10 *@Version 1.0 */

public class CustomButton extends View implements View.OnClickListener {

// 背景图片

private Bitmap mBackgroudBitmap;

// 开关图片

private Bitmap mSlidingBitmap;

// 开关是否打开

private boolean mIsOpen;

// 是否可点击

private boolean mIsClickable;

// 最大偏移量(离控件左边的距离)

private int mSlidingMaxOffset;

// 当前偏移量

private int mSlidingCurrentOffset;

// 开始X坐标

private float mStartX;

// 移动的X坐标

private float mMoveX;

public CustomButton(Context context) {

super(context);

}

/** * 构造方法(两个参数,必须重写) * *@param context *@param attrs */

public CustomButton(Context context, AttributeSet attrs) {

super(context, attrs);

initView();

}

/** * 初始化 */

private void initView() {

// 初始化一个画笔

mPaint = new Paint();

// 设置抗锯齿

mPaint.setAntiAlias(true);

// 得到背景图片转化为bitmap对象

mBackgroudBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.a);

// 得到button图片转化为bitmap对象

mSlidingBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.b);

// 计算最大偏移量(=背景图宽 - 按钮宽)

mSlidingMaxOffset = mBackgroudBitmap.getWidth() - mSlidingBitmap.getWidth();

// 给自定义的view设置点击事件

setOnClickListener(this);

}

/** * 测量指定图片如何显示(如何展示给用户) * *@param widthMeasureSpec *@param heightMeasureSpec */

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

// 指定背景如何显示

setMeasuredDimension(mBackgroudBitmap.getWidth(), mBackgroudBitmap.getHeight());

}

/** *@param canvas */

@Override

public void onDraw(Canvas canvas) {

// 画笔工具

Paint paint = new Paint();

// 初始化一个画笔

paint = new Paint();

// 设置抗锯齿

paint.setAntiAlias(true);

// 1.画出背景图片

canvas.drawBitmap(mBackgroudBitmap, 0, 0, mPaint);

// 2.画出button按钮(开始位置:当前偏移量,实时更新)

canvas.drawBitmap(mSlidingBitmap, mSlidingCurrentOffset, 0, mPaint);

}

/** * 给自定义的view设置点击事件 * * onClick和onLongClick是在super.onTouchEvent方法里被调用的,onClick是在ACTION_UP的时候可能被调用,而onLongClick是在ACTION_DOWN的时候可能被调用。 */

@Override

public void onClick(View v) {

if (mIsClickable) {

// 如何是打开的

if (mIsOpen) {

mSlidingCurrentOffset = 0;

} else {

mSlidingCurrentOffset = mSlidingMaxOffset;

}

mIsOpen = !mIsOpen;

// 重新初始化界面,可是OnDraw再次执行

flushView();

}

}

/** * 触摸监听 * *@param event *@return */

@Override

public boolean onTouchEvent(MotionEvent event) {

super.onTouchEvent(event);

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

// 1.记录第一次触摸时按下的X坐标

mStartX = event.getX();

// 按下时恢复开关的点击事件

mIsClickable = true;

break;

case MotionEvent.ACTION_MOVE:

mMoveX = event.getX();

// 如果有移动距离,就视为是触摸,就屏蔽点击事件

if (Math.abs(mMoveX - mStartX) > 0) {

mIsClickable = false;

}

// 得到最新的当前距离

mSlidingCurrentOffset += (int) (mMoveX - mStartX);

if (mSlidingCurrentOffset > mSlidingMaxOffset)

mSlidingCurrentOffset = mSlidingMaxOffset;

if (mSlidingCurrentOffset < 0)

mSlidingCurrentOffset = 0;

// 重新初始化界面

flushView();

// 还原,最新的开始X坐标

mStartX = event.getX();

break;

case MotionEvent.ACTION_UP:

// 抬起的时候,判断松开的位置是哪,来决定开关的状态是打开还是关闭

if (mSlidingCurrentOffset > mSlidingMaxOffset / 2)

mSlidingCurrentOffset = mSlidingMaxOffset;

if (mSlidingCurrentOffset <= mSlidingMaxOffset / 2)

mSlidingCurrentOffset = 0;

// 重新初始化界面

flushView();

break;

}

invalidate();

return true;

}

/** * 刷新视图 */

protected void flushView() {

// 刷新当前view会导致ondraw方法的执行

invalidate();

}

}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值