欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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程序设计有所帮助。