Android自定义view仿IOS开关效果

本文主要讲解如何在 Android 下实现高仿 iOS 的开关按钮,并非是在 Android 自带的 ToggleButton 上修改,而是使用 API 提供的 onDraw、onMeasure、Canvas 方法,纯手工绘制。基本原理就是在 Canvas 上叠着放两张图片,上面的图片根据手指触摸情况,不断移动,实现开关效果。

废话不说,上效果图,看看怎么样

样式如下:

网上也有实现这种效果的,但是大都滑动没中间消失的动画,或者是很复杂,今天用简单的绘图方式实现,重点就在onDraw里绘图。

功能点:

  • 不滑出边界,超过一半自动切换(边界判断)
  • 可滑动,也可点击(事件共存)
  • 提供状态改变监听(设置回调)
  • 通过属性设置初始状态、背景图片、滑动按钮(自定义属性)

自定义View的概述

Android 在绘制 View 时,其实就像蒙上眼睛在画板上画画,它并不知道应该把 View 画多大,画哪儿,怎么画。所以我们必须实现 View 的三个重要方法,以告诉它这些信息。即:onMeasure(画多大),onLayout(画哪儿),onDraw(怎么画)。

View的生命周期

在动手写之前,必须先了解以下几个概念:

1.View 的默认不支持 WRAP_CONTENT,必须重写 onMeasure 方法,通过 setMeasuredDimension() 设置尺寸
2.基本的事件分发机制:onClickListener 一定是在 onTouchEvent 之后执行

自定义View的流程

开始动手

1.导入开关的样式文件

<resources>

 <!-- Base application theme. -->
 <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
  <!-- Customize your theme here. -->
  <item name="colorPrimary">@color/colorPrimary</item>
  <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
  <item name="colorAccent">@color/colorAccent</item>
 </style>
 <!--高仿IOS7开关 - 样式-->
 <declare-styleable name="SwitchButton">
  <attr name="buttonColor" format="color" />
 </declare-styleable>

</resources>

2.开始自定义view,重点在onDraw()

/**
 * Author:AND
 * Time:2018/3/20.
 * Email:2911743255@qq.com
 * Description:
 * Detail:仿IOS开关
 */
public class SwitchButton extends View {
 //画笔
 private final Paint mPaint = new Paint();
 private static final double MBTNHEIGHT = 0.55;
 private static final int OFFSET = 3;
 private int mHeight;
 private float mAnimate = 0L;
 //此处命名不规范,目的和Android自带的switch有相同的用法
 private boolean checked = false;
 private float mScale;
 private int mSelectColor;
 private OnCheckedChangeListener mOnCheckedChangeListener;

 public SwitchButton(Context context) {
  this(context, null);
 }

