当前位置: 首页 > news >正文

Android 滑动效果基础篇(三)—— Gallery仿图像集浏览

Android系统自带一个Gallery浏览图片的应用,通过手指拖动时能够非常流畅的显示图片,用户交互和体验都很好。


本示例就是通过Gallery和自定义的View,模仿实现一个仿Gallery图像集的图片浏览效果。效果图如下:



1、基本原理

在 Activity 中实现OnGestureListener 的接口onFling() 手势事件,通过自定义的 View绘制draw() 图片


2、Activity

Activity中,通过onTouchEvent() 注册myGesture.onTouchEvent(event)

@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_UP: flingView.onFling(0); // 手指抬起后,重置滑动距离offsetX = 0 break; } return myGesture.onTouchEvent(event); }

接着实现接口OnGestureListener 的 onScroll()方法,给继承自View的 FlingView 的handleScroll()成员方法传递滑动参数,获取滑动的x轴距离

@Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { flingView.handleScroll(-1 * (int) distanceX); return true; }

接着实现接口OnGestureListener 的 OnFling()方法,给继承自View的 FlingView 的onFling()成员方法传递滑动参数,获取手势的速度

@Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { flingView.onFling((int) - velocityX); return true; }

3、FlingView

FlingView中,获取来自Activity中的手势速度

