仿抖音视频双指缩放和单指滑动效果
onScaleonScaleBeginonScaleEnd
单指:ACTION_DOWN->ACTION_MOVE->ACTION_UP;
多指:ACTION_DOWN->ACTION_POINTER_DOWN->ACTION_MOVE->ACTION_POINTER_UP->ACTION_UP一次完整的触摸事件中,Down和Up都只有一个,Move有若干个,可以为0个。当触摸事件被拦截时,Up可能是0个。View在ViewGroup内,ViewGroup也可以在其他ViewGroup内,这时候把内部的ViewGroup当成View来分析。
dispatchTouchEventonInterceptTouchEventonTouchEvent
/*** 可缩放的Layout*/
class TouchToScaleLayout(context: Context, attrs: AttributeSet?) : FrameLayout(context, attrs) {// 缩放view的初始left/topprivate var originalXY: IntArray? = null// 触摸时 双指中间的点 / 双指距离private var originalTwoPointerCenter: Point? = nullprivate var originalDistance: Int = 0// 移动时 双指距离 缩放比例private var moveDistance: Int = 0private var moveScale: Float = 0.0f;// 双指移动距离的增量比(用于计算缩放比、背景颜色)private var moveDistanceIncrement: Float = 0.0f// 缩放的Viewprivate var scaleableView: View? = null// 缩放的View原LayoutParamsprivate var viewLayoutParams: ViewGroup.LayoutParams? = null// 缩放的View,在dialog中的LayoutParamsprivate var dialogFrameLayoutParams: FrameLayout.LayoutParams? = null// 用于缩放的dialogprivate var dialog: ScaleDialog? = null// 缩放的动画状态private var isDismissAnimating: Boolean = false//监听回调private var mListener: OnVideoZoomListener? = nullprivate var mOneOrTwoListener: OnVideoZoomOneOrTwoPointListener? = nullfun setZoomListener(listener: OnVideoZoomListener) {mListener = listener}fun setOneOrTwoPointListener(listener:OnVideoZoomOneOrTwoPointListener){mOneOrTwoListener=listener}override fun onTouchEvent(ev: MotionEvent?): Boolean {//后续事件将可以继续传递给该view的onTouchEvent()处理//不想上传递return true}override fun dispatchTouchEvent(ev: MotionEvent): Boolean {if (childCount == 0 && scaleableView == null) return super.dispatchTouchEvent(ev)when (ev.actionMasked) {MotionEvent.ACTION_DOWN -> {Log.e("--------", "ACTION_DOWN")if (mOneOrTwoListener!=null){mOneOrTwoListener!!.onOnePoint()}//交与系统处理return super.dispatchTouchEvent(ev)}MotionEvent.ACTION_UP, MotionEvent.ACTION_CANCEL -> {//抬起直接复原下拉上拉if (mOneOrTwoListener!=null){mOneOrTwoListener!!.onOnePoint()}if (ev.action == MotionEvent.ACTION_UP) {Log.e("--------", "ACTION_UP")}if (ev.action == MotionEvent.ACTION_CANCEL) {Log.e("--------", "ACTION_CANCEL")}//自己处理requestDisallowInterceptTouchEvent(true)if (scaleableView != null) {if (!isDismissAnimating) {dismissWithAnimator()}return true}}MotionEvent.ACTION_POINTER_DOWN -> {if (mOneOrTwoListener!=null){mOneOrTwoListener!!.onTwoPoint()}Log.e("--------", "ACTION_POINTER_DOWN")//自己处理requestDisallowInterceptTouchEvent(true)if (scaleableView == null && childCount > 0) {scaleableView = getChildAt(0)originalXY = IntArray(2)scaleableView?.getLocationOnScreen(originalXY)dialog = ScaleDialog(context)dialog?.show()viewLayoutParams = scaleableView!!.layoutParamsdialogFrameLayoutParams =LayoutParams(scaleableView!!.width, scaleableView!!.height).apply {leftMargin = originalXY!![0]topMargin = originalXY!![1]}postDelayed({if (scaleableView != null && scaleableView?.parent == this && !isDismissAnimating) {removeView(scaleableView)dialog?.addView(scaleableView!!, dialogFrameLayoutParams)}}, 80)}originalDistance = getDistance(ev)if (originalTwoPointerCenter == null) {originalTwoPointerCenter = Point()}originalTwoPointerCenter?.x = getTwoPointerCenterX(ev)originalTwoPointerCenter?.y = getTwoPointerCenterY(ev)return true}MotionEvent.ACTION_MOVE -> {Log.e("--------", "ACTION_MOVE")if (scaleableView != null && scaleableView?.parent != this) {if (ev.pointerCount == 2) {if (mOneOrTwoListener!=null){mOneOrTwoListener!!.onTwoPoint()}// 双指距离和距离比例moveDistance = getDistance(ev)moveDistanceIncrement =(moveDistance.toFloat() - originalDistance.toFloat()) / originalDistance.toFloat()// 关键点:// 1.设置pivotX和pivotY为view左上角,相比View中心点更容易计算缩放后的位移// 2.位移计算公式 (触摸屏幕时的坐标 * 缩放比 = 缩放后的坐标,当前两指中心点 - 缩放后的坐标 + 触摸屏幕时的leftMargin和topMargin = left和top最终需要的位移)// leftMargin = 当前两指中心点的x坐标 - 首次触摸屏幕时两指中心点的x坐标 乘以 缩放比 + 首次触摸时的原始leftMargin// topMargin同上,将x换成y// 缩放moveScale = 1 + moveDistanceIncrementmoveScale = max(0.5f, moveScale)moveScale = min(3.0f, moveScale)if (moveScale < 1) {if (mListener != null) {mListener!!.onScaleEnd(false)}} else if (moveScale > 1) {//手指按下直接设置展示if (mListener != null) {mListener!!.onScaleEnd(true)}}scaleableView?.run {pivotX = 0fpivotY = 0fscaleX = moveScalescaleY = moveScale}// 位移if (originalTwoPointerCenter != null && originalXY != null) {updateOffset((getTwoPointerCenterX(ev) - originalTwoPointerCenter!!.x * moveScale) + originalXY!![0].toFloat(),(getTwoPointerCenterY(ev) - originalTwoPointerCenter!!.y * moveScale) + originalXY!![1].toFloat())}// 透明背景dialog?.setShadowAlpha(max(min(0.8f, moveDistanceIncrement / 1.5f), 0f))return true} else if (ev.pointerCount == 1) { //单指移动updateOffset(getOnePointerCenterX(ev) - getOnePointerCenterX(ev) * moveScale,getOnePointerCenterY(ev) - getOnePointerCenterY(ev) * moveScale)// 透明背景dialog?.setShadowAlpha(max(min(0.8f, moveDistanceIncrement / 1.5f), 0f))return true}}}}//事件继续向下分发return super.dispatchTouchEvent(ev)}...
}
如果你使用的有下拉刷新,注意把下拉、上拉进行动态控制,否则在滑动中会系统通知ACTION_CANCEL;
仿抖音视频双指缩放和单指滑动效果相关推荐
- html5仿抖音全屏播放,仿抖音视频全屏播放滑动切换
1 前言 随着移动技术的快速迭代,数据流量费用的快速下降,视频.直播正成为全民的媒体盛宴,我司必然也不会缺席此次盛宴,这里讲述的是通过h5实现仿抖音视频全屏播放&滑动切换的效果,供我司直播鉴定 ...
- Android直播头像动画,iOS 仿抖音直播头像缩放动画
效果图 仿抖音直播头像缩放效果, 简单写了demo, 思路简单, 直接用的递归重复调用, 呈上所有代码. @interface YCXHeaderZoomViewController () @prop ...
- Android 使用ViewPager2+ExoPlayer+VideoCache 实现仿抖音视频翻页播放
1. 实现效果 效果图中,视频没有铺满 是因为使用了ExoPlayer的RESIZE_MODE_FIT模式, 虽然使用RESIZE_MODE_FILL模式可以填充整个父布局,但是本Demo中使用的视频 ...
- html5仿抖音切换效果,仿抖音视频滑动效果
更新记录 1.6.2(2020-06-04) 优化css3动画效果 1.6.1(2020-05-23) 1.修复串音 2.新增进度条 3.新增弹幕 查看更多 scroll-video uniapp仿抖 ...
- 仿抖音视频自动播放html,vue 仿抖音视频列表(兼容微信内置X5浏览器)
制作 仿抖音视频列表遇到很多坑,特别是安卓微信内置浏览器,让人脑壳疼,核心代码不多 便于理解 组件用到了vant 中的swiper滑动组件 h5 原生 video 属性 webkit-playsinl ...
- vue仿抖音视频列表(兼容微信内置X5浏览器)
vue 仿抖音视频列表(兼容微信内置X5浏览器)https://blog.csdn.net/superKM/article/details/87603255制作 仿抖音视频列表遇到很多坑,特别是安卓微 ...
- 微信小程序仿抖音视频
微信小程序仿抖音视频 使用轮播图实现视频滑动效果. wxml 部分 <view class="video-contain"><!-- 自定义头部 -->&l ...
- android图片双指缩放,Android图片双指缩放,单指移动实现
Android 实现,图片双指缩放,单指移动.通过自定义ImageView控件实现. ZoomDragImageView.java代码如下: public class SwZoomDragImageV ...
- Android 仿抖音视频播放列表和评论列表
Android 汇集CSDN.GitHub等最实用的良心之作-KING Android最实用的各种技能点的网址链接(每天都会更新,希望大家用的上) Android 仿抖音系列之视频播放列表和评论列表 ...
最新文章
- 数据结构_顺序栈的代码实践
- mysql教程联合索引_MySQL中的联合索引学习教程
- 混合云如何落地?光环有云携手AWS一触即发
- VTK:PolyData之RibbonFilter
- ORACLE TEXT DATASTORE PREFERENCE(二)
- csrf spring_无状态Spring安全性第1部分:无状态CSRF保护
- hive 集成sentry
- 大数据之Hive教程
- 高质量程序设计指南c++/c语言(14)--函数指针
- ORACLE 制定时间 加N月
- sql语句有没有怎么优化的空间,这条语句在我这里执行是死机
- SPSS遇到缺失值怎么办?删除还是替换?【SPSS 067期】
- 编辑实测:迅捷PDF转换器怎么将PDF转换成JPG
- python下载大文件mp4_Python 实现视频爬取下载及断点续传优化、异步下载
- linux开机禁用vga设备,用vga_switcheroo在Linux下(开启KMS)彻底关闭某一可切换显卡的简单教程...
- 《电脑商情报》国内信号最强,有效距离最远的四种无线网卡
- 电路分析 极简复习指导、公式推导、常用结论归纳 第十章 含有耦合电感的电路
- 【VS开发】error C2220: 警告被视为错误 - 没有生成“object”文件
- auto.ja 部落冲突01 找图并点击
- jquery--拖拽效果
热门文章
- 根据字符串最后一次出现的位置将这个字符串拆分字符串为数组
- java直播毕业设计,使用red5,obs,video.js仿bilibili实现一个视频直播网站
- Vaadin Web应用开发教程(37):可视化界面编辑插件
- swep在C语言中的头文件,C ++ STL中的queue :: swap()
- Makefile中的ifeq 多条件使用
- android 服务 结束,android – onDestroy被调用但服务没有结束
- [可视化]时间线的7种设计方式
- React Native真机运行apk安装失败: com.android.ddmlib.InstallException: INSTALL_FAILED_USER_RESTRICTED
- python中有哪些颜色_8种颜色中哪一种最准确?
- Scrum是敏捷开发中的一种形式,它提供了一系列流程、方法、工具,旨在帮助项目团队保持高效、可持续地交付价值