Implementation of sliding effect based on Android novel Reader
I have read novels and I know that the page flip function of a novel reader has a variety of effects, such as simulation pages, sliding pages, and so on. For some reason, I suddenly want to write a simple sliding flip effect. There is no intention to write it here. I hope you can write other effects based on this effect. The graph will not be available.
The following is the code: You can understand the onTouch event.
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 mVelocityTra Cker; private int mVelocityValue = 0;/** determine whether the sliding distance is valid */private int limitDistance = 0; private int screenWidth = 0; /** finger movement direction */private static final int MOVE_TO_LEFT = 0; private static final int MOVE_TO_RIGHT = 1; private static final int MOVE_NO_RESULT = 2; /** result direction of the last touch */private int mTouchResult = MOVE_NO_RESULT;/** start direction */private int mDirection = MOVE_NO_RESULT; /** touch mode */private static final Int MODE_NONE = 0; private static final int MODE_MOVE = 1; private int mMode = MODE_NONE;/** sliding view */private View mScrollerView = null; /** Top view (on the edge, invisible) */private View currentTopView = null;/** view displayed, display on the screen */private View currentShowView = null;/** bottom view (invisible) */private View currentBottomView = null; public FlipperLayout (Context context) {super (context); init (context);} public FlipperLayo Ut (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 * @ pa Ram currentBottomView * is the bottom-layer view. The * @ param currentShowView * display View * @ param currentTopView * is not displayed in the initial state, slip out of the screen */public void initFlipperViews (TouchListener listener, View currentBottomView, View currentShowView, View currentTopView) {this. currentBottomView = currentBottomView; this. currentShowView = currentShowView; this. currentTopView = currentTopView; setTouchResultListener (listener); add View (currentBottomView); addView (currentShowView); addView (currentTopView);/** the edge of the top view sliding by default (used to View the previous page) */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, he Ight) ;}@ 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 start X = 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 left positive, right negative (), (startX + dx) if the value is 0, that is, reset/** 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) {// move your finger to the left. You can flip the screen to 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) {// move your finger to the right and you can flip the screen to 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; random ();} private TouchListener mListener; private void setTouchResultListener (TouchListener listener) {this. mListener = listener;} @ Overridepublic void computeScroll () {super. computeScroll (); if (mScroller. computescroloffset () {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. setVis Ibility (View. GONE); addView (currentTopView) ;}} mTouchResult = MOVE_NO_RESULT;} private void locate (MotionEvent event) {if (mVelocityTracker = null) {mVelocityTracker = VelocityTracker. obtain ();} mVelocityTracker. addMovement (event);} private void releaseVelocityTracker () {if (mVelocityTracker! = Null) {mVelocityTracker. recycle (); mVelocityTracker = null;}/*** used for real-time callback of touch events ** @ author freeson */public interface TouchListener {/** swipe your finger to the left, view the next section */final int MOVE_TO_LEFT = 0;/** move your finger to the right to view the previous section */final int MOVE_TO_RIGHT = 1; /*** create a View that carries Text ** @ param direction * {@ link MOVE_TO_LEFT, MOVE_TO_RIGHT} * @ return */public View createView (final int direction ); /***** whether the current page is the first page ** @ return */public boolean currentIsFirstPage (); /***** whether the current page is the last page ** @ return */public boolean currentIsLastPage ();/*** whether the current page has a previous page (used to determine whether the page is slidable) ** @ return */public boolean whetherHasPreviousPage ();/*** determines whether the current page has a next page (used to determine whether it is slidable) ** @ return */public boolean whetherHasNextPage ();}}
Activity Test file:
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 layout file:
Activity layout file:
Note: Why is a rate calculator added above? In fact, it is only to identify whether this action is a fast moving action, even if the sliding distance is less than 1/3 of the screen, however, as long as the speed is met, it can be determined that sliding is a flip action.
Note: This is only one of the slides, not the logic of the novels. Although it is a bit rough, there are still some things worth learning. If you have any good solutions, we can discuss them together.