public void onFling(int paramFloat1) { if (offsetX > GalleryDemoActivity.deviceScreenWidth / 5) { if (fBitmap != null) { isFling = true; isFlingRight = true; } } else if (offsetX < -GalleryDemoActivity.deviceScreenWidth / 5) { if (nBitmap != null) { isFling = true; isFlingLeft = true; } } // 开始动画效果 startAnimation(new MyAnimation()); }

在滑动过程中,通过实现View的Draw()方法绘制图片,注意:此时需要同时绘制当前图片(获取焦点)和下一张图片(即将获取焦点)共两张图片

@Override public void draw(Canvas canvas) { Paint paint = new Paint(); Rect rect = new Rect(); canvas.drawColor(Color.BLACK); // 绘制当前图片 if (bitmap != null) { int left = offsetX; int top = offsetY; int right = offsetX + GalleryDemoActivity.deviceScreenWidth; int bottom = offsetY + GalleryDemoActivity.deviceScreenHeight; rect.set(left, top, right, bottom); canvas.drawBitmap(bitmap, null, rect, paint); } // 绘制下一张图片 if (offsetX < 0) { // 向左滑动 if (nBitmap != null) { int left = GalleryDemoActivity.deviceScreenWidth + 15 + offsetX; int top = 0; int right = left + GalleryDemoActivity.deviceScreenWidth; int bottom = GalleryDemoActivity.deviceScreenHeight; rect.set(left, top, right, bottom); canvas.drawBitmap(nBitmap, null, rect, paint); } } else if (offsetX > 0) { // 向右滑动 if (fBitmap != null) { int left = -GalleryDemoActivity.deviceScreenWidth - 15 + offsetX; int top = 0; int right = left + GalleryDemoActivity.deviceScreenWidth; int bottom = GalleryDemoActivity.deviceScreenHeight; rect.set(left, top, right, bottom); canvas.drawBitmap(fBitmap, null, rect, paint); } } }在滑动图片结束后,需要做滑动动画后的处理,重新设置当前图片和当前图片的上一张和下一张的状态,为下次滑动做准备

@Override protected void onAnimationEnd() { if (isFlingRight) { // 向右滑动,position减1 nBitmap = bitmap; bitmap = fBitmap; fBitmap = null; postion = postion - 1; } else if (isFlingLeft) { // 向左滑动,position加1 fBitmap = bitmap; bitmap = nBitmap; nBitmap = null; postion = postion + 1; } isFlingRight = false; isFlingLeft = false; isFling = false; offsetX = 0; if (fBitmap == null && offsetX == 0) { // 如果前一张图片为空(向右滑),则重置前一张图片(position - 1) if (postion > 0) { fBitmap = getBitmap(postion - 1); } } else if (nBitmap == null && offsetX == 0) { // 如果后一张图片为空(向左滑),则重置后一张图片(position + 1) if (postion < bitmaps.length - 1) { nBitmap = getBitmap(postion + 1); } } clearAnimation(); }

4、手势坐标介绍

本示例中,用到了OnGestureListener接口的onScroll()和OnFling()方法,涉及到了Android系统坐标及触摸MotionEvent e1和e2、速度velocityX、velocityY等值

Android屏幕坐标系如下图(左)


(1)MotionEvent中 e1是手指第一次按上屏幕的起点,e2是抬起手指离开屏幕的终点,根据上图Android屏幕坐标系可知:

手指向滑动,终点(e2)在起点(e1)的右侧,有e2.getX() - e1.getX() 大于0
手指向左滑动,终点(e2)在起点(e1)的左侧,有e2.getX() - e1.getX() 小于0
手指向滑动,终点(e2)在起点(e1)的下侧,有e2.getY() - e1.getY() 大于0
手指向上滑动,终点(e2)在起点(e1)的上侧,有e2.getY() - e1.getY() 小于0


(2)onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY)

distanceX,是前后两次call的X距离,不是e2与e1的水平距离

distanceX,是前后两次call的Y距离,不是e2与e1的垂直距离

具体数值的方向,请详见上图(中)


(3)onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)

velocityX,是X轴的每秒速度

velocityY,是Y轴的每秒速度

具体数值的方向,请详见上图(右)

仔细观察可以发现:velocityX、velocityY的方向与distanceX、distanceY方向正好相反


更多OnGestureListener接口函数介绍,请见上一篇博客Android 滑动效果入门篇(一)—— ViewFlipper



示例源码下载


相关文章:

  • 笔试之const问题
  • 【IOS】《捕鱼达人》的简单实现(一)
  • 2018.5.23 创建用户并授权序列
  • MFC双缓冲 防止闪屏
  • js数组操作
  • React-router
  • SourceEngine中的粒子系统
  • Java并发编程(五)锁的使用(下)
  • FilmicToneMapping
  • 一对多关联按照一方的id查找信息的一个笛卡尔积问题
  • Android 滑动效果基础篇(四)—— Gallery + GridView
  • lvm基本应用(自我整理)
  • 【IOS】多语言资源文件加载的一种解决方案
  • BZOJ4725: [POI2017]Reprezentacje ró?nicowe
  • Log4j和thymeleaf结合导致sql 日志输出不了
  • [NodeJS] 关于Buffer
  • Druid 在有赞的实践
  • FineReport中如何实现自动滚屏效果
  • Java小白进阶笔记(3)-初级面向对象
  • Joomla 2.x, 3.x useful code cheatsheet
  • PHP的类修饰符与访问修饰符
  • python 装饰器(一)
  • vue-router的history模式发布配置
  • 成为一名优秀的Developer的书单
  • 二维平面内的碰撞检测【一】
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 基于组件的设计工作流与界面抽象
  • 理解 C# 泛型接口中的协变与逆变(抗变)
  • 理解IaaS, PaaS, SaaS等云模型 (Cloud Models)
  • 漫谈开发设计中的一些“原则”及“设计哲学”
  • 排序算法学习笔记
  • 扫描识别控件Dynamic Web TWAIN v12.2发布,改进SSL证书
  • 删除表内多余的重复数据
  • 原生js练习题---第五课
  • 自制字幕遮挡器
  • SAP CRM里Lead通过工作流自动创建Opportunity的原理讲解 ...
  • 阿里云服务器如何修改远程端口?
  • 不要一棍子打翻所有黑盒模型,其实可以让它们发挥作用 ...
  • 机器人开始自主学习,是人类福祉,还是定时炸弹? ...
  • # 睡眠3秒_床上这样睡觉的人,睡眠质量多半不好
  • $(selector).each()和$.each()的区别
  • (delphi11最新学习资料) Object Pascal 学习笔记---第5章第5节(delphi中的指针)
  • (Mac上)使用Python进行matplotlib 画图时,中文显示不出来
  • (vue)el-checkbox 实现展示区分 label 和 value(展示值与选中获取值需不同)
  • (zhuan) 一些RL的文献(及笔记)
  • (板子)A* astar算法,AcWing第k短路+八数码 带注释
  • (附源码)基于ssm的模具配件账单管理系统 毕业设计 081848
  • (接口自动化)Python3操作MySQL数据库
  • (没学懂,待填坑)【动态规划】数位动态规划
  • (三)Pytorch快速搭建卷积神经网络模型实现手写数字识别(代码+详细注解)
  • (十八)用JAVA编写MP3解码器——迷你播放器
  • (原創) 如何刪除Windows Live Writer留在本機的文章? (Web) (Windows Live Writer)
  • (转) Android中ViewStub组件使用
  • (转)nsfocus-绿盟科技笔试题目
  • *2 echo、printf、mkdir命令的应用