看过小说都知道小说阅读器翻页有好多种效果,比如仿真翻页,滑动翻页,等等。由于某种原因,突然想写一个简单点的滑动翻页效果。在这里写出来也没有什么意图,希望大家可以根据这个效果举一反三,写出其他的效果。图就不上了。

下面是代码:大家理解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);}@Overrideprotected 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);}}@Overrideprotected 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;@Overridepublic 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")@Overridepublic 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;}@Overridepublic 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;}};};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);new ReadingThread().start();}@Overridepublic void onClick(View v) {}@Overridepublic 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;}@Overridepublic boolean whetherHasPreviousPage() {return currentShowEndIndex > COUNT;}@Overridepublic boolean whetherHasNextPage() {return currentShowEndIndex < textLenght;}@Overridepublic boolean currentIsFirstPage() {boolean should = currentTopEndIndex > COUNT;if (!should) {currentBottomEndIndex = currentShowEndIndex;currentShowEndIndex = currentTopEndIndex;currentTopEndIndex = currentTopEndIndex - COUNT;}return should;}@Overridepublic 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"?>        

activity布局文件:


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

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

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

更多相关文章

  1. Android(安卓)屏幕自适应
  2. android-image-slide-panel图片照片墙的加载和滑动特效
  3. android 开发之切换landscape屏幕
  4. android View的scrollTo,scrollBy方法详解
  5. (转)Android学习路线指南
  6. android 自动调整屏幕分辨率
  7. Android仿YouTube拖拽视频效果的实现
  8. Android最全的屏幕适配
  9. .Net程序员玩转Android开发---(15)ListView滚动事件

随机推荐

  1. Android(安卓)intent action大全
  2. android 布局 ListView中的列表 Relative
  3. Android(安卓)ANR分析三
  4. LottieAnimationView 使用无法显示效果
  5. Android(安卓)BLE ERROR CODE
  6. HtmlTextView for Android
  7. android 配置
  8. android TextView
  9. Android(安卓)Studio 文件类型图标
  10. Android(安卓)蓝牙开发常用UUID表