Android编程实现小说阅读器滑动效果的方法
程序员文章站
2024-02-10 15:31:22
本文实例讲述了android编程实现小说阅读器滑动效果的方法。分享给大家供大家参考,具体如下:
看过小说都知道小说阅读器翻页有好多种效果,比如仿真翻页,滑动翻页,等等。由...
本文实例讲述了android编程实现小说阅读器滑动效果的方法。分享给大家供大家参考,具体如下:
看过小说都知道小说阅读器翻页有好多种效果,比如仿真翻页,滑动翻页,等等。由于某种原因,突然想写一个简单点的滑动翻页效果。在这里写出来也没有什么意图,希望大家可以根据这个效果举一反三,写出其他的效果。图就不上了。
下面是代码:大家理解ontouch事件即可
package com.example.testscroll.view; import android.content.context; import android.util.attributeset; import android.view.motionevent; import android.view.velocitytracker; import android.view.view; import android.view.viewconfiguration; import android.view.viewgroup; import android.widget.scroller; public class flipperlayout extends viewgroup { private scroller mscroller; private velocitytracker mvelocitytracker; private int mvelocityvalue = 0; /** 商定这个滑动是否有效的距离 */ private int limitdistance = 0; private int screenwidth = 0; /** 手指移动的方向 */ private static final int move_to_left = 0; private static final int move_to_right = 1; private static final int move_no_result = 2; /** 最后触摸的结果方向 */ private int mtouchresult = move_no_result; /** 一开始的方向 */ private int mdirection = move_no_result; /** 触摸的模式 */ private static final int mode_none = 0; private static final int mode_move = 1; private int mmode = mode_none; /** 滑动的view */ private view mscrollerview = null; /** 最上层的view(处于边缘的,看不到的) */ private view currenttopview = null; /** 显示的view,显示在屏幕 */ private view currentshowview = null; /** 最底层的view(看不到的) */ private view currentbottomview = null; public flipperlayout(context context) { super(context); init(context); } public flipperlayout(context context, attributeset attrs, int defstyle) { super(context, attrs, defstyle); init(context); } public flipperlayout(context context, attributeset attrs) { super(context, attrs); init(context); } private void init(context context) { mscroller = new scroller(context); screenwidth = context.getresources().getdisplaymetrics().widthpixels; limitdistance = screenwidth / 3; } /*** * * @param listener * @param currentbottomview * 最底层的view,初始状态看不到 * @param currentshowview * 正在显示的view * @param currenttopview * 最上层的view,初始化时滑出屏幕 */ public void initflipperviews(touchlistener listener, view currentbottomview, view currentshowview, view currenttopview) { this.currentbottomview = currentbottomview; this.currentshowview = currentshowview; this.currenttopview = currenttopview; settouchresultlistener(listener); addview(currentbottomview); addview(currentshowview); addview(currenttopview); /** 默认将最上层的view滑动的边缘(用于查看上一页) */ currenttopview.scrollto(-screenwidth, 0); } @override protected void onlayout(boolean changed, int l, int t, int r, int b) { for (int i = 0; i < getchildcount(); i++) { view child = getchildat(i); int height = child.getmeasuredheight(); int width = child.getmeasuredwidth(); child.layout(0, 0, width, height); } } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, heightmeasurespec); int width = measurespec.getsize(widthmeasurespec); int height = measurespec.getsize(heightmeasurespec); setmeasureddimension(width, height); for (int i = 0; i < getchildcount(); i++) { getchildat(i).measure(widthmeasurespec, heightmeasurespec); } } private int startx = 0; @override public boolean dispatchtouchevent(motionevent ev) { switch (ev.getaction()) { case motionevent.action_down: if (!mscroller.isfinished()) { break; } startx = (int) ev.getx(); break; } return super.dispatchtouchevent(ev); } @suppresswarnings("deprecation") @override public boolean ontouchevent(motionevent event) { obtainvelocitytracker(event); switch (event.getaction()) { case motionevent.action_move: if (!mscroller.isfinished()) { return super.ontouchevent(event); } if (startx == 0) { startx = (int) event.getx(); } final int distance = startx - (int) event.getx(); if (mdirection == move_no_result) { if (mlistener.whetherhasnextpage() && distance > 0) { mdirection = move_to_left; } else if (mlistener.whetherhaspreviouspage() && distance < 0) { mdirection = move_to_right; } } if (mmode == mode_none && ((mdirection == move_to_left && mlistener.whetherhasnextpage()) || (mdirection == move_to_right && mlistener .whetherhaspreviouspage()))) { mmode = mode_move; } if (mmode == mode_move) { if ((mdirection == move_to_left && distance <= 0) || (mdirection == move_to_right && distance >= 0)) { mmode = mode_none; } } if (mdirection != move_no_result) { if (mdirection == move_to_left) { if (mscrollerview != currentshowview) { mscrollerview = currentshowview; } } else { if (mscrollerview != currenttopview) { mscrollerview = currenttopview; } } if (mmode == mode_move) { mvelocitytracker.computecurrentvelocity(1000, viewconfiguration.getmaximumflingvelocity()); if (mdirection == move_to_left) { mscrollerview.scrollto(distance, 0); } else { mscrollerview.scrollto(screenwidth + distance, 0); } } else { final int scrollx = mscrollerview.getscrollx(); if (mdirection == move_to_left && scrollx != 0 && mlistener.whetherhasnextpage()) { mscrollerview.scrollto(0, 0); } else if (mdirection == move_to_right && mlistener.whetherhaspreviouspage() && screenwidth != math.abs(scrollx)) { mscrollerview.scrollto(-screenwidth, 0); } } } break; case motionevent.action_up: if (mscrollerview == null) { return super.ontouchevent(event); } final int scrollx = mscrollerview.getscrollx(); mvelocityvalue = (int) mvelocitytracker.getxvelocity(); // scroll左正,右负(),(startx + dx)的值如果为0,即复位 /* * android.widget.scroller.startscroll( int startx, int starty, int * dx, int dy, int duration ) */ int time = 500; if (mmode == mode_move && mdirection == move_to_left) { if (scrollx > limitdistance || mvelocityvalue < -time) { // 手指向左移动,可以翻屏幕 mtouchresult = move_to_left; if (mvelocityvalue < -time) { time = 200; } mscroller.startscroll(scrollx, 0, screenwidth - scrollx, 0, time); } else { mtouchresult = move_no_result; mscroller.startscroll(scrollx, 0, -scrollx, 0, time); } } else if (mmode == mode_move && mdirection == move_to_right) { if ((screenwidth - scrollx) > limitdistance || mvelocityvalue > time) { // 手指向右移动,可以翻屏幕 mtouchresult = move_to_right; if (mvelocityvalue > time) { time = 250; } mscroller.startscroll(scrollx, 0, -scrollx, 0, time); } else { mtouchresult = move_no_result; mscroller.startscroll(scrollx, 0, screenwidth - scrollx, 0, time); } } resetvariables(); postinvalidate(); break; } return true; } private void resetvariables() { mdirection = move_no_result; mmode = mode_none; startx = 0; releasevelocitytracker(); } private touchlistener mlistener; private void settouchresultlistener(touchlistener listener) { this.mlistener = listener; } @override public void computescroll() { super.computescroll(); if (mscroller.computescrolloffset()) { mscrollerview.scrollto(mscroller.getcurrx(), mscroller.getcurry()); postinvalidate(); } else if (mscroller.isfinished() && mlistener != null && mtouchresult != move_no_result) { if (mtouchresult == move_to_left) { if (currenttopview != null) { removeview(currenttopview); } currenttopview = mscrollerview; currentshowview = currentbottomview; if (mlistener.currentislastpage()) { final view newview = mlistener.createview(mtouchresult); currentbottomview = newview; addview(newview, 0); } else { currentbottomview = new view(getcontext()); currentbottomview.setvisibility(view.gone); addview(currentbottomview, 0); } } else { if (currentbottomview != null) { removeview(currentbottomview); } currentbottomview = currentshowview; currentshowview = mscrollerview; if (mlistener.currentisfirstpage()) { final view newview = mlistener.createview(mtouchresult); currenttopview = newview; currenttopview.scrollto(-screenwidth, 0); addview(currenttopview); } else { currenttopview = new view(getcontext()); currenttopview.scrollto(-screenwidth, 0); currenttopview.setvisibility(view.gone); addview(currenttopview); } } mtouchresult = move_no_result; } } private void obtainvelocitytracker(motionevent event) { if (mvelocitytracker == null) { mvelocitytracker = velocitytracker.obtain(); } mvelocitytracker.addmovement(event); } private void releasevelocitytracker() { if (mvelocitytracker != null) { mvelocitytracker.recycle(); mvelocitytracker = null; } } /*** * 用来实时回调触摸事件回调 * * @author freeson */ public interface touchlistener { /** 手指向左滑动,即查看下一章节 */ final int move_to_left = 0; /** 手指向右滑动,即查看上一章节 */ final int move_to_right = 1; /** * 创建一个承载text的view * * @param direction * {@link move_to_left,move_to_right} * @return */ public view createview(final int direction); /*** * 当前页是否是第一页 * * @return */ public boolean currentisfirstpage(); /*** * 当前页是否是最后一页 * * @return */ public boolean currentislastpage(); /** * 当前页是否有上一页(用来判断可滑动性) * * @return */ public boolean whetherhaspreviouspage(); /*** * 当前页是否有下一页(用来判断可滑动性) * * @return */ public boolean whetherhasnextpage(); } }
activity测试文件:
package com.example.testscroll; import java.io.bytearrayoutputstream; import java.io.ioexception; import java.io.inputstream; import android.app.activity; import android.content.res.assetmanager; import android.os.bundle; import android.os.handler; import android.view.layoutinflater; import android.view.view; import android.view.view.onclicklistener; import android.widget.textview; import com.example.testscroll.view.flipperlayout; import com.example.testscroll.view.flipperlayout.touchlistener; import com.example.testscrollactivity.r; public class mainactivity extends activity implements onclicklistener, touchlistener { private string text = ""; private int textlenght = 0; private static final int count = 400; private int currenttopendindex = 0; private int currentshowendindex = 0; private int currentbottomendindex = 0; private handler handler = new handler() { public void handlemessage(android.os.message msg) { flipperlayout rootlayout = (flipperlayout) findviewbyid(r.id.container); view recoverview = layoutinflater.from(mainactivity.this).inflate(r.layout.view_new, null); view view1 = layoutinflater.from(mainactivity.this).inflate(r.layout.view_new, null); view view2 = layoutinflater.from(mainactivity.this).inflate(r.layout.view_new, null); rootlayout.initflipperviews(mainactivity.this, view2, view1, recoverview); textlenght = text.length(); system.out.println("----textlenght----->" + textlenght); textview textview = (textview) view1.findviewbyid(r.id.textview); if (textlenght > count) { textview.settext(text.subsequence(0, count)); textview = (textview) view2.findviewbyid(r.id.textview); if (textlenght > (count << 1)) { textview.settext(text.subsequence(count, count * 2)); currentshowendindex = count; currentbottomendindex = count << 1; } else { textview.settext(text.subsequence(count, textlenght)); currentshowendindex = textlenght; currentbottomendindex = textlenght; } } else { textview.settext(text.subsequence(0, textlenght)); currentshowendindex = textlenght; currentbottomendindex = textlenght; } }; }; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); new readingthread().start(); } @override public void onclick(view v) { } @override public view createview(final int direction) { string txt = ""; if (direction == touchlistener.move_to_left) { currenttopendindex = currentshowendindex; final int nextindex = currentbottomendindex + count; currentshowendindex = currentbottomendindex; if (textlenght > nextindex) { txt = text.substring(currentbottomendindex, nextindex); currentbottomendindex = nextindex; } else { txt = text.substring(currentbottomendindex, textlenght); currentbottomendindex = textlenght; } } else { currentbottomendindex = currentshowendindex; currentshowendindex = currenttopendindex; currenttopendindex = currenttopendindex - count; txt = text.substring(currenttopendindex - count, currenttopendindex); } view view = layoutinflater.from(this).inflate(r.layout.view_new, null); textview textview = (textview) view.findviewbyid(r.id.textview); textview.settext(txt); system.out.println("-top->" + currenttopendindex + "-show->" + currentshowendindex + "--bottom-->" + currentbottomendindex); return view; } @override public boolean whetherhaspreviouspage() { return currentshowendindex > count; } @override public boolean whetherhasnextpage() { return currentshowendindex < textlenght; } @override public boolean currentisfirstpage() { boolean should = currenttopendindex > count; if (!should) { currentbottomendindex = currentshowendindex; currentshowendindex = currenttopendindex; currenttopendindex = currenttopendindex - count; } return should; } @override public boolean currentislastpage() { boolean should = currentbottomendindex < textlenght; if (!should) { currenttopendindex = currentshowendindex; final int nextindex = currentbottomendindex + count; currentshowendindex = currentbottomendindex; if (textlenght > nextindex) { currentbottomendindex = nextindex; } else { currentbottomendindex = textlenght; } } return should; } private class readingthread extends thread { public void run() { assetmanager am = getassets(); inputstream response; try { response = am.open("text.txt"); if (response != null) { bytearrayoutputstream baos = new bytearrayoutputstream(); int i = -1; while ((i = response.read()) != -1) { baos.write(i); } text = new string(baos.tobytearray(), "utf-8"); baos.close(); response.close(); handler.sendemptymessage(0); } } catch (ioexception e) { e.printstacktrace(); } } } }
xml布局文件:
<?xml version="1.0" encoding="utf-8"?> <linearlayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="horizontal" > <textview android:id="@+id/textview" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1.0" android:background="#666666" android:gravity="center" android:text="新建的view" android:textcolor="@android:color/white" android:textsize="16sp" android:visibility="visible" /> <view android:layout_width="5dp" android:layout_height="match_parent" android:background="#ffff00" android:gravity="center" android:textsize="25sp" android:visibility="visible" /> </linearlayout>
activity布局文件:
<com.example.testscroll.view.flipperlayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" > </com.example.testscroll.view.flipperlayout>
备注:上面为什么加一个速率计算器呢,其实只是为了识别这个动作是不是快速滑动的动作,就算滑动的距离不到屏幕的1/3,但是只要速率满足都可以判定改滑动是一个翻页的动作。
注意哦:这只是其中一个滑动的效果而已啊,不包括小说分章节的逻辑哦。虽然有些粗糙,但是还是有可以值得学习的地方,大家如果还有什么好的解决方案,可以一起讨论。
附上demo下载地址 点击下载demo。
希望本文所述对大家android程序设计有所帮助。
上一篇: 智能程序如何申请,8个智能小程序平台推荐