自定义ScrollView 实现上拉下拉的回弹效果--并且子控件中有Viewpager的情况

onInterceptTouchEvent就是对子控件中Viewpager的处理:左右滑动应该让viewpager消费
 public class MyScrollView extends ScrollView {
     private View childView;
     public MyScrollView(Context context) {
         super(context);
     }
     public MyScrollView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
     public MyScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
     }
 //    @Override
 //    protected void onLayout(boolean changed, int l, int t, int r, int b) {
 //        super.onLayout(changed, l, t, r, b);
 //    }
     //获取子视图
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
         if (getChildCount() > ) {
             childView = getChildAt();
         }
     }
     private int lastY;//上一次y轴方向操作的坐标位置
     private Rect normal = new Rect();//用于记录临界状态的左、上、右、下
     private boolean isFinishAnimation = true;//是否动画结束
     private int lastX, downX, downY;
     //拦截:实现父视图对子视图的拦截
     //是否拦截成功,取决于方法的返回值。返回值true:拦截成功。反之,拦截失败
     @Override
     public boolean onInterceptTouchEvent(MotionEvent ev) {
         boolean isIntercept = false;
         int eventX = (int) ev.getX();
         int eventY = (int) ev.getY();
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 lastX = downX = eventX;
                 lastY = downY = eventY;
                 break;
             case MotionEvent.ACTION_MOVE:
                 //获取水平和垂直方向的移动距离
                 int absX = Math.abs(eventX - downX);
                 int absY = Math.abs(eventY - downY);
                 if(absY > absX && absY >= UIUtils.dp2px()){
                     isIntercept = true;//执行拦截
                 }
                 lastX = eventX;
                 lastY = eventY;
                 break;
         }
         return isIntercept;
     }
     @Override
     public boolean onTouchEvent(MotionEvent ev) {
         if (childView == null || !isFinishAnimation) {
             return super.onTouchEvent(ev);
         }
         int eventY = (int) ev.getY();//获取当前的y轴坐标
         switch (ev.getAction()) {
             case MotionEvent.ACTION_DOWN:
                 lastY = eventY;
                 break;
             case MotionEvent.ACTION_MOVE:
                 int dy = eventY - lastY;//微小的移动量
                 if (isNeedMove()) {
                     if (normal.isEmpty()) {
                         //记录了childView的临界状态的左、上、右、下
                         normal.set(childView.getLeft(), childView.getTop(), childView.getRight(), childView.getBottom());
                     }
                     //重新布局
                     childView.layout(childView.getLeft(), childView.getTop() + dy / , childView.getRight(), childView.getBottom() + dy / );
                 }
                 lastY = eventY;//重新赋值
                 break;
             case MotionEvent.ACTION_UP:
                 if (isNeedAnimation()) {
                     //使用平移动画
                     int translateY = childView.getBottom() - normal.bottom;
                     TranslateAnimation translateAnimation = new TranslateAnimation(, , , -translateY);
                     translateAnimation.setDuration();
 //                translateAnimation.setFillAfter(true);//停留在最终位置上
                     translateAnimation.setAnimationListener(new Animation.AnimationListener() {
                         @Override
                         public void onAnimationStart(Animation animation) {
                             isFinishAnimation = false;
                         }
                         @Override
                         public void onAnimationEnd(Animation animation) {
                             isFinishAnimation = true;
                             childView.clearAnimation();//清除动画
                             //重新布局
                             childView.layout(normal.left, normal.top, normal.right, normal.bottom);
                             //清除normal的数据
                             normal.setEmpty();
                         }
                         @Override
                         public void onAnimationRepeat(Animation animation) {
                         }
                     });
                     //启动动画
                     childView.startAnimation(translateAnimation);
                 }
                 break;
         }
         return super.onTouchEvent(ev);
     }
     //判断是否需要执行平移动画
     private boolean isNeedAnimation() {
         return !normal.isEmpty();
     }
     private boolean isNeedMove() {
         int childMeasuredHeight = childView.getMeasuredHeight();//获取子视图的高度
         int scrollViewMeasuredHeight = this.getMeasuredHeight();//获取布局的高度
         Log.e("TAG", "childMeasuredHeight = " + childMeasuredHeight);
         Log.e("TAG", "scrollViewMeasuredHeight = " + scrollViewMeasuredHeight);
         int dy = childMeasuredHeight - scrollViewMeasuredHeight;//dy >= 0
         int scrollY = this.getScrollY();//获取用户在y轴方向上的偏移量 (上 + 下 -)
         if (scrollY <=  || scrollY >= dy) {
             return true;//按照我们自定义的MyScrollView的方式处理
         }
         //其他处在临界范围内的,返回false。即表示,仍按照ScrollView的方式处理
         return false;
     }
 }
自定义ScrollView 实现上拉下拉的回弹效果--并且子控件中有Viewpager的情况的更多相关文章
- Android 自定义ScrollView 支持惯性滑动,惯性回弹效果。支持上拉加载更多
		
先讲下原理: ScrollView的子View 主要分为3部分:head头部,滚动内容,fooder底部 我们实现惯性滑动,以及回弹,都是靠超过head或者fooder 就重新滚动到 ,内容的顶部或 ...
 - 解决iscroll.js上拉下拉刷新手指划出屏幕页面无法回弹问题
		
