zoukankan      html  css  js  c++  java
  • Android自定义之ScrollView下拉刷新

    公司项目,需要用到ScrollView的下拉刷新,一开始使用的时候PullToRefresh三方库的下拉刷新,我比较纠结第三档库,很强大,但是,公司项目的需求,PullToRefresh就不能做到了,改来改去的还是自己写一个下拉刷新比较靠谱,很多东西能够自己去控制。效果图就不上传了。直接解释关键代码。
    ScrollView的下拉刷新比ListView的好做多了。
    因为ScroTo的性质,ScrollView的下拉刷新,需要在外部添加一个父布局,通过父布局来控制触摸手势时候下传,什么时候下拉。
    我自定义了一个PullScrollView 
    public class PullScrollView extends RelativeLayout   

    public PullScrollView(Context context, AttributeSet attrs, int defStyle) {
            super(context, attrs, defStyle);
            init(context);
        }
        
        public PullScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
            init(context);
        }
        
        public PullScrollView(Context context) {
            super(context);
            init(context);
        }
        
        private Scroller mScroller ;
        private int mTouchSlop ;
        private void init(Context context){
            
             ViewConfiguration configuration = ViewConfiguration.get(getContext());
             mTouchSlop = configuration.getScaledTouchSlop();
            mScroller = new Scroller(context, new DecelerateInterpolator());
        }  

    首先是初始化mTouchSlop  是触摸手势滑动的最小像素值,也就是说滑动多少的距离才算是手势滑动,这样可以防止手势一点点的移动就引起的滑动事件。
    mScroller  是用来处理平滑滚动的。之前的博客有介绍。

    第二点:
    @Override
        protected void onFinishInflate() {
            super.onFinishInflate();
            if (getChildCount() > 2) {
                throw new RuntimeException("子孩子只能有两个");
            }
            bottomView = (ViewGroup) getChildAt(0);
            contentView = (ScrollView) getChildAt(1);
        }  

    在布局初始化结束之后,得到布局中的两个子孩子,为啥只能有两个孩子那?? BottomView是用来下拉刷新展示的View  contentView 就是我们的ScrollView了。如果子孩子多了,怎么知道哪个VIew是需要被隐藏的?所以只处理两个View的情况,当然,如果还有上拉加载更多,就需要三个子孩子了。


    第三:

    @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            bottomHeight = getBottomViewHeight() ; 
            Log.i("Test", l + "ceshi" + " t="+t + " r"+r + " b=" + b + " height= "   + bottomHeight);
            bottomView.layout(l, - bottomHeight, r, t);
            contentView.layout(l, 0, r, b);
        }  
    onLayout,做过自定义的都应该很熟悉这个方法,放置子孩子位置的一个方法,因为我们需要有一个子孩子隐藏掉,当我们需要它显示的时候才去显示,所以  需要手动的去将BottomView放到布局-hight到0的位置,这样下拉的时候才能显示出来。

    第四:
    @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            
            if (getScrollY() < 0 ) {
                return true ;
            }
            
            switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startY = (int) ev.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int moveY = (int) ev.getY();
                int delayY = moveY - startY ;
                Log.i("Test", delayY + " =  " + mTouchSlop) ;
                if (getTopPosition() && delayY > mTouchSlop) {
                    ev.setAction(MotionEvent.ACTION_DOWN);
                    return true ;
                }
                break ;
            case MotionEvent.ACTION_UP:
                
                break;
            }
            return super.onInterceptTouchEvent(ev);
        }  

    手势的拦截动作,通过getTopPosition()方式,来判断ScrollView时候处于下拉需要显示隐藏子View的状态,delayY > mTouchSlop 是用来判断是不是下拉的动作的。 如果符合条件  我们就需要将手势拦截掉,return true。
    为什么我觉得ScrollView做下来刷新比较好做那? 就是因为ScrollView的判断比较好判断。

    private boolean getTopPosition(){
            if (contentView.getScrollY() <= 0 ) {
                return true ;
            }
            return false ;
        }
    是不是很简单!!!!

    第五:
    @Override
        public boolean onTouchEvent(MotionEvent event) {
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startY = (int) event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                int delayY = (int) (event.getY() - startY) ;
                if (getTopPosition() && getScrollY() <= 0 ) {
                    pullMove((int) (-delayY * 0.8));  // 跟随手势滑动
                }
                startY = (int) event.getY();
                return true ;
            case MotionEvent.ACTION_UP:
                int scrollY = getScrollY();
                if (state == PullState.ON_REFRESH && scrollY < 0 && Math.abs(scrollY) > bottomHeight) {
                    restView(-getScrollY() - bottomHeight);  // 回弹到下拉刷新的状态
                    return true ;
                }else if (state == PullState.ON_REFRESH && scrollY < 0 && Math.abs(scrollY) < bottomHeight) {
                    return true ;
                }
                if (scrollY < 0  &&  Math.abs(scrollY) < bottomHeight ) {
                    returnView(); // 回弹到原来的位置。
                }else if (scrollY < 0 && Math.abs(scrollY) > bottomHeight  && state != PullState.ON_REFRESH) {
                    if (onreListener != null) {
                        state = PullState.ON_REFRESH ;
                        onreListener.refresh();  // 回调函数
                    }
                    restView(-getScrollY() - bottomHeight);
                }
                break;
            }
            return true ;
        }  
    这个就是做移动的处理手势的方法了。

    ScrollView的下拉刷新比起Listview ,要好做的多了。哈哈………………  
    下面是源码附上,用做学习之用。代码还有不完善之处,等我项目完成之后,我会把项目中的封装很完善的下拉刷新代码重新打包上传。

    下载地址:  http://pan.baidu.com/s/1jG67mzc 







  • 相关阅读:
    思维探索者:理解了才是真正的学习 理解会带来巨大的好处
    思维探索者:让记忆与学习更有效率 别在别人的思考中得意着
    思维探索者:从问题到答案的思维过程 像侦探一样思考
    android-HttpClient上传信息(包括图片)到服务端
    java web每天定时执行任务
    基础总结篇之一:Activity生命周期
    Spring面试题一
    J2EE用监听器实现同一用户只能有一个在线
    notepad++快捷键大全
    python for循环巧妙运用(迭代、列表生成式)
  • 原文地址:https://www.cnblogs.com/flyme2012/p/4222821.html
Copyright © 2011-2022 走看看