Android自定义view仿IOS开关效果

 更新时间:2019年06月15日 12:00:47   作者:AND_Devil  
这篇文章主要为大家详细介绍了Android自定义view仿IOS开关效果,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

GPT4.0+Midjourney绘画+国内大模型 会员永久免费使用!
如果你想靠AI翻身,你先需要一个靠谱的工具!

本文主要讲解如何在 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.导入开关的样式文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<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()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/**
 * 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中使用

1
2
3
4
5
6
7
8
9
10
11
12
@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();
  }
 });
 }

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

1
mBtnSwitch.setChecked(boolean);

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

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

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

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:https://blog.csdn.net/qq_40543575/article/details/79625046

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

最新评论