本文实例讲述了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布局文件:

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="horizontal" >

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" />

android:layout_width="5dp"

android:layout_height="match_parent"

android:background="#FFFF00"

android:gravity="center"

android:textSize="25sp"

android:visibility="visible" />

activity布局文件:

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="match_parent" >

备注:上面为什么加一个速率计算器呢,其实只是为了识别这个动作是不是快速滑动的动作,就算滑动的距离不到屏幕的1/3,但是只要速率满足都可以判定改滑动是一个翻页的动作。

注意哦:这只是其中一个滑动的效果而已啊,不包括小说分章节的逻辑哦。虽然有些粗糙,但是还是有可以值得学习的地方,大家如果还有什么好的解决方案,可以一起讨论。

附上demo下载地址 点击下载demo。

希望本文所述对大家Android程序设计有所帮助。

android 阅读器自动滚动,Android编程实现小说阅读器滑动效果的方法相关推荐

  1. android文字自动滚动,Android TextView文字横向自动滚动(跑马灯)

    TextView实现文字滚动需要以下几个要点: 1.文字长度长于可显示范围:android:singleLine="true" 2.设置可滚到,或显示样式:android:elli ...

  2. android横向自动滚动列表,android横向循环自动滚动

    项目需要实现GridView横向循环自动滚动 1.先看布局 android:layout_width="fill_parent" android:layout_height=&qu ...

  3. android listview 向上自动滚动效果,Android通过代码控制ListView上下滚动的方法

    本文将介绍一种通过代码控制ListView上下滚动的方法. 先上图: 按下按钮会触发ListView滚动或停止. 实现该功能并不难,下面给出主要代码MainActivity.java package ...

  4. android 自定义textview 垂直滚动,Android中TextView如何实现水平和垂直滚动

    一.只想让TextView显示一行,但是文字超过TextView的长度怎么办? 在开头显示省略号 android:singleLine="true" android:ellipsi ...

  5. android自定义横竖双向滚动,Android开发实现自定义水平滚动的容器示例

    Android开发实现自定义水平滚动的容器示例 发布时间:2020-09-12 01:25:56 来源:脚本之家 阅读:71 作者:CharlinGod 本文实例讲述了Android开发实现自定义水平 ...

  6. android ble 实现自动连接,Android:自动重新连接BLE设备

    经过多次试验和磨难之后,这就是我最好让Android自动连接的唯一用户操作是首先选择设备(如果使用设置菜单然后首先配对). 您必须将配对事件捕获到BroadcastReceiver中并执行Blueto ...

  7. android 进度条自动增长,Android 进度条自动前进效果的实现代码

    今天给大家分享进度条自动前进功能的实现,先给大家分享实现效果图,感觉不错可以参考实现代码. 效果如下图: 首先布局要设置进度条最大值: android:id="@+id/pro1" ...

  8. android系统相机自动录像,android 调用系统相机录像并保存

    1.在AndroidManifest.xml中添加如下代码 tools:ignore="ProtectedPermissions" /> android:authoritie ...

  9. android 静态图片自动切换,Android静态图片人脸识别的完整demo(附完整源码)

    Android静态图片人脸识别的完整demo(附完整源码) 来源:互联网 作者:佚名 时间:2015-03-24 20:07 本文介绍了android静态识别人脸并进行标记人眼位置及人脸框的完整dem ...

最新文章

  1. 5G 除了上网快,还有什么用?
  2. windows测试模式打开关闭
  3. 如何将VBE中模块、工作表、工作簿和窗体等内的所有代码一次导出?
  4. lintcode 丢鸡蛋
  5. 《大数据之路:阿里巴巴大数据实践》-第1篇 数据技术篇 -第7章 数据挖掘
  6. Android实现校园新闻APP,基于android平台的校园新闻app的开发 大学毕业论文.doc
  7. 【信管师-资料总结篇】一、立项管理
  8. 自然语言处理入门理论知识
  9. sklearn中的make_blobs
  10. BootStrap按钮和图片
  11. php cli python,PHP MVC框架 CodeIgniter CLI模式简介
  12. DSP模型中FM FFM模型
  13. Ubuntu如何安装Python
  14. 学习也是一种兴趣爱好
  15. R语言 无敌小抄 cheatsheet
  16. 可用的mathtype安装包
  17. 项目经理应知道的项目管理的7个特点
  18. mysql iops_如何解决MySQL IOPS使用率高?
  19. 对一个MEMO中的字段处理
  20. 网管的自我修养-弱电系统

热门文章

  1. 老年消费市场最新观察:变化/趋势/入局/未来,以人为核心,构建信任感
  2. 运营新人掌握会这些工具,可提升80%的工作效率
  3. Coronary Artery Segmentation, A Review
  4. 利用jquery插件的图片剪切上传功能
  5. 干货!浏览器提示“您与此网站之间建立的连接不安全”的解决方案
  6. Easy3D开发——点云孔洞填充
  7. 【STM32】MDK点 Reset and Run 还是要点复位的运行解决方案
  8. 创建五星级评级的五种方法
  9. 基于Arria10的H.264 4K高性能编解码器模块视频演示
  10. JavaScript中常用事件有哪些?