ListView实现下拉刷新-2-将顶部布局加载到ListView中

上一篇实现了Adapter类的创建,和getView函数的分析;

这一篇主要讲第二部分,即将顶部布局加载到ListView中;重点是ReFlashListView的实现上,这一篇中我会谈一谈在阅读源代码的过程中所遇到的困难和采取的方法;

首先看ReFlashListView类:

public  class  ReFlashListView extends ListView implements OnScrollListener

表明ReFlashListView是继承自ListView的,并且 实现了OnScrollListener接口:

继承自ListView:如何进行构造方法的添加呢?我在包下又创建了一个MyListView类,进行了以下两种方法的实现:

方法1:将ListView的包导入后,鼠标移动到MyListView下,之后就会出现三种构造方法,可以点击添加;

方法2:右击->Source->Generate Constructors from Superclass,在窗口中选择Select All,点击ok;

 548662a50001dac505000399.jpg

这两种方法:方法一虽然比较简单,但是只能添加一个。方法二比较复杂,但是可以添加多个。所以推荐使用方法二;

实现了OnScrollListener接口:按住ctrl+右键,进入OnScrollListener接口的定义位置,发现他是定义在AbsListView$OnScrolListener.java文件中,在里面声明的常量和函数有:

  public  interface OnScrollListener {
         public  static  int  SCROLL_STATE_IDLE = 0
         public  static  int  SCROLL_STATE_TOUCH_SCROLL = 1;
         public  static  int  SCROLL_STATE_FLING = 2;
 
         public  void  onScrollStateChanged(AbsListView view,  int  scrollState);
 
         public  void  onScroll(AbsListView view,  int  firstVisibleItem,  int  visibleItemCount,
                 int  totalItemCount);
     }

在导入OnScrollListener的包后,鼠标移动到我们的实验类MyListView下,之后点击Add unimplemented methods;就为类添加了onScrollStateChanged和onScroll这两者函数了;

有关于ReFlashListView的继承关系与接口实现讨论结束之后,接下来我们将讨论各个成员函数的作用,并在这个过程中,获得ReFlashListView类的成员变量;最后再将成员变量和其所起的作用,总结给出(毕竟我们并不是一开始就知道需要什么成员变量,只有在写函数的时候才在开始的位置补充上的)。

首先给出各个函数的声明:

private  void  initView(Context context)
private  void  measureView(View view)
private  void  topPadding( int  topPadding)
public  void  onScroll(AbsListView view,  int  firstVisibleItem, int  visibleItemCount,  int  totalItemCount)
public  void  onScrollStateChanged(AbsListView view,  int  scrollState)
public  boolean onTouchEvent(MotionEvent ev)
private  void  onMove(MotionEvent ev)
private  void  reflashViewByState()
public  void  reflashComplete()
public  void  setInterface(IReflashListener iReflashListener)
public  interface IReflashListener

各个函数的作用:

 initView:初始化界面,添加顶部布局文件到 listview

 measureView:通知父布局,占用的宽,高;

 topPadding:设置header布局上边距;

onScroll:获取到当前可见的第一个的编号;

 onScrollStateChanged:获得listview 当前滚动状态;

 onTouchEvent:获得手势;

 onMove:根据手势,来改变view的显示;

 reflashViewByState:根据当前状态,改变界面显示;

reflashComplete:获取完数据;

 setInterface:设置监听器,主要是接口回调机制中起作用;

在initView函数中:

private  void  initView(Context context) {
         LayoutInflater inflater = LayoutInflater.from(context);  ///获得context的Inflater;
         header = inflater.inflate(R.layout.header_layout, null); ///为xml文件创建一个View对象;
         measureView(header);   ///获得高度
         headerHeight = header.getMeasuredHeight(); ///测量高度
         Log.i( "tag" "headerHeight = "  + headerHeight);
         topPadding(-headerHeight);
         this .addHeaderView(header);     ///添加顶部view
         this .setOnScrollListener( this );
     }

Inflater类的作用主要是连接xml与VIew对象的,具体的话可以看我的博客:常用但忽略的android知识1-Inflate

heade是View类型,属于类的成员变量,用来记录顶部布局;

为什么要用measureView函数来获得高度的原因是:在onCreate()里面获取控件的高度是0,ReFlashListView实例化的时候正好是在onCreate函数中的,具体的话可以看我的博客:常用但忽略的anroid知识5-获得一个view的宽和高

之后调用topPadding函数来设置高度,从而达到隐藏的目的;

ListView的成员函数addHeaderView,可以用来为ListView加载顶部布局;

最后setOnScrollListener设置监听器,自动调用onScroll,onScrollStateChanged这两个函数。

在measureView函数中:

private  void  measureView(View view) {
         ViewGroup.LayoutParams p = view.getLayoutParams();
         if  (p ==  null ) {
             p =  new  ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
                     ViewGroup.LayoutParams.WRAP_CONTENT);
         }
         int  width = ViewGroup.getChildMeasureSpec( 0 0 , p.width);
         int  height;
         int  tempHeight = p.height;
         if  (tempHeight >  0 ) {
             height = MeasureSpec.makeMeasureSpec(tempHeight,
                     MeasureSpec.EXACTLY);
         else  {
             height = MeasureSpec.makeMeasureSpec( 0 , MeasureSpec.UNSPECIFIED);
         }
         view.measure(width, height);
     }

ViewGroup.LayoutParams这个在代码中的解释是:LayoutParams are used by views to tell their parents how they want to be laid out.也就是获得view的大小;

MeasureSpec这个在代码中的解释是:A MeasureSpec encapsulates the layout requirements passed from parent to child. Each MeasureSpec represents a requirement for either the width or the height. A MeasureSpec is comprised of a size and a mode.

注意到在课程的回复区:有大神是这样说的"测量子 view 的时候根本不用这么麻烦,既然没有按照 android view 系统的标准流程走,在 onMeasure 的时候测量,而提前在构造函数的时候就测量,其实只需要高,所以只需要

p = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,

ViewGroup.LayoutParams.WRAP_CONTENT);

height = MeasureSpec.makeMeasureSpec(tempHeight,MeasureSpec.AT_MOST);

view.measure(width, height);

就行啦,宽随便设置一个值就行嘛,反正也不使用的。"


在topPadding函数中:

private  void  topPadding( int  topPadding) {
         header.setPadding(header.getPaddingLeft(), topPadding,
                 header.getPaddingRight(), header.getPaddingBottom());
         header.invalidate(); 
     }

需要注意invalidate()是用来刷新View的,必须是在UI线程中进行工作。比如在修改某个view的显示时,调用invalidate()才能看到重新绘制的界面;

通过上面的这几个函数,大致的Head顶部布局就被加载到ListView中了,并被隐藏;

下一篇我们将主要讨论状态的改变,和下拉刷新的实现。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值