一个模仿布卡那样的划动手势看在线漫画的简单应用DEMO
这次学着做了一个可以左右触控来切换图片的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相关推荐
- [html] 如何禁止移动端的左右划动手势?
[html] 如何禁止移动端的左右划动手势? html{touch-action:none;touch-action:pan-y;} 个人简介 我是歌谣,欢迎和大家一起交流前后端知识.放弃很容易, 但 ...
- 解决android模拟器划动手势时自动输入字母“c” 的问题
以下内容转载自互联网,仅供个人学习之用. 个案一: android开发,一直受到一个问题的困扰,就是模拟器使用的时候,用鼠标和键盘点击,总是会不停地弹出输入框,并且不停地输入字母'c'. 最近终于通过 ...
- 【转】让Chrome化身成为摸鱼神器,利用Chorme运行布卡漫画以及其他安卓APK应用教程...
下周就是十一了,无论是学生党还是工作党,大家的大概都会有点心不在焉,为了让大家更好的心不在焉,更好的在十一前最后一周愉快的摸鱼,今天就写一个如何让Chrome(google浏览器)运行安卓APK应用的 ...
- Swift开发:仿Clear手势操作(拖拽、划动、捏合)UITableView
2019独角兽企业重金招聘Python工程师标准>>> 这是一个完全依靠手势的操作ToDoList的演示,功能上左划删除,右划完成任务,拖拽调整顺序,捏合张开插入. 项目源码: ht ...
- iphone练习之手势识别(双击、捏、旋转、拖动、划动、长按)UITapGestureRecognizer...
首先新建一个基于Sigle view Application的项目,名为GestureTest;我的项目结构如下: 往viewController.xib文件里拖动一个imageView,并使覆盖整个 ...
- UIScrollView 平滑划动处理
iOS开发经常会用到UIScrollView,而能够平滑的展示划动效果,是至关重要的.比较常用的方法有两种: 1)将所有的scrollview子页面都add到scrollview中,这样可以平滑滑动, ...
- UITableView实现划动删除
先前的准备工作: 第一步,准备好数据源. #import <UIKit/UIKit.h> @interface UITableCellSwapDeleteViewController : ...
- HTML5期末大作业:漫画网站设计——布卡漫画官网(4页) HTML+CSS+JavaScript 学生DW网页设计作业成品 w学生原创课程设计漫画设计制作大作业成品免费下载
HTML5期末大作业:漫画网站设计--布卡漫画官网(4页) HTML+CSS+JavaScript 学生DW网页设计作业成品 w学生原创课程设计漫画设计制作大作业成品免费下载 常见网页设计作业题材有 ...
- Android 自定义控件之圆形页面指示器CirclePageIndicator带划动效果
Android 自定义控件之圆形页面指示器CirclePageIndicator带划动效果 前言 感谢 效果图 目标 流程 自定义属性 自定义默认属性 自定义接口 创建控件类继承View 声明属性变量 ...
最新文章
- 除了百度,国内还有哪些无人驾驶公司?
- 计算机专业教育,科学网—中国大学计算机教育路在何方? - 吴军的博文
- 吴恩达机器学习笔记 —— 9 神经网络学习
- torch The “freeze_support()” line can be omitted if the programis not going to be frozen to produce
- c语言循环程序设计教案,10 《C语言程序设计》教案 第三章 程序的控制结构(6)—循环结构 while和do while.doc...
- 学业水平考试网登录_江西2020年下半年普通高中学业水平考试成绩查询时间及入口...
- vue mianjs 引用css_7个有用的Vue开发技巧
- SysUtils.UpperCase、SysUtils.LowerCase - 大小写转换
- 树莓派-迅雷远程下载
- utc时间 单位换算_DataTime.Now.Ticks精确的时间单位[转]
- 【C++】重定义,重载,重写
- 【路径规划】基于粒子群算法机器人避障路径规划matlab代码
- 胡须清洗的全球与中国市场2022-2028年:技术、参与者、趋势、市场规模及占有率研究报告
- 跟领导汇报工作时,这句话建议你不要说
- java毕业设计_企业销售合同管理系统
- 一种在外部中心化基础下的网络空间去中心化充盈区块链系统
- 第四章 浮动 ① 笔记
- 什么是 EventLoop ?
- 飞利浦智慧路灯推动城市物联网
- SQL添加字段、删除字段、调整字段顺序
热门文章
- eCharts.js使用心得
- VB6如何引用VBDX9.tlb-------VB6编程学习DX9游戏编程DirectX9编程2D小游戏源码冷风引擎CoolWind2D游戏引擎(2)
- 【机器学习】决策树特征选择准则 信息增益、信息增益率、基尼系数的计算及其python实现
- CodeGear RAD 2007 up4最新下载及破解
- 内网安全:内网穿透详解
- john破解用户密码和防破解
- 从月薪 2000 到月入 20 万,我这一路上的可复制与不可复制
- 趣学python教孩子学编程_《趣学Python——教孩子学编程》学习笔记第1-3章
- Windows Jar包开机自启动
- 3分钟学习下射频放大器基础知识