android 阅读器自动滚动,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布局文件:
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编程实现小说阅读器滑动效果的方法相关推荐
- android文字自动滚动,Android TextView文字横向自动滚动(跑马灯)
TextView实现文字滚动需要以下几个要点: 1.文字长度长于可显示范围:android:singleLine="true" 2.设置可滚到,或显示样式:android:elli ...
- android横向自动滚动列表,android横向循环自动滚动
项目需要实现GridView横向循环自动滚动 1.先看布局 android:layout_width="fill_parent" android:layout_height=&qu ...
- android listview 向上自动滚动效果,Android通过代码控制ListView上下滚动的方法
本文将介绍一种通过代码控制ListView上下滚动的方法. 先上图: 按下按钮会触发ListView滚动或停止. 实现该功能并不难,下面给出主要代码MainActivity.java package ...
- android 自定义textview 垂直滚动,Android中TextView如何实现水平和垂直滚动
一.只想让TextView显示一行,但是文字超过TextView的长度怎么办? 在开头显示省略号 android:singleLine="true" android:ellipsi ...
- android自定义横竖双向滚动,Android开发实现自定义水平滚动的容器示例
Android开发实现自定义水平滚动的容器示例 发布时间:2020-09-12 01:25:56 来源:脚本之家 阅读:71 作者:CharlinGod 本文实例讲述了Android开发实现自定义水平 ...
- android ble 实现自动连接,Android:自动重新连接BLE设备
经过多次试验和磨难之后,这就是我最好让Android自动连接的唯一用户操作是首先选择设备(如果使用设置菜单然后首先配对). 您必须将配对事件捕获到BroadcastReceiver中并执行Blueto ...
- android 进度条自动增长,Android 进度条自动前进效果的实现代码
今天给大家分享进度条自动前进功能的实现,先给大家分享实现效果图,感觉不错可以参考实现代码. 效果如下图: 首先布局要设置进度条最大值: android:id="@+id/pro1" ...
- android系统相机自动录像,android 调用系统相机录像并保存
1.在AndroidManifest.xml中添加如下代码 tools:ignore="ProtectedPermissions" /> android:authoritie ...
- android 静态图片自动切换,Android静态图片人脸识别的完整demo(附完整源码)
Android静态图片人脸识别的完整demo(附完整源码) 来源:互联网 作者:佚名 时间:2015-03-24 20:07 本文介绍了android静态识别人脸并进行标记人眼位置及人脸框的完整dem ...
最新文章
- 5G 除了上网快,还有什么用?
- windows测试模式打开关闭
- 如何将VBE中模块、工作表、工作簿和窗体等内的所有代码一次导出?
- lintcode 丢鸡蛋
- 《大数据之路:阿里巴巴大数据实践》-第1篇 数据技术篇 -第7章 数据挖掘
- Android实现校园新闻APP,基于android平台的校园新闻app的开发 大学毕业论文.doc
- 【信管师-资料总结篇】一、立项管理
- 自然语言处理入门理论知识
- sklearn中的make_blobs
- BootStrap按钮和图片
- php cli python,PHP MVC框架 CodeIgniter CLI模式简介
- DSP模型中FM FFM模型
- Ubuntu如何安装Python
- 学习也是一种兴趣爱好
- R语言 无敌小抄 cheatsheet
- 可用的mathtype安装包
- 项目经理应知道的项目管理的7个特点
- mysql iops_如何解决MySQL IOPS使用率高?
- 对一个MEMO中的字段处理
- 网管的自我修养-弱电系统
热门文章
- 老年消费市场最新观察:变化/趋势/入局/未来,以人为核心,构建信任感
- 运营新人掌握会这些工具,可提升80%的工作效率
- Coronary Artery Segmentation, A Review
- 利用jquery插件的图片剪切上传功能
- 干货!浏览器提示“您与此网站之间建立的连接不安全”的解决方案
- Easy3D开发——点云孔洞填充
- 【STM32】MDK点 Reset and Run 还是要点复位的运行解决方案
- 创建五星级评级的五种方法
- 基于Arria10的H.264 4K高性能编解码器模块视频演示
- JavaScript中常用事件有哪些?