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

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

1、基本原理

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

2、Activity

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

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

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

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

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

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

3、FlingView

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

  1. public void onFling(int paramFloat1) {
  2. if (offsetX > GalleryDemoActivity.deviceScreenWidth / 5) {
  3. if (fBitmap != null) {
  4. isFling = true;
  5. isFlingRight = true;
  6. }
  7. } else if (offsetX < -GalleryDemoActivity.deviceScreenWidth / 5) {
  8. if (nBitmap != null) {
  9. isFling = true;
  10. isFlingLeft = true;
  11. }
  12. }
  13. // 开始动画效果
  14. startAnimation(new MyAnimation());
  15. }

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

  1. @Override
  2. public void draw(Canvas canvas) {
  3. Paint paint = new Paint();
  4. Rect rect = new Rect();
  5. canvas.drawColor(Color.BLACK);
  6. // 绘制当前图片
  7. if (bitmap != null) {
  8. int left = offsetX;
  9. int top = offsetY;
  10. int right = offsetX + GalleryDemoActivity.deviceScreenWidth;
  11. int bottom = offsetY + GalleryDemoActivity.deviceScreenHeight;
  12. rect.set(left, top, right, bottom);
  13. canvas.drawBitmap(bitmap, null, rect, paint);
  14. }
  15. // 绘制下一张图片
  16. if (offsetX < 0) {           // 向左滑动
  17. if (nBitmap != null) {
  18. int left = GalleryDemoActivity.deviceScreenWidth + 15 + offsetX;
  19. int top = 0;
  20. int right = left + GalleryDemoActivity.deviceScreenWidth;
  21. int bottom = GalleryDemoActivity.deviceScreenHeight;
  22. rect.set(left, top, right, bottom);
  23. canvas.drawBitmap(nBitmap, null, rect, paint);
  24. }
  25. } else if (offsetX > 0) {        // 向右滑动
  26. if (fBitmap != null) {
  27. int left = -GalleryDemoActivity.deviceScreenWidth - 15 + offsetX;
  28. int top = 0;
  29. int right = left + GalleryDemoActivity.deviceScreenWidth;
  30. int bottom = GalleryDemoActivity.deviceScreenHeight;
  31. rect.set(left, top, right, bottom);
  32. canvas.drawBitmap(fBitmap, null, rect, paint);
  33. }
  34. }
  35. }

在滑动图片结束后,需要做滑动动画后的处理,重新设置当前图片和当前图片的上一张和下一张的状态,为下次滑动做准备

  1. @Override
  2. protected void onAnimationEnd() {
  3. if (isFlingRight) {         // 向右滑动,position减1
  4. nBitmap = bitmap;
  5. bitmap = fBitmap;
  6. fBitmap = null;
  7. postion = postion - 1;
  8. } else if (isFlingLeft) {       // 向左滑动,position加1
  9. fBitmap = bitmap;
  10. bitmap = nBitmap;
  11. nBitmap = null;
  12. postion = postion + 1;
  13. }
  14. isFlingRight = false;
  15. isFlingLeft = false;
  16. isFling = false;
  17. offsetX = 0;
  18. if (fBitmap == null && offsetX == 0) {          // 如果前一张图片为空(向右滑),则重置前一张图片(position - 1)
  19. if (postion > 0) {
  20. fBitmap = getBitmap(postion - 1);
  21. }
  22. } else if (nBitmap == null && offsetX == 0) {       // 如果后一张图片为空(向左滑),则重置后一张图片(position + 1)
  23. if (postion < bitmaps.length - 1) {
  24. nBitmap = getBitmap(postion + 1);
  25. }
  26. }
  27. clearAnimation();
  28. }

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方向正好相反

