你的位置:首页 > 操作系统

[操作系统]【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();  }}