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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值