滚动回弹效果分析:
首先,创建一个类,继承scrollview,重写ontouch事件,实现伸缩回弹效果。
[scroollview节点下只能有一个子节点,这个子节点就是我们要移动的view布局]
 
第一步:获取要操作的子view布局
第二步:重写onTouch事件监听
 
 
分析具体事件:
观察分析得出结论:
让布局移动每一次拉动的Y轴一半的距离,然后松手滚动[携带动画]回到原来的位置。
下拉或者上拉的时候,记录按下时的Y轴位置
action_down:
y
 
移动过程中的处理:
计算上一次与本次的Y轴(拉动距离)[而不是按下时候的Y值,和现在移动到的Y值,是每上一次和本次的Y值比较
判断是否需要移动布局的情况:Y轴的一个距离偏移
 
//2种情况,随着布局的拖动, inner.getMeasuredHeight()的值是变化的
//inner.getMeasuredHeight()与getHeight()的区别:
当屏幕可以包裹内容的时候,他们的值相等
当view的高度超出屏幕时,getMeasuredHeight()是实际View的大小,与屏幕无关,getHeight的大小此时则是屏幕的大小。
此时,getMeasuredHeight() = getHeight+超出部分。
 
抬起的处理:布局回滚到正常位置
移动动画回滚到正常位置(*:动画执行期间,不允许拖拉操作)   
距离:-的滚动距离
public class MyScrollview extends ScrollView {

    //要操作的布局
    private View innerView;
    private float y;
    private Rect normal = new Rect();
    private boolean animationFinish = true;

    public MyScrollview(Context context) {
        super(context, null);
    }

    public MyScrollview(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public MyScrollview(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onFinishInflate() {
        int childCount = getChildCount();
        if (childCount > 0) {
            innerView = getChildAt(0);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        if (innerView == null) {
            return super.onTouchEvent(ev);
        } else {
            commonTouchEvent(ev);
        }
        return super.onTouchEvent(ev);
    }

    /**
     * 自定义touch事件处理
     *
     * @param ev
     */
    private void commonTouchEvent(MotionEvent ev) {
        if (animationFinish) {
            int action = ev.getAction();
            switch (action) {
                case MotionEvent.ACTION_DOWN:
                    y = ev.getY();
                    break;
                case MotionEvent.ACTION_MOVE:
                    float preY = y == 0 ? ev.getY() : y;
                    float nowY = ev.getY();
                    int detailY = (int) (preY - nowY);
                    y = nowY;
                    //操作view进行拖动detailY的一半
                    if (isNeedMove()) {
                        //布局改变位置之前,记录一下正常状态的位置
                        if (normal.isEmpty()) {
                            normal.set(innerView.getLeft(), innerView.getTop(), innerView.getRight(), innerView.getBottom());
                        }
                        innerView.layout(innerView.getLeft(), innerView.getTop() - detailY / 2, innerView.getRight(), innerView.getBottom() - detailY / 2);
                    }
                    break;
                case MotionEvent.ACTION_UP:
                    y = 0;
                    //布局回滚到原来的位置
                    if (isNeedAnimation()) {
                        animation();
                    }
                    break;
            }
        }
    }

    private void animation() {
        TranslateAnimation ta = new TranslateAnimation(0, 0, 0, normal.top - innerView.getTop());
        ta.setDuration(200);
        ta.setAnimationListener(new Animation.AnimationListener() {
            @Override
            public void onAnimationStart(Animation animation) {
                animationFinish = false;
            }

            @Override
            public void onAnimationEnd(Animation animation) {
                innerView.clearAnimation();
                innerView.layout(normal.left, normal.top, normal.right, normal.bottom);
                normal.setEmpty();
                animationFinish = true;
            }

            @Override
            public void onAnimationRepeat(Animation animation) {

            }
        });
        innerView.startAnimation(ta);
    }

    /**
     * 判断是否需要回滚
     *
     * @return
     */
    private boolean isNeedAnimation() {
        return !normal.isEmpty();
    }

    /**
     * 判断是否需要移动
     *
     * @return
     */
    private boolean isNeedMove() {
        int offset = innerView.getMeasuredHeight() - getHeight();
        int scrollY = getScrollY();
        Log.e("zoubo", "getMeasuredHeight:" + innerView.getMeasuredHeight() + "----getHeight:" + getHeight());
        Log.e("zoubo", "offset:" + offset + "----scrollY:" + scrollY);
        if (scrollY == 0 || scrollY == offset) {
            return true;
        }
        return false;
    }
}

  

 

Scrollview回弹效果自定义控件的更多相关文章

  1. Android仿IOS回弹效果 ScrollView回弹 总结

    Android仿IOS回弹效果  ScrollView回弹 总结 应项目中的需求  须要仿IOS 下拉回弹的效果 , 我在网上搜了非常多 大多数都是拿scrollview 改吧改吧 试了一些  发现总 ...

  2. 阻尼回弹效果的ScrollView嵌套GridView

    以前写过一篇带阻尼回弹效果的ScrollView,但是有些小问题,于是又重新整理了一下,这篇文章一是一个带阻尼的Scrollview,再个就是Scrollview嵌套GridView实现,而GridV ...

  3. ScrollView的阻尼回弹效果实现(仿qq空间)

    玩过新浪微博,qq空间等手机客户端的童鞋,都应该清楚,在主界面向下滑动时,会有一个阻尼回弹效果,看起来挺不错,接下来我们就来实现一下这种效果,下拉后回弹刷新界面,先看效果图: 这个是编辑器里面的界面效 ...

  4. ScrollView的顶部下拉和底部上拉回弹效果

    要实现ScrollView的回弹效果,需要对其进行触摸事件处理.先来看一下简单的效果: 根据Android的View事件分发处理机制,下面对dispatchTouchEvent进行详细分析: 在加载布 ...

  5. 移动端页面 弹出框滚动,底部body锁定,不滚动 / 微信网页禁止回弹效果

    需求:页面有弹出层菜单,当弹出层菜单超出屏幕可视区域时,不能滚动.加上滚动后,底部body的滚动事件如何禁止,加上了overflow:hidden;还是不可用. 如下图:地区弹出框可以滚动,而底部的b ...

  6. -webkit-overflow-scrolling 与滚动回弹效果.

    参考来源:https://developer.mozilla.org/zh-CN/docs/Web/CSS/-webkit-overflow-scrolling https://www.w3cways ...

  7. 源生js惯性滚动与回弹效果

    在写移动端的APP或者页面时,经常会遇到惯性滚动与回弹效果.用插件iscroll可以轻松解决这个问题,大多数的移动框架也能轻松解决这个问题,它们内部都封装了这个效果. 一直好奇这个效果原生JS是怎么实 ...

  8. WPF 扩大,回弹效果

    原文:WPF 扩大,回弹效果 <Window x:Class="Fish.AccountBook.View.Test.PanelWindow" xmlns="htt ...

  9. Android使用TextView实现跑马灯效果(自定义控件)

    对于一个长的TetxView 折行显示是一个很好的办法,另一种方法就是跑马灯显示(单行滚动) 1.折行显示的长TextView <LinearLayout xmlns:android=" ...

随机推荐

  1. Knockout 系列

    由于近期要做的项目要兼容到IE6,原来的angular框架已经不能满足现在的兼容性要求. 解决方案: 1. 放弃框架,改为库 2. UI库采用 Knockout,css 3. css库 采用 boot ...

  2. AngularJs ng-class 使用

    今天在做项目的时候要对表格内的部分的最大最小值高亮 解决方案 1. 引用 ng-class 2. 引用原型求最大最小值 实例 AngularJs HTML 代码 <table class=&qu ...

  3. 在阿里云ECS(CentOS6.5)上安装ftp

    安装vsftpd 命令: yum install vsftpd –y 结果: 创建ftp存取文件的目录,用户名,密码 命令: useradd -d /home/ftp -g ftp -s /sbin/ ...

  4. 火狐上的一个post提交工具(主要用于测试接口时候)

    添加的过程 安装完后,就可以在下图上,看到一个poster 点击poster就可以看到下图 图中红线圈好的,是必须要填写的 Url是访问路径 Name是参数名称 Value是参数值 需要注意一点的是: ...

  5. AFNetworking content type not support

    ref:http://blog.csdn.net/nyh1006/article/details/25068255 1.错误信息:Error:Error Domain=AFNetworkingErro ...

  6. Spark Standalone Mode

    It is very easy to install a Spark cluster (Standalone mode). In my example, I used three machines. ...

  7. Dom编程(二)

    document是window对象的一个属性,因为使用window对象成员的时候可以省略window.,所以一般直接写document  document的方法: (1)write:向文档中写入内容. ...

  8. eclipse 完全智能提示

     1.添加智能提示 eclipse的代码提示是按”.”这个字符提示的,而如果想在其他的条件下触发,则需要按Alt + / 或者是 Ctrl + Space手动调用 (Ctrl + Space原先是Ec ...

  9. TSP问题 遗传算法 智能优化算法

    写了半天,效率还是有点低的,以后有空再优化下: //用次序表示法来表示个体编码 #include<iostream> #include<fstream> #include< ...

  10. python实现二叉树

    初学python,需要实现一个决策树,首先实践一下利用python实现一个二叉树数据结构.建树的时候做了处理,保证建立的二叉树是平衡二叉树. # -*- coding: utf-8 -*- from ...