• 【Android】下拉刷新实现


    关于这方面的文章百度下有很多,我就只写写我自己实现过程。

    我觉得学习一门语言不是做了几个项目就可以认为自己会了,这只是暂时的,若没有笔记,时间长了,你是怎么解决某些问题,估计连你自己都忘了,又得费时费力的重新研究~ 这就是我为什么写这篇文章的原因。

    现在公司做Android是用AndroidStudio来做的,AndroidStudio开发是需要搞gradle 的,有点麻烦,我就直接上Eclipse上做些测试例子~

    进入正文:

    下拉的刷新的实现主要是基于ListView这个控件扩展来的。ListView的数据需要由“适配器”来提供,这个跟之前的web开发有些差异。以前做集合控件开发时,将一些有规律的数据直接与控件绑定就可以显示了。但Android却不行,为什么呢?因为ListView是个多功能控件,它能将不同数据表现实现都在一个集合中展示。那不同的形式要在一个容器中展示就涉及到“适配”的问题。

    (什么的适配?我的理解就是匹配,插口转换之类的)

    原来ListView要呈现不同子视图,所以就需要一个适配器来做“兼容”~

    下拉ListView时它上面会有“刷新”等图标及文字,这是怎么做到的? ListView类中有个addHeaderView(View v) 方法,我们将 【放好“刷新”等图标及文字】的一个子视图,通过这个方法将这个子视图放到ListView中,就可以从“逻辑上”了解了,上面那块“刷新”的东东是怎么来的。

    新增的Head视图(Layout)
    原ListView

    有了这个组合,剩下的就是滑动相关了~

    由于我们是要实现“下拉刷新”效果的,且这个效果是基于ListView控件的,所以我们需要自定义一个ListView控件,我们叫它mListView吧~

    在继续下面文章之前,我提一个代码使用技巧,高手略过~

    Begin---------------------------------------------------------------------------------------------------------------------------

    如图:

    我们把相关事件定义在辅类时,实现却在主类中来实现,怎么来实现呢?

    在辅类中定义一个接口如IInterface1

    辅类部分代码Code-begin    -------------------------------------

    IInterface1 iobj;

    public void setIInterface1(IInterface1  l)

    {

      iobj=l;

    }

    然后,在相应事件中直接使用iobj.doSomeThing() 把位置占住~

    辅类部分代码Code-end   -------------------------------------

    主类Activity implements IInterface1 (主类Activity实现 辅类中定义的接口及方法)

    public override doSomeThing(){......}

    KEY:主类中调用辅类的  setIInterface1 方法把自己放进去 如:setIInterface1(this);   

    小节下,辅类创建一个接口定义些抽象方法,在相关事件把位置占好,并提供外部set接口实例的方法,主类实现接口把自己做为接口的实现者传入辅类中,成功替换之前的占位抽象方法~

    End---------------------------------------------------------------------------------------------------------------------------

    以上逻辑将用于下拉触点时,调用相关刷新数据(加载数据)

    自定义的mListView 需要 实现(implements)OnScrollListener 接口,

    申明一个Scroller 实例,如下:

    mScroller=new Scroller(context,new DecelerateInterpolator());

    重写 onTouchEvent 方法

    根据不同事件保存与调用滑动方法

    mScroller.startScroll(0, height, 0, finalHeight-height,SCROLL_DURATION);

    然后就是调用方法  invalidate()  重绘界面

    仅仅调用Scroller的startScroll方法是不能实现滚动的~  还有个关键方法   computeScroll  ,你可能需要重写这个方法

    @Override
        public void computeScroll() {
            
            if(mScroller.computeScrollOffset())
            {
                mHeaderView.setVisiableHeight(mScroller.getCurrY());
                
                postInvalidate();
                invokeOnScrolling();
            }
            super.computeScroll();
        }

    每次滑动时都会调用这个computerScroll()方法,   

    mScroller.computeScrollOffset()   /////  是否有偏移

    postInvalidate()     /////  刷新界面与 Invalidate  有点细微差别~
    
    

    以上就是我的小节~

    直接贴代码吧~  如下:

    package com.example.androidtest1.widget;
    
    import android.content.Context;
    import android.text.format.Time;
    import android.util.AttributeSet;
    import android.view.MotionEvent;
    import android.view.View;
    import android.view.ViewTreeObserver.OnGlobalLayoutListener;
    import android.view.animation.DecelerateInterpolator;
    import android.widget.AbsListView;
    import android.widget.AbsListView.OnScrollListener;
    import android.widget.ListView;
    import android.widget.RelativeLayout;
    import android.widget.Scroller;
    
    import com.example.androidtest1.R;
    
    public class XListView extends ListView implements OnScrollListener {
        
        private float mLastY = -1; // save event y
        private Scroller mScroller;
        private OnScrollListener mScrollListener; ///// 滚动侦听
        
        private IXListViewListener mListViewListener; ///// 触发刷新接口
        
        private Context m_context;
        private XListViewHeader mHeaderView;
        private RelativeLayout mHeaderViewContent;
        private int mHeaderViewHeight;
        private boolean mEnablePullRefresh=true;  //// 是否允许下拉刷新
        private boolean mPullRefreshing=false;    //// 下拉刷新中?
        
        //////  list  中的数量
        private int mTotalItemCount;
        
        private int mScrollBack;
        private final static int SCROLLBACK_HEADER=0;
        private final static int SCROLLBACK_FOOTER=1;
        
        private final static int SCROLL_DURATION=400;
        private final static int PULL_LOAD_MORE_DELTA=50;
        
        private final static float OFFSET_RADIO=1.8f;
        
        public XListView(Context context) {
            super(context);
            initWidthContext(context);
        }
        
        public XListView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initWidthContext(context);
        }
    
        public XListView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initWidthContext(context);
        }
    
        private void initWidthContext(Context context)
        {
            mScroller=new Scroller(context,new DecelerateInterpolator());
            super.setOnScrollListener(this);
            
            m_context=context;
            mHeaderView=new XListViewHeader(context);
            mHeaderViewContent=(RelativeLayout) mHeaderView.findViewById(R.id.xlistview_header_content);
            addHeaderView(mHeaderView);
            
            mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener(
                    new OnGlobalLayoutListener(){
                        @Override
                        public void onGlobalLayout() {
                            mHeaderViewHeight=mHeaderViewContent.getHeight();
                            getViewTreeObserver().removeGlobalOnLayoutListener(this);
                        }
                    });
        }
        
        /**
         * 准备刷新中~
         */
        public void pullRefreshing(){
            if(!mEnablePullRefresh){
                return;
            }
            mHeaderView.setVisiableHeight(mHeaderViewHeight);
            mPullRefreshing=true;
            mHeaderView.setState(XListViewHeader.STATE_READY);
        }
        
        /*
         * 设置能否下拉刷新
         */
        public void setPullRefreshEnable(boolean enable){
            mEnablePullRefresh=enable;
            if(!mEnablePullRefresh){
                mHeaderViewContent.setVisibility(View.INVISIBLE);
            }else{
                mHeaderViewContent.setVisibility(View.VISIBLE);
            }
        }
        
        /**
         * 停止刷新
         */
        public void stopRefresh(){
            Time time=new Time();
            time.setToNow();
            mHeaderView.setRefreshTime(time.format("%Y-%m-%d %T"));
            if(mPullRefreshing==true){
                mPullRefreshing=false;
                resetHeaderHeight();
            }
        }
        
        /**
         * 未处于刷新状态,更新箭头
         * @param delta
         */
        private void updateHeaderHeight(float delta)
        {
            mHeaderView.setVisiableHeight((int)delta+mHeaderView.getVisiableHeight());
            if(mEnablePullRefresh && !mPullRefreshing){
                if(mHeaderView.getVisiableHeight()>mHeaderViewHeight){
                    mHeaderView.setState(XListViewHeader.STATE_READY);
                }else{
                    mHeaderView.setState(XListViewHeader.STATE_NORMAL);
                }
            }
            setSelection(0);
        }
        
        /**
         * 重置自定义头部高度
         */
        private void resetHeaderHeight()
        {
            int height=mHeaderView.getVisiableHeight();
            if(height==0)
                return;
            
            /*
             * 下拉刷新的高度不够~
             * */
            if(mPullRefreshing && height<=mHeaderViewHeight)
            {
                mListViewListener.reShowMoreView();
            }
            int finalHeight=0;
            if(mPullRefreshing && height>mHeaderViewHeight){
                finalHeight=mHeaderViewHeight;
            }
            
            mScrollBack=SCROLLBACK_HEADER;
            
            //////  设置滚动
            mScroller.startScroll(0, height, 0, finalHeight-height,SCROLL_DURATION);
            
            //////  触发computeScroll
            invalidate();
        }
        
        private void invokeOnScrolling(){
            if(mScrollListener instanceof OnXScrollListener){
                OnXScrollListener l=(OnXScrollListener)mScrollListener;
                l.onXScrolling(this);
            }
        }
        
        @Override
        public boolean onTouchEvent(MotionEvent ev) {
            
            if(mLastY==-1)
                mLastY=ev.getRawY();
            
            switch(ev.getAction()){
            case MotionEvent.ACTION_DOWN:
                mLastY=ev.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                final float deltaY=ev.getRawY()-mLastY;
                mLastY=ev.getRawY();
                if(getFirstVisiblePosition()==0
                        && (mHeaderView.getVisiableHeight()>0 || deltaY>0))
                {
                    updateHeaderHeight(deltaY/OFFSET_RADIO);
                    invokeOnScrolling();
                }
                break;
            default:
                mLastY=-1;
                if(getFirstVisiblePosition()==0){
                    if(mHeaderView.getVisiableHeight()>0)
                        mPullRefreshing=true;
                    
                    if(mEnablePullRefresh && mHeaderView.getVisiableHeight()>mHeaderViewHeight){
                        mHeaderView.setState(XListViewHeader.STATE_REFRESHING);
                        if(mListViewListener!=null){
                            mListViewListener.onRefresh();
                        }
                    }
                    resetHeaderHeight();
                }
                break;
            }
            return super.onTouchEvent(ev);
        }
        
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {
            mTotalItemCount=totalItemCount;
            if(mScrollListener!=null)
            {
                mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
            }
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {
            if(mScrollListener!=null)
            {
                mScrollListener.onScrollStateChanged(view, scrollState);
            }
        }
        
        @Override
        public void computeScroll() {
            
            if(mScroller.computeScrollOffset())
            {
                mHeaderView.setVisiableHeight(mScroller.getCurrY());
                
                postInvalidate();
                invokeOnScrolling();
            }
            super.computeScroll();
        }
        
        @Override
        public void setOnScrollListener(OnScrollListener l) {
            mScrollListener = l;
        }
    
        /**
         * 
         * @param l
         */
        public void setXListViewListener(IXListViewListener l){
            mListViewListener=l;
        }
        
        public interface OnXScrollListener extends OnScrollListener{
            public void onXScrolling(View view);
        }
        
        public interface IXListViewListener{
            public void onRefresh();
            public void onLoadMore();
            public void hiddenShowMoreView();
            public void reShowMoreView();
        }
    }
  • 相关阅读:
    递归的用法
    冒泡排序
    Python_MySQL:MySQL常用命令
    开发Python项目案例,这8个库不容错过,功能强大性能优质
    pyQuery CSS选择器
    数据结构——快速排序(使用Java)
    spring security 动态配置登出页面
    String、StringBuffer和StringBuilder
    vue部署项目刷新404的解决方案
    String数组常用的几种遍历方法
  • 原文地址:https://www.cnblogs.com/jackicalSong/p/4982264.html
Copyright © 2020-2023  润新知