首页 > 系统 > Android > 正文

Android编程实现小说阅读器滑动效果的方法

2020-04-11 11:21:11
字体:
来源:转载
供稿:网友

本文实例讲述了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程序设计有所帮助。

发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表