博客已迁移至http://zlwis.me. 使用过iscroll.js的上拉下拉刷新效果的朋友应该都碰到过这个问题:在iOS的浏览器中,上拉或下拉刷新时,当手指划出屏幕后,页面无法弹回.很多人因为解 ...
 - 打造android万能上拉下拉刷新框架——XRefreshView (二)
		
打造Android万能上拉下拉刷新框架--XRefreshView(一) 打造Android万能上拉下拉刷新框架--XRefreshView(三) 一.前言 自从上次发表了打造android万能上拉下 ...
 - iOS不得姐项目--推荐关注模块(一个控制器控制两个tableView),数据重复请求的问题,分页数据的加载,上拉下拉刷新(MJRefresh)
		
一.推荐关注模块(一个控制器控制两个tableView) -- 数据的显示 刚开始加载数据值得注意的有以下几点 导航控制器会自动调整scrollView的contentInset,最好是取消系统的设置 ...
 - ListView实现上拉下拉刷新加载功能
		
第一步.首先在你项目中创建一个包存放支持下拉刷新和上拉加载的类:
 - 打造Android万能上拉下拉刷新框架--XRefreshView(三)
		
转载请注明出处:http://blog.csdn.net/footballclub/ 打造Android万能上拉下拉刷新框架–XRefreshView(一) 打造Android万能上拉下拉刷新框架–X ...
 - iOS不得姐项目--精华模块上拉下拉的注意事项,日期显示,重构子控制器,计算cell的高度(只计算一次),图片帖子的显示
		
一.上拉下拉注意事项 使用MJRefresh中的上拉控件自动设置透明 当请求下页数据通过page的时候,注意的是上拉加载更多数据失败的问题,下拉加载数据失败了,页数应该还原.或者是请求成功的时候再将页 ...
 - 练习使用XRecyclerView,可上拉下拉刷新。
		
package com.lixu.testxrecyclerview; import android.support.v7.app.AppCompatActivity; import android. ...
 - swift实现UItableview上拉下拉刷新模块
		
最近用写个项目 发现上拉下拉刷新模块没找到合适的 so 自己写了一个 由于最近忙 教程就不写了 里面有 直接贴地址https://github.com/DaChengTechnology/DCRefr ...
 
随机推荐
- Iptables-redhat/centos
			
6用iptables 7默认用firewalld firewalld 与 iptables 过滤点,表 做nat是使用postrouting,prerouting表 Samba服务所使用的端口和协议: ...
 - 《机器学习实战(基于scikit-learn和TensorFlow)》第三章内容的学习心得
			
本章主要讲关于分类的一些机器学习知识点.我会按照以下关键点来总结自己的学习心得:(本文源码在文末,请自行获取) 什么是MNIST数据集 二分类 二分类的性能评估与权衡 从二元分类到多类别分类 错误分析 ...
 - Java的面向对象(初涉)
			
Java的面向对象(初涉) 面向对象的分析根据抽象关键的问题域来分解系统.面向对象的设计是一种提供符号设计系统的面向对象的实现过程,它用非常接近实际领域术语的方法把系统构造成"现实世界&qu ...
 - ASP.NET Core中自定义路由约束
			
路由约束 ASP.NET Core中,通过定义路由模板,可以在Url上传递变量,同时可以针对变量提供默认值.可选和约束. 约束的使用方法是在属性路由上添加指定的约束名,用法如下: // 单个使用 [R ...
 - asp.net mvc 安全测试漏洞 "跨站点请求伪造" 问题解决
			
IBM Security Appscan漏洞筛查-跨站请求伪造,该漏洞的产生,有多种情况: 1.WebApi的跨站请求伪造,需要对WebApi的请求头部做限制(此文不做详细介绍): 2.MVC Act ...
 - 【不遮遮掩掩】Github上传本地代码以及常见问题解决方案
			
2019.20.18更新: 把完整命令打一遍吧,不然看完太累了不是 //初始化文件夹 git init //初始化目录,把基本文件下载下来,如ignore文件 git pull --rebase or ...
 - LeetCode:104_Maximum Depth of Binary Tree | 二叉树的最大深度 | Easy
			
要求:求二叉树的深度(二叉树的深度为最远叶子节点到根节点的距离,即根节点到最远叶子节点的距离) Given a binary tree, find its maximum depth. The max ...
 - numpy中pad函数的常用方法
			
一.参数解释 ndarray = numpy.pad(array, pad_width, mode, **kwargs) array为要填补的数组 pad_width是在各维度的各个方向上想要填补的长 ...
 - salesforce零基础学习(八十九)使用 input type=file 以及RemoteAction方式上传附件
			
在classic环境中,salesforce提供了<apex:inputFile>标签用来实现附件的上传以及内容获取.salesforce 零基础学习(二十四)解析csv格式内容中有类似的 ...
 - php获取父目录的方法 dirname()
			
dirname() 方法,获取父目录的方法,官方文档:http://php.net/manual/en/function.dirname.php 在 php 7.0 后,dirname() 支持两个参 ...