 public SwitchButton(Context context, AttributeSet attrs) {
  super(context, attrs);
  TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.SwitchButton);
  mSelectColor = typedArray.getColor(R.styleable.SwitchButton_buttonColor, Color.parseColor("#2eaa57"));
  typedArray.recycle();
 }

 /**
  * @param widthMeasureSpec
  * @param heightMeasureSpec 高度是是宽度的0.55倍
  */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  int width = MeasureSpec.getSize(widthMeasureSpec);
  mHeight = (int) (MBTNHEIGHT * width);
  setMeasuredDimension(width, mHeight);
 }

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  mPaint.setStyle(Paint.Style.FILL);
  mPaint.setAntiAlias(true);
  mPaint.setColor(mSelectColor);
  Rect rect = new Rect(0, 0, getWidth(), getHeight());
  RectF rectf = new RectF(rect);
  //绘制圆角矩形
  canvas.drawRoundRect(rectf, mHeight / 2, mHeight / 2, mPaint);

  //以下save和restore很重要,确保动画在中间一层 ,如果大家不明白,可以去搜下用法

  canvas.save();
  mPaint.setColor(Color.parseColor("#E6E6E6"));
  mAnimate = mAnimate - 0.1f > 0 ? mAnimate - 0.1f : 0; // 动画标示 ,重绘10次,借鉴被人的动画
  mScale = (!checked ? 1 - mAnimate : mAnimate);
  canvas.scale(mScale, mScale, getWidth() - getHeight() / 2, rect.centerY());
  //绘制缩放的灰色圆角矩形
  canvas.drawRoundRect(rectf, mHeight / 2, mHeight / 2, mPaint);

  mPaint.setColor(Color.WHITE);
  Rect rect_inner = new Rect(OFFSET, OFFSET, getWidth() - OFFSET, getHeight() - OFFSET);
  RectF rect_f_inner = new RectF(rect_inner);
  //绘制缩放的白色圆角矩形,和上边的重叠实现灰色边框效果
  canvas.drawRoundRect(rect_f_inner, (mHeight - 8) / 2, (mHeight - 8) / 2, mPaint);
  canvas.restore();

  //中间圆形平移
  int sWidth = getWidth();
  int bTranslateX = sWidth - getHeight();
  final float translate = bTranslateX * (!checked ? mAnimate : 1 - mAnimate);
  canvas.translate(translate, 0);

  //以下两个圆带灰色边框
  mPaint.setColor(Color.parseColor("#E6E6E6"));
  canvas.drawCircle(getHeight() / 2, getHeight() / 2, getHeight() / 2 - OFFSET / 2, mPaint);

  mPaint.setColor(Color.WHITE);
  canvas.drawCircle(getHeight() / 2, getHeight() / 2, getHeight() / 2 - OFFSET, mPaint);

  if (mScale > 0) {
   mPaint.reset();
   invalidate();
  }
 }

 /**
  * 事件分发
  *
  * @param event
  * @return
  */
 @Override
 public boolean onTouchEvent(MotionEvent event) {
  switch (event.getAction()) {
   case MotionEvent.ACTION_DOWN:
    return true;
   case MotionEvent.ACTION_MOVE:
    break;
   case MotionEvent.ACTION_UP:
    mAnimate = 1;
    checked = !checked;

    if (mOnCheckedChangeListener != null) {

     mOnCheckedChangeListener.OnCheckedChanged(checked);

    }
    invalidate();
    break;
  }
  return super.onTouchEvent(event);
 }

 /**
  * 状态构造函数
  *
  * @return
  */
 public boolean isChecked() {
  return checked;
 }

 public void setChecked(boolean checked) {
  this.checked = checked;
 }

 /**
  * 构造函数
  *
  * @return
  */
 public OnCheckedChangeListener getmOnCheckedChangeListener() {
  return mOnCheckedChangeListener;
 }

 /**
  * 调用方法
  *
  * @param mOnCheckedChangeListener
  */
 public void setmOnCheckedChangeListener(OnCheckedChangeListener mOnCheckedChangeListener) {
  this.mOnCheckedChangeListener = mOnCheckedChangeListener;
 }

 /**
  * 滑动接口
  */
 public interface OnCheckedChangeListener {
  void OnCheckedChanged(boolean isChecked);
 }

}

3.Activity中使用

@Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mBtnSwitch = (SwitchButton) findViewById(R.id.switch_btn);
  mBtnSwitch.setmOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
   @Override
   public void OnCheckedChanged(boolean isChecked) {
    Toast.makeText(MainActivity.this, "" + isChecked, Toast.LENGTH_SHORT).show();
   }
  });
 }

当然,也可以上来就给开关定义状态值

mBtnSwitch.setChecked(boolean);

好了,自定义工作全部完成!!

那么300行左右的代码 完成了我们的仿iOS SwitchButton 的控件 SwitchView 生气!

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

(0)