Android 滑动效果基础篇(三)—— Gallery仿图像集浏览的更多相关文章

  1. Android 滑动效果基础篇(四)—— Gallery + GridView

    Android系统自带一个GridView和Gallery两个控件,GridView网格显示,Gallery单个浏览,两者结合起来可以真正实现Gallery浏览图片效果. 本示例通过GridView和 ...

  2. Android 滑动效果进阶篇(六)—— 倒影效果

    上篇介绍了使用Animation实现3D动画旋转翻页效果,现在介绍图片倒影实现,先看效果图 本示例主要通过自定义Gallery和ImageAdapter(继承自BaseAdapter)实现 1.倒影绘 ...

  3. Android 滑动效果入门篇(二)—— Gallery

    Gallery 是Android官方提供的一个View容器类,继承于AbsSpinner类,用于实现页面滑动效果. 从上面的继承关系可以看出,AbsSpinner类继承自AdapterView,因此我 ...

  4. Android 滑动效果高级篇(八)—— 自定义控件

    自定义控件,较常用View.ViewGroup.Scroller三个类,其继承关系如下: 本示例自定义控件,实现一个Gallery效果,并添加了一个显示View个数和位置的bar条,效果图: 自定义控 ...

  5. Android 滑动效果入门篇(一)—— ViewFlipper

    ViewFilpper 是Android官方提供的一个View容器类,继承于ViewAnimator类,用于实现页面切换,也可以设定时间间隔,让它自动播放.又ViewAnimator继承至于Frame ...

  6. Android 滑动效果进阶篇(五)—— 3D旋转

    前面介绍了利用Android自带的控件,进行滑动翻页制作效果,现在我们通过代码实现一些滑动翻页的动画效果. Animation实现动画有两个方式:帧动画(frame-by-frame animatio ...

  7. Android 滑动效果高级篇(七)—— 华丽翻页效果

    By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 之前看到像ipad上的ibook的模拟书籍翻页的特效感觉很炫,在android上也有像laputa和ireader ...

  8. 十六、Android 滑动效果汇总

    Android 滑动效果入门篇(一)—— ViewFlipper Android 滑动效果入门篇(二)—— Gallery Android 滑动效果基础篇(三)—— Gallery仿图像集浏览 And ...

  9. Android 滑动效果汇总

    Android 滑动效果入门篇(一)—— ViewFlipper Android 滑动效果入门篇(二)—— Gallery Android 滑动效果基础篇(三)—— Gallery仿图像集浏览 And ...

随机推荐

  1. C#中常见的winform控件命名规范

    我们知道Button 常常简称为btn,那么Winform中的其它控件呢,这篇文章在C#的winform控件命名规范 的基础上对一些控件的名称的简称进行了整理. 1. 标准控件 NO. 控件类型简写 ...

  2. ASIHTTPREQUEST 文档

    http://blog.csdn.net/ysysbaobei/article/details/17026577 Please note that I am no longer working on ...

  3. 为Fitnesse-20140630定制RestFixture代码

    摘要:Fitnesse插件RestFixture在最新版Fitnesse输出测试结果为html文本,而非html.本博文记录RestFixture定制代码的过程. 准备开发环境 假定你已经正确安装JD ...

  4. 通过实验分析system_call中断处理过程

    作者:吴乐 山东师范大学 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 本实验目的:通过以一个简单的m ...

  5. ORA-15005: name "orcl" is already used by an existing alias

    在进行ASM操作的时候,如果目录不存在的话,那么可能会报如下的错误: <pre name="code" class="plain">RMAN> ...

  6. leetcode—Swap Nodes in Pairs

    1.题目描述 Given a linked list, swap every two adjacent nodes and return its head.   For example, Given ...

  7. 为了以后愉快的玩耍,Virtualbox安装Ubuntu

    为了以后愉快的玩耍,Virtualbox安装Ubuntu 每次安装虚拟机都是总要折腾一下,毕竟不是特别熟悉,几个小细节总要google半天,为了以后能愉快的玩耍.把这些问题都记录下来,免得再折腾. 此 ...

  8. 生成chm文档工具- Sandcastle -摘自网络

    Sandcastle是微软官方的文档生成工具,NDoc开发停止后,这个貌似也是唯一的一个这方面的工具.它从dll文件及其xml注释文件能够 生成完整的帮助文档,支持多种生成格式(Helpe1x:chm ...

  9. iOS 8 Xcode6 设置Launch Image 启动图片<转>

    Step1 1.点击Image.xcassets 进入图片管理,然后右击,弹出"New Launch Image" 2.如图,右侧的勾选可以让你选择是否要对ipad,横屏,竖屏,以 ...

  10. mysql 错误解决

    1. Error Code: 1175. You are using safe update mode and you tried to update a table without a WHERE ...