Android高仿iOS Messages录音操作按钮
Android高仿iOS Messages录音操作按钮
目录
一、目标
二、功能分析
三、实现效果
四、实现过程
五、开发过程回顾
六、接下来
七、Finally
前面的2次开发,分别完成了实现录音和播放以及相对应的波形。
- Android低仿iOS Messages录音波形效果
- Android高仿iOS Messages声音播放波形效果
这次的开发目标是解决录音操作按钮。
一、目标
实现录音操作按钮,为神马笔记实现录音功能做准备。
二、功能分析
iOS Messages录音按钮可以通过上下滑动选择不同的功能。
其中一个使用场景:
- 长按录音按钮启动录音功能
- 向上滑动到发送按钮,发送语音
- 向下滑动到停止按钮,停止录音
- 滑动到按钮外部,不进行任何操作
截图 | 描述 |
---|---|
录音按钮及按下状态 | |
发送按钮及按下状态 | |
播放按钮及按下状态 | |
暂停按钮及按下状态 | |
三、实现效果
没有动态效果,看起来跟LinearLayout
或者其他的控件容器毫无差别。
进行触控操作,则可以通过上下滑动选择不同的功能。
四、实现过程
因为布局方式与LinearLayout
非常一致,因此选择LinearLayout
为蓝本,然后重新编写触控事件。
触控事件的处理方式则参考ScrollView
,因为无需处理滚动,实现非常之简单。
使用时,需要将子控件clickable
属性设置为true
,才能反应控件状态。
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 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 |
public class ActionLayout extends LinearLayout {private static final String TAG = "ActionLayout";View actionView;View.OnClickListener onClickListener;/*** Sentinel value for no current active pointer.* Used by {@link #mActivePointerId}.*/private static final int INVALID_POINTER = -1;/*** ID of the active pointer. This is used to retain consistency during* drags/flings if multiple pointers are used.*/private int mActivePointerId = INVALID_POINTER;public ActionLayout(Context context) {this(context, null);}public ActionLayout(Context context, @Nullable AttributeSet attrs) {this(context, attrs, 0);}public ActionLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {this(context, attrs, defStyleAttr, 0);}public ActionLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {super(context, attrs, defStyleAttr, defStyleRes);}@Overridepublic void setOnClickListener(@Nullable OnClickListener l) {this.onClickListener = l;super.setOnClickListener(l);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {super.onInterceptTouchEvent(ev);final int action = ev.getAction();switch (action & MotionEvent.ACTION_MASK) {case MotionEvent.ACTION_DOWN: {mActivePointerId = ev.getPointerId(0);this.updateAction(ev);break;}case MotionEvent.ACTION_MOVE: {if (mActivePointerId == INVALID_POINTER) {mActivePointerId = ev.getPointerId(0);}this.updateAction(ev);break;}case MotionEvent.ACTION_CANCEL: {this.mActivePointerId = INVALID_POINTER;this.actionView = null;break;}case MotionEvent.ACTION_UP: {this.fireAction();this.mActivePointerId = INVALID_POINTER;this.actionView = null;break;}case MotionEvent.ACTION_POINTER_UP: {onSecondaryPointerUp(ev);this.updateAction(ev);break;}}return isClickable() || (getChildCount() != 0);}@Overridepublic boolean onTouchEvent(MotionEvent ev) {final int actionMasked = ev.getActionMasked();switch (actionMasked) {case MotionEvent.ACTION_DOWN: {mActivePointerId = ev.getPointerId(0);updateAction(ev);break;}case MotionEvent.ACTION_MOVE: {if (mActivePointerId == INVALID_POINTER) {mActivePointerId = ev.getPointerId(0);}updateAction(ev);break;}case MotionEvent.ACTION_UP: {fireAction();this.mActivePointerId = INVALID_POINTER;this.actionView = null;break;}case MotionEvent.ACTION_CANCEL: {mActivePointerId = INVALID_POINTER;this.actionView = null;break;}case MotionEvent.ACTION_POINTER_DOWN: {final int index = ev.getActionIndex();this.mActivePointerId = ev.getPointerId(index);this.updateAction(ev);break;}case MotionEvent.ACTION_POINTER_UP: {onSecondaryPointerUp(ev);this.updateAction(ev);break;}}return isClickable() || (getChildCount() != 0);}void fireAction() {if (actionView == null) {return;}actionView.setPressed(false);if (onClickListener != null) {onClickListener.onClick(actionView);}}void updateAction(MotionEvent ev) {final int activePointerIndex = ev.findPointerIndex(mActivePointerId);if (activePointerIndex == -1) {Log.e(TAG, "Invalid pointerId=" + mActivePointerId + " in onTouchEvent");return;}final float x = ev.getX(activePointerIndex);final float y = ev.getY(activePointerIndex);View view = findChildViewUnder(x, y);if (view != null && view.getVisibility() != View.VISIBLE) {view = null;}if (actionView == view) {return;}if (actionView != null) {actionView.setPressed(false);}if (view != null) {view.setPressed(true);}this.actionView = view;}View findChildViewUnder(float x, float y) {final int count = this.getChildCount();for (int i = count - 1; i >= 0; i--) {View child = this.getChildAt(i);final float translationX = child.getTranslationX();final float translationY = child.getTranslationY();if (x >= child.getLeft() + translationX&& x <= child.getRight() + translationX&& y >= child.getTop() + translationY&& y <= child.getBottom() + translationY) {return child;}}return null;}void onSecondaryPointerUp(MotionEvent ev) {final int pointerIndex = (ev.getAction() & MotionEvent.ACTION_POINTER_INDEX_MASK) >>MotionEvent.ACTION_POINTER_INDEX_SHIFT;final int pointerId = ev.getPointerId(pointerIndex);if (pointerId == mActivePointerId) {// This was our active pointer going up. Choose a new// active pointer and adjust accordingly.// TODO: Make this decision more intelligent.final int newPointerIndex = pointerIndex == 0 ? 1 : 0;mActivePointerId = ev.getPointerId(newPointerIndex);}} } |
五、开发过程回顾
明确开发目标,选择LinearLayout
和ScrollView
为蓝本进行改造。
还从RecyclerView
拿了点代码来用。
六、接下来
继续朝录音编辑器迈进。
七、Finally
尔时。世尊而说偈言。
若以色见我。 以音声求我。 是人行邪道。 不能见如来。
Android高仿iOS Messages录音操作按钮相关推荐
- Android高仿iOS Messages聊天气泡
Android高仿iOS Messages聊天气泡 一.目标 二.功能分析 三.实现代码 1. ChatItem 2. DateItem 3. TextItem 4. PhotoItem 5. Cha ...
- android高仿ios控制中心,高仿ios控制中心安卓版
高仿ios控制中心安卓版是一款非常好用的安卓仿苹果手机控制中心的软件,能够让使用安卓手机的朋友们随时体验苹果手机的系统,操作简单方便,软件也是非常稳定的,大家可放心的下载使用,感兴趣的用户们就前来下载 ...
- android 高仿ios开关,Android自定义view仿IOS开关效果
本文主要讲解如何在 Android 下实现高仿 iOS 的开关按钮,并非是在 Android 自带的 ToggleButton 上修改,而是使用 API 提供的 onDraw.onMeasure.Ca ...
- Android高仿IOS和QQ的弹出对话框
我们知道Android中其实并不提供圆形的东西,像Button,TextView,EditView等等都是没有弧形元素在里面(看看这些控件的属性就知道了).而很多时候我们的程序中又需要用到这样有弧形元 ...
- android 高仿ios时间选择器,仿ios时间选择
再mui得picker的基础上修改为类似ios选择时间的插件. muipicker exapmple地址 把里面数据换成下面的数据就可以了. (function($, doc) { $.init(); ...
- android 高仿ios水滴,iOS仿芝麻信用水滴效果
开篇: 最近接到客户需要开发(就按某付宝那个页面给我做一个)的新需求,大体就是类似芝麻信用的水滴效果(图1)用来展示用户的信用积分.苦于没有思路,找到的iOS实现的文章基本都是类似图2仪表盘的实现思路 ...
- Android Study 之通过DialogFragment玩转高仿IOS弹框~ ^.^
LZ-Say:在努力向前奔跑的途中,不要忘记让自己始终保持一个良好的状态,一颗初心,一颗永不言弃的心,一起加油` 前言 LZ虽说是搞Android的,但是对IOS的风格样式甚是酷爱,感觉简约大方,而今 ...
- android高仿微信聊天页面,Android 高仿微信语音聊天页面高斯模糊(毛玻璃效果)
目前的应用市场上,使用毛玻璃效果的APP随处可见,比如用过微信语音聊天的人可以发现,语音聊天页面就使用了高斯模糊效果. 先看下效果图: 仔细观察上图,我们可以发现,背景图以用户头像为模板,对其进行了高 ...
- Android 高仿唱吧 咔拉ok 商业项目开源代码 K歌合成 伴奏录音合成MP3(音频五)
Android MediaRecorder录音录像 暂停 继续录音 播放 ARM格式(音频一) https://blog.csdn.net/WHB20081815/article/details/88 ...
最新文章
- 支持html5浏览器速查
- javascript动画函数封装(升级版)
- Effective Java之避免创建不必要的对象(五)
- 阿里云技术白皮书_对阿里重磅发布的云原生架构白皮书的初步解读
- The podfile
- 用 GDB 调试Linux程序及有用技巧
- github private链接访问_将github配置为图床+PicGo配置
- 基于Spring Security的认证授权_连接数据库认证_Spring Security OAuth2.0认证授权---springcloud工作笔记128
- 温故10个经典排序算法(Java版)
- EXE反编译方法及工具
- 2.8.13 hadoop体系之离线计算-HBase数据库-HBase的优化
- 天线多频设计方法精讲
- Linux与.Net Core(一) Centos 系统制作教程
- 计算机桌面有去不掉的框,电脑右下角有个白色方框去不掉
- 【Python】Pandas实用技能,数据筛选query函数详细介绍
- php mysql die_【PHP】当mysql遇上PHP
- 前端html网页,点击按钮或超链接 弹出 一个登陆的div窗口或者对话框
- 使用VirtualBox安装Linux虚拟机,避坑指南
- 周鸿祎产品秘笈:小版本成就大产品
- DBeaver SQL format 第三方插件方案