相关推荐

  • Android自定义View实现开关按钮

    前言:Android自定义View对于刚入门乃至工作几年的程序员来说都是非常恐惧的,但也是Android进阶学习的必经之路,平时项目中经常会有一些苛刻的需求,我们可以在GitHub上找到各种各样的效果,能用则用,不能用自己花功夫改改也能草草了事.不过随着工作经验和工作性质,越来越觉得自定义View是时候有必要自己花点功夫研究一下. 一.经过这两天的努力,自己也尝试着写了一个Demo,效果很简单,就是开关按钮的实现. 可能有的人会说这效果so easy,找UI切三张图就完事了,何必大费周折自定义.

  • Android基于ImageView绘制的开关按钮效果示例

    本文实例讲述了Android基于ImageView绘制的开关按钮效果.分享给大家供大家参考,具体如下: 今天弄了一下用图片绘制开关按钮. 效果图: 还有我两张start图片和stop图片就是上面的图片,到时候大家可以按照自己的图片调用.. Main.xml文件 在xml进入这段代码就ok了. <ImageView Android:id="@+id/start" android:layout_width="150.px" android:layout_heigh

  • Android自定义view仿IOS开关效果

    本文主要讲解如何在 Android 下实现高仿 iOS 的开关按钮,并非是在 Android 自带的 ToggleButton 上修改,而是使用 API 提供的 onDraw.onMeasure.Canvas 方法,纯手工绘制.基本原理就是在 Canvas 上叠着放两张图片,上面的图片根据手指触摸情况,不断移动,实现开关效果. 废话不说,上效果图,看看怎么样 样式如下: 网上也有实现这种效果的,但是大都滑动没中间消失的动画,或者是很复杂,今天用简单的绘图方式实现,重点就在onDraw里绘图. 功

  • Android自定义view仿iOS弹出框效果

    本文实例为大家分享了Android自定义view仿iOS弹出框的具体代码,供大家参考,具体内容如下 运行效果图 自定义对话框的使用,仿照ios.从底部弹出,类似pop窗口.包括消息.图片.列表及对话框. 好了,用法都会,直接贴上代码 1.layout布局文件 view_actionsheet.xml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="ht

  • Android自定义View仿IOS圆盘时间选择器

    通过自定义view实现仿iOS实现滑动两端的点选择时间的效果 效果图 自定义的view代码 public class Ring_Slide2 extends View { private static final double RADIAN = 180 / Math.PI; private int max_progress; // 设置最大进度 private int cur_progress; //设置锚点1当前进度 private int cur_progress2; //设置锚点2进度 p

  • Android自定义View仿微信LetterView效果

    废话不多说了,具体代码如下所示: public class LetterView extends View { private String TAG = LetterView.class.getSimpleName(); //A,B,C....Z,# public List<String> letters; private Paint mPaint; private int selectPosition = -1; private TextView mLetter; public void s

  • Android自定义View仿探探卡片滑动效果

    Android自定义View仿探探卡片滑动这种效果网上有很多人已经讲解了实现思路,大多都用的是RecyclerView来实现的,但是我们今天来换一种实现思路,只用一个自定义的ViewGroup来搞定这个实现. 下面我们先看一下实现的效果: 这个自定义View用法也很简单,首先从github上下载或者fork这个项目,在布局中添加: <com.liyafeng.view.swipecard.SwipeCardLayout android:id="@+id/scl_layout" a

  • Android自定义view仿QQ的Tab按钮动画效果(示例代码)

    话不多说 先上效果图 实现其实很简单,先用两张图 一张是背景的图,一张是笑脸的图片,笑脸的图片是白色,可能看不出来.实现思路:主要是再触摸view的时候同时移动这两个图片,但是移动的距离不一样,造成的错位感,代码很简单: import android.content.Context import android.graphics.* import android.util.AttributeSet import android.view.MotionEvent import android.vi

  • Android自定义View 仿QQ侧滑菜单的实现代码

    先看看QQ的侧滑效果 分析一下 先上原理图(不知道能否表达的清楚 ==) -首先这里使用了 Android 的HorizontalScrollView 水平滑动布局作为容器,当然我们需要继承它自定义一个侧滑视图 - 这个容器里面有一个父布局(一般用LinerLayout,本demo用的是),这个父布局里面有且只有两个子控件(布局),初始状态菜单页的位置在Y轴上存在偏移这样可以就可以形成主页叠在菜单页的上方的视觉效果:然后在滑动的过程程中 逐渐修正偏移,最后菜单页和主页并排排列.原理搞清了实现起来

  • Android 自定义view仿支付宝咻一咻功能

    支付宝上有一个咻一咻的功能,就是点击图片后四周有水波纹的这种效果,今天也写一个类似的功能. 效果如下所示: 思路: 就是几个圆的半径不断在变大,这个可以使用动画缩放实现,还有透明动画 还有就是这是好几个圆,然后执行的动画有个延迟效果,其实这些动画是放在一起执行的,熟悉属性动画的知道已经给我们提供了同步执行动画和顺序执行动画的实现api,也会会有人说这几个view就是在onDraw()方法中画几个圆,可能会说我还要继承容器view去onLayout()方法中这些子view添加在某个特定的区域,当然

  • Android自定义View实现拖拽效果

    腾讯QQ有那种红点拖动效果,今天就来实现一个简单的自定义View拖动效果,再回到原处,并非完全仿QQ红点拖动. 先来看一下效果图 简单说一下实现步骤 1.创建一个类继承View 2.绘制出一个小球 3.重写onTouchEvent,来根据手指放下,移动,抬起,来控制小球 4.直接在布局中引用 先贴一张图看下View的坐标系 下面就贴一下代码,最后会给出源码 public class CustomView extends View { private int lastX; private int

  • Android 自定义view仿微信相机单击拍照长按录视频按钮

    Android仿微信相机的拍照按钮单击拍照,长按录视频.先上效果图. 项目地址:https://github.com/c786909486/PhotoButton2/tree/v1.0 添加依赖 allprojects { repositories { ... maven { url 'https://jitpack.io' } } } dependencies { compile compile 'com.github.c786909486:PhotoButton2:v1.1' } 长按效果分

随机推荐