今天工作有点忙,就先贴上源码,有时间了再详细说明吧。

可以完整执行的上下翻页源码被我上传至资源页:http://download.csdn.net/detail/fener10289/6284691

主要实现上下滑动翻页的自定义控件代码:

package com.example.flingpage; 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.view.View.MeasureSpec;
import android.widget.Scroller; /**
* 自定义一个ScrollView实现屏幕的上下滑动
*/
public class DefinedScrollView extends ViewGroup { // 用来平滑过渡各个页面之间的切换,需要进行平滑的滚动,就要重写其ComputeScroll方法 private Scroller mScroller; // 用来检测用户的手势,或者也可用GestureDetector private VelocityTracker mVelocityTracker; // 当前的屏幕索引 private int mCurrentScreen; // 翻屏的页数 //private int mPage = 0; // 默认的屏幕索引 private int mDefaultScreen = 0; // 屏幕闲置时 private static final int TOUCH_STATE_REST = 0; // 屏幕滚动时 private static final int TOUCH_STATE_SCROLLING = 1; // 滚动速度 private static final int SNAP_VELOCITY = 600; // 触屏状态为当前屏幕闲置 private int mTouchState = TOUCH_STATE_REST; // 触屏溢出 private int mTouchSlop;
/*  // 最后的横向手势坐标 private float mLastMotionX; */// 最后的纵向手势坐标 private float mLastMotionY; private PageListener pageListener; /** * 在构造方法中初始化各个状态 *  * @param context * @param attrs * @param defStyle * ScrollView的默认样式 */public DefinedScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); mScroller = new Scroller(context); // 当前屏幕即为默认的屏幕,即为第一屏 mCurrentScreen = mDefaultScreen; // 是一个距离,表示滑动的时候,手的移动要大于这个距离才开始移动控件 mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } public DefinedScrollView(Context context, AttributeSet attrs) { // 0表示没有风格 this(context, attrs, 0); } /** * 横向画出每一个子view,这样所得到的view的高与屏幕高一致,宽度为getChildCount()-1个屏幕宽度的view。 */@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) { ///int childLeft = 0; int childTop = 0;int childCount = getChildCount(); for (int i = 0; i < childCount; i++) { final View childView = getChildAt(i); if (childView.getVisibility() != View.GONE) { final int childWidth = childView.getMeasuredWidth(); final int childHeight = childView.getMeasuredHeight();
/*              childView.layout(childLeft, 0, childLeft + childWidth, childView.getMeasuredHeight()); */childView.layout(0, childTop, childView.getMeasuredHeight(), childTop + childHeight); childTop +=childHeight;///childLeft += childWidth; } } }  /** * onMeasure方法在控件的父元素正要放置它的子控件时调用.它会问一个问题,“你想要用多大地方啊?”,然后传入两个参数——widthMeasureSpec和heightMeasureSpec. * 必须调用setMeasuredDimension方法,否则当控件放置时会引发一个运行时异常。 *  *setMeasuredDimension(measuredHeight, measuredWidth); *  * 当我们设置width或height为fill_parent时,容器在布局时调用子view的measure方法传入的模式是EXACTLY,因为子view会占据剩余容器的空间,所以它大小是确定的。 * 而当设置为wrap_content时,容器传进去的是AT_MOST, 表示子view的大小最多是多少,这样子view会根据这个上限来设置自己的尺寸。 * 当子view的大小设置为精确值时,容器传入的是EXACTLY, 而MeasureSpec的UNSPECIFIED模式目前还没有发现在什么情况下使用。  */@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); /final int width = MeasureSpec.getSize(widthMeasureSpec); final int height = MeasureSpec.getSize(heightMeasureSpec); final int widthMode = MeasureSpec.getMode(widthMeasureSpec); if (widthMode != MeasureSpec.EXACTLY) { throw new IllegalStateException("ScrollLayout only canmCurScreen run at EXACTLY mode!"); } /** * wrap_content 传进去的是AT_MOST 代表的是最大尺寸 * 固定数值或fill_parent 传入的模式是EXACTLY 代表的是精确的尺寸 */final int heightMode = MeasureSpec.getMode(heightMeasureSpec); if (heightMode != MeasureSpec.EXACTLY) { throw new IllegalStateException("ScrollLayout only can run at EXACTLY mode!"); } // The children are given the same width and height as the scrollLayout final int count = getChildCount(); for (int i = 0; i < count; i++) { getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec); } //在当前视图内容偏移至(x , y)坐标处,即显示(可视)区域位于(x , y)坐标处。 //将View的Content的位置移动到(x,y),而View的大小和位置不发生改变。如果Content超出了View的范围,则超出的部分会被挡住。 scrollTo(mCurrentScreen * width, 0); scrollTo(0,mCurrentScreen*height); } /** * According to the position of current layout scroll to the destination * page. * 是处理当屏幕拖动到一个位置松手后的处理 */public void snapToDestination() { final int screenWidth = getWidth(); final int screenHeight = getHeight();final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth; final int destScreen = (getScrollY() + screenHeight / 2) / screenHeight; //根据当前x坐标位置确定切换到第几屏  snapToScreen(destScreen); } /** * 拖拽到目标屏幕,滑屏 * 用于根据指定屏幕号切换到该屏幕 * @param whichScreen */public void snapToScreen(int whichScreen) { // get the valid layout page whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); ///if (getScrollX() != (whichScreen * getWidth())) { if (getScrollY() != (whichScreen * getHeight())) {    final int delta = whichScreen * getHeight() - getScrollY(); ///mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2); mScroller.startScroll(0,getScrollY(), 0,delta,  Math.abs(delta) * 2); mCurrentScreen = whichScreen; if(mCurrentScreen>Configure.curentPage){ Configure.curentPage = whichScreen; pageListener.page(Configure.curentPage); }else if(mCurrentScreen<Configure.curentPage){ Configure.curentPage = whichScreen; pageListener.page(Configure.curentPage); } invalidate(); // Redraw the layout } } /** * 获得当前页码 */public int getCurScreen() { return mCurrentScreen; } /** * 当滑动后的当前页码 */ public int getPage() { return Configure.curentPage; } public void setToScreen(int whichScreen) { whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1)); mCurrentScreen = whichScreen; ///scrollTo(whichScreen * getWidth(), 0); scrollTo(0,whichScreen * getHeight() ); } /** * 主要功能是计算拖动的位移量、更新背景、设置要显示的屏幕(setCurrentScreen(mCurrentScreen);)。 *  *  *必要时由父控件调用请求或通知其一个子节点需要更新它的mScrollX和mScrollY的值。 *典型的例子就是在一个子节点正在使用Scroller进行滑动动画时将会被执行。 *所以,从该方法的注释来看,继承这个方法的话一般都会有Scroller对象出现。 */ @Overridepublic void computeScroll() { //是用来判断动画是否完成,如果没有完成返回true继续执行界面刷新的操作,各种位置信息将被重新计算用以重新绘制最新状态的界面。 /** * 如果动画没有完成(mScroller.computeScrollOffset() == true)那么就使用scrollTo方法对mScrollX、mScrollY的值进行重新计算刷新界面, 调用postInvalidate()方法重新绘制界面, postInvalidate()方法会调用invalidate()方法, invalidate()方法又会调用computeScroll方法, 就这样周而复始的相互调用,直到mScroller.computeScrollOffset() 返回false才会停止界面的重绘动作 */if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } } /** * 处理手机屏幕的触摸事件 * @event 参数event为手机屏幕触摸事件封装类的对象,其中封装了该事件的所有信息,例如触摸的位置、触摸的类型以及触摸的时间等。该对象会在用户触摸手机屏幕时被创建。 * <A href='\"http://www.eoeandroid.com/home.php?mod=space&uid=7300\"' target='\"_blank\"'>@return</A> 该方法的返回值机理与键盘响应事件的相同,同样是当已经完整地处理了该事件且不希望其他回调方法再次处理时返回true,否则返回false * 屏幕被按下:当屏幕被按下时,会自动调用该方法来处理事件,此时MotionEvent.getAction()的值为MotionEvent.ACTION_DOWN,如果在应用程序中需要处理屏幕被按下的事件,只需重新该回调方法,然后在方法中进行动作的判断即可。  * 屏幕被抬起:当触控笔离开屏幕时触发的事件,该事件同样需要onTouchEvent方法来捕捉,然后在方法中进行动作判断。当MotionEvent.getAction()的值为MotionEvent.ACTION_UP时,表示是屏幕被抬起的事件。 * 在屏幕中拖动:该方法还负责处理触控笔在屏幕上滑动的事件,同样是调用MotionEvent.getAction()方法来判断动作值是否为MotionEvent.ACTION_MOVE再进行处理。 */@Overridepublic boolean onTouchEvent(MotionEvent event) { if (mVelocityTracker == null) { //用来追踪触摸事件(flinging事件和其他手势事件)的速率。用obtain()函数来获得类的实例 mVelocityTracker = VelocityTracker.obtain(); } //用addMovement(MotionEvent)函数将motion event加入到VelocityTracker类实例中 mVelocityTracker.addMovement(event); final int action = event.getAction(); final float x = event.getX(); final float y = event.getY(); switch (action) { case MotionEvent.ACTION_DOWN: if (!mScroller.isFinished()) { mScroller.abortAnimation(); } ///mLastMotionX = x; mLastMotionY = y; break; case MotionEvent.ACTION_MOVE: ///int deltaX = (int) (mLastMotionX - x); ///mLastMotionX = x; int deltaY = (int) (mLastMotionY - y); mLastMotionY = y; //在当前视图内容继续偏移(x , y)个单位,显示(可视)区域也跟着偏移(x,y)个单位 ///scrollBy(deltaX, 0); scrollBy(0, deltaY); break; case MotionEvent.ACTION_UP: final VelocityTracker velocityTracker = mVelocityTracker; //当你使用到速率时,使用computeCurrentVelocity(int)初始化速率的单位,并获得当前的事件的速率, //然后使用getXVelocity() 或getXVelocity()获得横向和竖向的速率。  //1000:你使用的速率单位.1的意思是,以一毫秒运动了多少个像素的速率, 1000表示 一秒时间内运动了多少个像素。  velocityTracker.computeCurrentVelocity(1000); ///int velocityX = (int) velocityTracker.getXVelocity(); int velocityY = (int) velocityTracker.getYVelocity();//如果手指滑动速率>600并且当前屏幕切换,因为当前屏幕初始化的时候是第一屏,为0 ///if (velocityX > SNAP_VELOCITY && getCurScreen() > 0) { if (velocityY > SNAP_VELOCITY && getCurScreen() > 0) { // Fling enough to move left snapToScreen(getCurScreen() - 1); //--Configure.curentPage; pageListener.page(Configure.curentPage); } ///else if (velocityX < -SNAP_VELOCITY && getCurScreen() < getChildCount() - 1) { else if (velocityY < -SNAP_VELOCITY && getCurScreen() < getChildCount() - 1) { // Fling enough to move right snapToScreen(getCurScreen() + 1); //++Configure.curentPage; //pageListener.page(Configure.curentPage); } else { snapToDestination(); } if (mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; } mTouchState = TOUCH_STATE_REST; break; case MotionEvent.ACTION_CANCEL: mTouchState = TOUCH_STATE_REST; break; } return true; } @Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) { if(Configure.isMove) return false;//拦截分发给子控件 final int action = ev.getAction(); if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) { return true; } ///final float x = ev.getX(); final float y = ev.getY(); switch (action) { case MotionEvent.ACTION_MOVE: final int xDiff = (int) Math.abs(mLastMotionX - x); final int yDiff = (int) Math.abs(mLastMotionY - y); if (xDiff > mTouchSlop) { if (yDiff > mTouchSlop) {mTouchState = TOUCH_STATE_SCROLLING; } break; case MotionEvent.ACTION_DOWN: ///mLastMotionX = x; mLastMotionY = y; mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING; break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: mTouchState = TOUCH_STATE_REST; break; } return mTouchState != TOUCH_STATE_REST; } public void setPageListener(PageListener pageListener) { this.pageListener = pageListener; } public interface PageListener { void page(int page); }
}


