这次学着做了一个可以左右触控来切换图片的DEMO,类似于漫画阅读器(布卡)的功能。

主要有下面两个技术点

1、GestureDetector类

主要是监听用户用手指在屏幕上的各种操作,然后根据操作来处理事件。

2、ViewFlipper控件

放滚动图片的容器,所有的功能也是基于此来实现的

看上去挺简单的,我要实现的是什么样的功能呢?

我把这个DEMO叫做漫画阅读器,打开应用,出来漫画的第一页,我手指对着屏幕由右向左划动,就切换到下一页漫画图片上。反之则是上一页。

OK,接下来就来实现。

老样子,先做页面布局。

activity_main.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><ViewFlipperandroid:layout_width="fill_parent"android:layout_height="fill_parent"android:id="@+id/viewFlipper"android:layout_gravity="center_vertical" />
</LinearLayout>

在这里我创建了一个ViewFlipper的小控件。这是Android专门用来做屏幕滑动用的。

接下来就是代码实现

    protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);viewFlipper = (ViewFlipper)findViewById(R.id.viewFlipper);viewFlipper.setOnTouchListener(new View.OnTouchListener() {@Overridepublic boolean onTouch(View v, MotionEvent event) {boolean b = detector.onTouchEvent(event);/*这里监听的是手从屏幕上松开的事件。因为flip事件感觉总是监听不到,需要在上面的detector.onTouchEvent没有监听到任何事件时,重新做一下校验*/if(b == false){if(event.getAction() == event.ACTION_UP){//右向左划了一下,间距超过120像素了,切换图片if(viewFlipper.getCurrentView().getX()< -120){if(id<count) {viewFlipper.showNext();nextView = null;}//左向向划了一下,间距超过120像素了,切换图片}else if(viewFlipper.getCurrentView().getX()> 120){if(id>0) {viewFlipper.showPrevious();prevView = null;}}//更新当前图片的坐标,免得在屏幕上显示不正确viewFlipper.getCurrentView().setX(0);//Log.d(TAG,"现在的坐标定在?"+viewFlipper.getCurrentView().getX());}}return b;}});

在这里,我给viewFlipper分配了setOnTouchListener的事件,用来监听用户用手指在屏幕上的各种操作。不过很可惜。

看介绍说setOnTouchListener这个事件能做的事情并不多。

也无非就是按下,抬起之类的,不过我看源码里面好像蛮多的,

ACTION_UP
ACTION_CANCEL
ACTION_MOVE
ACTION_POINTER_UP
ACTION_POINTER_DOWN

等等……等等,有兴趣可以写代码一个一个试。而我这次决定用GestureDetector类来试一下

GestureDetector类是一个手势类,简单来就是可以识别很多的手势,所以我就用这个了。

从代码上看,GestureDetector类是要注入到OnTouchListener里面的。两者是相辅相成的,而不是说可以独立存在。

boolean b = detector.onTouchEvent(event);

就是创建的拦截方法,他截取了event事件,并且重新做解析。

然后完成以后,会返回true或false告诉你这次的事件是否处理完成。

这有什么用?用处就是万一他没处理好的话,我还可以用OnTouchListener再弥补一下

if(b==false)这一段就是在用户的手指离开屏幕后,我会再进行一次处理。前提是GestureDetector类没有很好的处理我的事件。

接下来就是detector这个方法的实现了。

GestureDetector类是一个抽象类,需要我去具体实现。

        detector = new GestureDetector(this, new GestureDetector.OnGestureListener() {@Overridepublic boolean onDown(MotionEvent e) {//Log.d(TAG,"onDown");return true;}@Overridepublic void onShowPress(MotionEvent e) {// Log.d(TAG,"onShowPress");}@Overridepublic boolean onSingleTapUp(MotionEvent e) {// Log.d(TAG,"onSingleTapUp");return false;}@Overridepublic boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {Log.d(TAG,"onScroll: e1="+e1.getX()+",e2="+e2.getX());int nextId; //上一张图的索引int prevId; //下一张图的索引float offset = e1.getX()-e2.getX();float x = viewFlipper.getX();//当前正在显示的图片索引id = viewFlipper.getDisplayedChild();//如果已经到最后的话if(id>=count && offset>0){//最后一页了,所以不用再翻页viewFlipper.getCurrentView().setX(x-offset);}else if(id<=0 && offset<0) {//第一页,不用再往前翻viewFlipper.getCurrentView().setX(x-offset);}else{//其它情况//重新定义当前图片的坐标,跟着手势走viewFlipper.getCurrentView().setX(x - offset);if(offset<0){   //手势是从左向右移prevId = id-1;  //取上一张图片的索引prevView = viewFlipper.getChildAt(prevId);  //上一张图prevView.setVisibility(View.VISIBLE);//紧贴前面一张图prevView.setX(viewFlipper.getCurrentView().getX() - prevView.getWidth());}else{  //手势是从右移向右的nextId = id+1;  //取下一张图片的索引nextView = viewFlipper.getChildAt(nextId); //下一张图片nextView.setVisibility(View.VISIBLE);   //设置为可见//紧贴前面一张图nextView.setX(viewFlipper.getCurrentView().getX()+viewFlipper.getCurrentView().getWidth());}}return true;}@Overridepublic void onLongPress(MotionEvent e) {// Log.d(TAG,"onLongPress");}@Overridepublic boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {Log.d(TAG,"onFling");Log.i(TAG, "e1=" + e1.getX() + " e2=" + e2.getX() + " e1-e2=" + (e1.getX() - e2.getX()));/*两种情况:一种是最后一页,并且是在做从右划到左的操作的时候一种是第一页,并且是在做从左划到右的操作的时候都不需要做图片切换,直接重置当前图片的坐标*/if((id>=count && (e1.getX() - e2.getX()>0)) || (id<= 0 && (e1.getX() - e2.getX()<0))){viewFlipper.getCurrentView().setX(0);return false;}//从右划到左的时候,只要超过120个象素就认为是成功的手势操作if(e1.getX()-e2.getX()>120){viewFlipper.showNext();viewFlipper.getCurrentView().setX(0);nextView = null;return true;}else if(e1.getX()-e2.getX()<-120){//从左划到右viewFlipper.showPrevious();viewFlipper.getCurrentView().setX(0);prevView = null;return true;}//都不是,初始化图片的位置viewFlipper.getCurrentView().setX(0);if(nextView!=null) {nextView.setVisibility(View.INVISIBLE);   //设置为不可见}if(prevView!=null) {prevView.setVisibility(View.INVISIBLE);   //设置为不可见}return false;}});

这里共继承了它的6种事件

onDown:用户按下屏幕就会触发
onShowPress:非常短的时间内按下
onSingleTapUp:轻击一下屏幕
onScroll:手指在屏上划来划去
onLongPress:长按触摸屏
onFling:按下屏幕,划动后离开
嗯,这次我就用了两个事件onScroll和onFling
其它的……先不用了。
这里有要注间的就是return false,如果你要用onFling事件,你的onDown事件就设置成return true,不然的话他会直接不触发onFling事件的,我搞了老半天才弄清楚。

其它的具体逻辑代码可以看注释。

关于手指操作屏幕的处理我这就结束了。

接下来就是要把图片弄进去。

        //detector = new GestureDetector(this);//往viewFlipper添加ViewviewFlipper.addView(getImageView(R.drawable.page_1));viewFlipper.addView(getImageView(R.drawable.page_2));viewFlipper.addView(getImageView(R.drawable.page_3));viewFlipper.addView(getImageView(R.drawable.page_4));viewFlipper.addView(getImageView(R.drawable.page_5));viewFlipper.addView(getImageView(R.drawable.page_6));count = viewFlipper.getChildCount()-1;//禁止自动播放viewFlipper.setAutoStart(false);

我一共弄了六张图片,做为一个测试。其实就是addView,把图片对象加到viewFlipper控件中去,超简单。

不过图片是要对象形式送进去的,所以我还得去加载一下图片资源

    private ImageView getImageView(int id){ImageView imageView = new ImageView(this);Bitmap bitmap=readBitMap(MainActivity.this,id);imageView.setImageBitmap(bitmap);/*注释掉的这段不行。实在是太慢了。ImageView imageView = new ImageView(this);imageView.setImageResource(id);imageView.setScaleType(ImageView.ScaleType.FIT_XY);*/return imageView;}/*** 以最省内存的方式读取本地资源的图片* 这段函数网上抄的,确实比之前的setImageResource要快数倍** @param context* @param resId* @return*/public static Bitmap readBitMap(Context context, int resId) {BitmapFactory.Options opt = new BitmapFactory.Options();opt.inPreferredConfig = Bitmap.Config.RGB_565;//下面这两个函数过期了。所以不用了//opt.inPurgeable = true;//opt.inInputShareable = true;// 获取资源图片InputStream is = context.getResources().openRawResource(resId);return BitmapFactory.decodeStream(is, null, opt);}

原先我用的是setImageResource的方法,而且网上很多也是用这个方法,但是不得不说。。。这个方法实在是太差了。没办法用,我六张图片一加载,卡成狗了。

所以我又在网上找了一下,用新的方法,readBitMap

顿时丝般软滑。。

然后……然后就全部完成了。

嗯。。虽然简单,但是其中的一些逻辑和用法也搞了我好久。

比如我看到网上很多用的是

public class MainActivity extends Activity implements OnTouchListener

来继承触摸方法,再声明

mGestureDetector = new GestureDetector(new gestureListener());

不过现在新的SDK里面已经不支持这样的用法了。

另外这只是提供一种思路,并不一定是对的,像图片资源的加载,如果真要做成在线阅读的形式,还要考虑到怎么样通过网络去获得图片,然后自动由程序来读取。

现在6张图片还可以,如果是60张,600张呢?在性能的优化上还是需要考虑的。

附上DEMO下载:

http://download.csdn.net/detail/gundamzaku/8857279

效果图:

    



一个模仿布卡那样的划动手势看在线漫画的简单应用DEMO相关推荐

  1. [html] 如何禁止移动端的左右划动手势?

    [html] 如何禁止移动端的左右划动手势? html{touch-action:none;touch-action:pan-y;} 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但 ...

  2. 解决android模拟器划动手势时自动输入字母“c” 的问题

    以下内容转载自互联网,仅供个人学习之用. 个案一: android开发,一直受到一个问题的困扰,就是模拟器使用的时候,用鼠标和键盘点击,总是会不停地弹出输入框,并且不停地输入字母'c'. 最近终于通过 ...

  3. 【转】让Chrome化身成为摸鱼神器,利用Chorme运行布卡漫画以及其他安卓APK应用教程...

    下周就是十一了,无论是学生党还是工作党,大家的大概都会有点心不在焉,为了让大家更好的心不在焉,更好的在十一前最后一周愉快的摸鱼,今天就写一个如何让Chrome(google浏览器)运行安卓APK应用的 ...

  4. Swift开发:仿Clear手势操作(拖拽、划动、捏合)UITableView

    2019独角兽企业重金招聘Python工程师标准>>> 这是一个完全依靠手势的操作ToDoList的演示,功能上左划删除,右划完成任务,拖拽调整顺序,捏合张开插入. 项目源码: ht ...

  5. iphone练习之手势识别(双击、捏、旋转、拖动、划动、长按)UITapGestureRecognizer...

    首先新建一个基于Sigle view Application的项目,名为GestureTest;我的项目结构如下: 往viewController.xib文件里拖动一个imageView,并使覆盖整个 ...

  6. UIScrollView 平滑划动处理

    iOS开发经常会用到UIScrollView,而能够平滑的展示划动效果,是至关重要的.比较常用的方法有两种: 1)将所有的scrollview子页面都add到scrollview中,这样可以平滑滑动, ...

  7. UITableView实现划动删除

    先前的准备工作: 第一步,准备好数据源. #import <UIKit/UIKit.h> @interface UITableCellSwapDeleteViewController : ...

  8. HTML5期末大作业:漫画网站设计——布卡漫画官网(4页) HTML+CSS+JavaScript 学生DW网页设计作业成品 w学生原创课程设计漫画设计制作大作业成品免费下载

    HTML5期末大作业:漫画网站设计--布卡漫画官网(4页) HTML+CSS+JavaScript 学生DW网页设计作业成品 w学生原创课程设计漫画设计制作大作业成品免费下载 常见网页设计作业题材有 ...

  9. Android 自定义控件之圆形页面指示器CirclePageIndicator带划动效果

    Android 自定义控件之圆形页面指示器CirclePageIndicator带划动效果 前言 感谢 效果图 目标 流程 自定义属性 自定义默认属性 自定义接口 创建控件类继承View 声明属性变量 ...

最新文章

  1. 除了百度,国内还有哪些无人驾驶公司?
  2. 计算机专业教育,科学网—中国大学计算机教育路在何方? - 吴军的博文
  3. 吴恩达机器学习笔记 —— 9 神经网络学习
  4. torch The “freeze_support()” line can be omitted if the programis not going to be frozen to produce
  5. c语言循环程序设计教案,10 《C语言程序设计》教案 第三章 程序的控制结构(6)—循环结构 while和do while.doc...
  6. 学业水平考试网登录_江西2020年下半年普通高中学业水平考试成绩查询时间及入口...
  7. vue mianjs 引用css_7个有用的Vue开发技巧
  8. SysUtils.UpperCase、SysUtils.LowerCase - 大小写转换
  9. 树莓派-迅雷远程下载
  10. utc时间 单位换算_DataTime.Now.Ticks精确的时间单位[转]
  11. 【C++】重定义,重载,重写
  12. 【路径规划】基于粒子群算法机器人避障路径规划matlab代码
  13. 胡须清洗的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
  14. 跟领导汇报工作时,这句话建议你不要说
  15. java毕业设计_企业销售合同管理系统
  16. 一种在外部中心化基础下的网络空间去中心化充盈区块链系统
  17. 第四章 浮动 ① 笔记
  18. 什么是 EventLoop ?
  19. 飞利浦智慧路灯推动城市物联网
  20. SQL添加字段、删除字段、调整字段顺序

热门文章

  1. eCharts.js使用心得
  2. VB6如何引用VBDX9.tlb-------VB6编程学习DX9游戏编程DirectX9编程2D小游戏源码冷风引擎CoolWind2D游戏引擎(2)
  3. 【机器学习】决策树特征选择准则 信息增益、信息增益率、基尼系数的计算及其python实现
  4. CodeGear RAD 2007 up4最新下载及破解
  5. 内网安全:内网穿透详解
  6. john破解用户密码和防破解
  7. 从月薪 2000 到月入 20 万,我这一路上的可复制与不可复制
  8. 趣学python教孩子学编程_《趣学Python——教孩子学编程》学习笔记第1-3章
  9. Windows Jar包开机自启动
  10. 3分钟学习下射频放大器基础知识