android 上下平滑翻页相关推荐

  1. Android App开发动画特效之利用滚动器实现平滑翻页(附源码和演示 简单易懂)

    需要图片集请点赞关注收藏后评论区留言~~~ 一.利用滚动器实现平滑翻页 在日常生活中,平移动画比较常见,有时也被称为位移动画,左右翻页和上下滚动其实都用到了平移动画,譬如平滑翻书的动画效果,就是位移动 ...

  2. android 日历翻页动画,Android 仿日历翻页、仿htc时钟翻页、数字翻页切换效果

    废话不多说,效果图: 自定义控件找自网络,使用相对简单,具体还没有来得及深入研究,只是先用笨方法大概实现了想要的效果,后续有空会仔细研究再更新文章, 本demo切换方法是用的笨方法,也就是由新数字和旧 ...

  3. Android 实现书籍翻页效果----升级篇

    自从之前发布了<Android 实现书籍翻页效果----完结篇 >之后,收到了很多朋友给我留言,前段时间由于事情较多,博客写得太匆忙很多细节地方没有描述清楚.所以不少人对其中的地方有不少不 ...

  4. Java电子书平滑翻页效果_(转载)Android 平滑和立体翻页效果1

    Android 平台提供了一套完整的动画框架,使得开发者可以用它来开发各种动画效果,本文将向读者阐述 Android 的动画框架是如何实现的.任何一个框架都有其优势和局限性,只有明白了其实现原理,开发 ...

  5. Android 实现书籍翻页效果----原理篇

    之前看到像ipad上的ibook的模拟书籍翻页的特效感觉很炫,在android上也有像laputa和ireader等应用实现有这个特效,在网上搜索了一下好像也没有现成的例子,所以自己动手实现了一个,现 ...

  6. Android viewpager2实现翻页效果

    为什么要实现翻页效果?减少用户的操作 viewpager2是基于recyclerview实现的,自带懒加载功能 viewpager2是对recyclerview的封装 要实现下面这个效果 viewpa ...

  7. Java电子书平滑翻页效果_移动端页面平滑翻页的解决方案

    随着近几年移动营销页的火爆,催生了一个中国式的名词「H5」.而 H5 最常见的形态就是类似幻灯片翻页效果. 我们需要制作 H5 的时候,最快的办法就是使用一些滑动插件库,如 iDangero.us 出 ...

  8. Android 实现书籍翻页效果---番外篇之光影效果

    By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 对于之前发布的翻页效果的源码,由于写得太匆忙,注释讲解的不多,且本人文笔较差,至使很多人对其中的很多部分不是很清楚 ...

  9. Android 实现书籍翻页效果----完结篇

    By 何明桂(http://blog.csdn.net/hmg25) 转载请注明出处 之前由于种种琐事,暂停了这个翻页效果的实现,终于在这周末完成了大部分功能,但是这里只是给出了一个基本的雏形,没有添 ...

最新文章

  1. 【VMware vSAN 6.6】2.1.带有本地存储的服务器:vSAN硬件服务器解决方案
  2. windows命令大全_必收藏!电脑快捷键、组合键大全
  3. 网络编程学习笔记(getsockopt和setsockopt函数)
  4. l360废墨收集垫清零_知识分享003:EPSON L360打印机出现故障-废墨计数清零
  5. 融云 php web在线客户,GitHub - yy526063395/Web-IM-mini: PHP+layIM+融云简单实现版
  6. php mysql安装_搭建PHP环境中的MySQL配置
  7. C语言中简单的题目,C语言的一些简单题目,没有答案,哪位大神帮忙做一下!!!...
  8. ASP.NET 使用Session,避免用户F5刷新时重复提交(转)
  9. 中比较两个时间的月份差值_测量血压时,一天中什么时间测比较准?控制血压又有哪些好方式?...
  10. 七上八下猜数字_猜数字教案
  11. 《机械制造技术基础》常见的问题
  12. 结合Cookie的简单图片验证码的工作原理探究
  13. 文本编辑器(vim)
  14. 思维导图MindManager2022版下载安装(无序列号)
  15. Jenkins - Publish Over SSH
  16. 基于聚类算法的图像分割技术
  17. 【沐风老师】3DMAX随机挤出插件2DExtruder使用教程
  18. 生成随机字符串序列号类似于UUID,但是比较短的那种。
  19. Task02 python与excel
  20. python与区块链_python与区块链

热门文章

  1. 人人网遭监管约谈,传统互联网公司能否借区块链弯道超车?
  2. 是炒作还是创新?区块链又一互联网入局者出现
  3. EOS主网账号,钱包申请 教程(未完全版本)
  4. C++ Primer Plus 第13章笔记
  5. 卖家新神器:淘宝宝贝复制专家。可以复制淘宝、天猫上的宝贝到自家店里卖。分分钟克隆店铺。谁要,请留言你要克隆的店铺或宝贝地址!
  6. 关于测试用例之一的白盒测试
  7. 黑客借微信大规模盗号
  8. 机械零件的强度(一)
  9. ISIS(中间系统到中间系统)概述
  10. 记一次羞羞的事情。。。