分享磨砺营马剑威老师讲解-GridView如何实现上拉更多和下拉刷新

GridView上拉更多和下拉刷新的原理分析:

一、要解决的问题:

       1:GridView和ListView不一样listView直接提供了addFootView和addHeadView两个方法,GridView是没有这两个方法的.

       猜想解决方案:GridView既然是不能直接添加HeadView和FootView的那么可以借助于组合控件. 

       2:猜想产生的问题

           如果借助于组合控件的话那么GridView的滑动和FootView的滑动是独立的,没有相关联(也就是说,GridView的滑动与否和FootVew本身没有任何的联系)

        猜想解决方案:如果我们借助于,ScrollView来进行滑动的话那么在ScrollView的底部有了这个FootView的话那么是可以滑动的

        3:猜想产生的问题

        ScrollView和GridView不一样,ScrollView是不能直接给添加适配器的

        猜想解决方案

        使用ScrollView中嵌套一个布局不居中包括 GridView和一个底部的FootView

二、ScrollView中嵌套GridView的时候会造成显示不全的问题,需要解决ScrollView计算孩子高度的问题

         解决方案:可以重写GridView中的onMeasure()方法,然后给定孩子高度的最大值,然后再设计一个测量的模式.

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int expectHeight=MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE>>2,MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

三、需要解决什么时候滑动到了底部和顶部

         解决方案:可以通过计算ScrollView孩子的高度,以及当前孩子滑动的顶部的相对的Y的偏移量  getScrollY和当前窗体的高度getHeight.如果getScrollY+getHeight>=孩子的高度,说明滑动到底部了

四、解决问题:ScrollView知道了什么时候滑动到底部,如何将上级的状态

         解决方案:直接通过回调的方法将状态在传递到上级页面

五、整合所有的对象

源代码如下:

                GridView

public class MyGridView extends GridView {

public MyGridView(Context context, AttributeSet attrs, int defStyleAttr) {

    super(context, attrs, defStyleAttr);

}

public MyGridView(Context context) {

    super(context);

}

public MyGridView(Context context, AttributeSet attrs) {

    super(context, attrs);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    int heighMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST);

    super.onMeasure(widthMeasureSpec, heighMeasureSpec);

}

}

                   MyScrollViewpublic class MyScrollView extends ScrollView{

private static final String LOAD="load";   //表示的是加载数据的状态

private static final String REFRESH="refresh";  //表示的是需要刷新页面的状态

public MyScrollView(Context context, AttributeSet attrs) {

    super(context, attrs);

}

interface ICallBack{

    public void notifactionAbovePage(String tag);

}

ICallBack mICallBack=null;

public void setOnCallBackLister(ICallBack mICallBack){

    this.mICallBack=mICallBack;

}

@Override

protected void onScrollChanged(int l, int t, int oldl, int oldt) {

    super.onScrollChanged(l, t, oldl, oldt);

   if(getChildAt(0)!=null){   //有这个孩子才有意义的

       View childView=getChildAt(0);

       //第二步:通过孩子获取孩子本身的高度

       int childMeasuredHeight = childView.getMeasuredHeight();

       //第三步:获取屏幕顶部的相对y坐标

       int scrollY = getScrollY();    //屏幕顶部相对的y坐标

       //第四步:获取当前屏幕的高度

       int screenHeight=getHeight();

       if(scrollY+screenHeight==childMeasuredHeight){   //说明滑动到底部了?

           //这个地方是有遗留的问题的最后还需要处理

           if(PullUpLoadView.getDownLoadingOrNot()){

               return;

           }

           mICallBack.notifactionAbovePage(LOAD);

       }

   }

}

}

                PullUpLoadView  public class PullUpLoadView extends LinearLayout{

private static final String LOAD="load";   //表示的是加载数据的状态

private static final String REFRESH="refresh";  //表示的是需要刷新页面的状态

MyGridView mMyGridView;

LinearLayout footView;

MyScrollView mMyScrollView;

static boolean downLoadingOrNot=false;   //判断当前是否正在加载数据

public PullUpLoadView(Context context, AttributeSet attrs) {

    super(context, attrs);

    initView();

}

/**

 * 初始化数据用的

 */

private void initView() {

    //初始化布局加载器

    LayoutInflater mLayoutInflater= (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);

    View view=mLayoutInflater.inflate(R.layout.scroll_grid_footview,this);  //这句话的意思是把当前的布局绑定给谁

    findView(view);

    setCallBack();

}

/**

 * 写一个方法来实现回调

 */

private void setCallBack() {

   mMyScrollView.setOnCallBackLister(new OnCallBack());

}

/**

 * 定义一个接口回调到Activity页面

 */

public interface PullCallBack{

    public void load();

    public void refresh();

}

PullCallBack mPullCallBack=null;

public void setPullCallBacklistener(PullCallBack mPullCallBack ){

    this.mPullCallBack=mPullCallBack;

}

/**

 * 上一个页面回调的状态

 */

private class OnCallBack implements MyScrollView.ICallBack{

    @Override

    public void notifactionAbovePage(String tag) {

      if(tag.equals(LOAD)){  //说明需要加载数据

          //在这个地方我们书不是需要将这个状态发送到Activity这个页面去

          mPullCallBack.load();

          handler.sendEmptyMessage(100);

          downLoadingOrNot=true;   //表示的额是正在加载

      }else{   //说明需要刷新数据

      }

    }

}

//刷新UI

Handler handler=new Handler(){

    @Override

    public void handleMessage(Message msg) {

        switch (msg.what){

            case 100:     //表示的是需要显示底部的View

                setFootViewVisible();

                break;

            case 101:    //表示的是需要隐藏底部的View

                 setFootViewHide();

                 downLoadingOrNot=false;

                break;

        }

    }

};

/**

 * 获取是否正在加载数据的这个状态

 * [@return](http://my.oschina.net/u/556800)

 */

public static boolean getDownLoadingOrNot(){

    return downLoadingOrNot;

}

/**

 * 说明数据已经加载完成

 * 这个方法是Activity调用的

 */

public void dataDone(){

    handler.sendEmptyMessage(101);

}

/**

 * 找下那个View

 * @param view

 */

private void findView(View view) {

    mMyGridView= (MyGridView) findViewById(R.id.gridView);

    footView= (LinearLayout) findViewById(R.id.footView);

    mMyScrollView= (MyScrollView) findViewById(R.id.myScrollView);

}

/**

 * 返回GridView

 * @return

 */

public MyGridView getMyGridView(){

    return mMyGridView;

}

/**

 * 设置footView影藏

 */

public void setFootViewHide(){

    footView.setVisibility(View.GONE);

}

/**

 * 设置FootView显示

 */

public void setFootViewVisible(){

    footView.setVisibility(View.VISIBLE);

}

}

                      <?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"

xmlns:tools="http://schemas.android.com/tools"

android:layout_width="match_parent"

android:layout_height="match_parent">

<com.example.mylibrary.MyScrollView

    android:id="@+id/myScrollView"

    android:layout_width="match_parent"

    android:layout_height="match_parent">

    <LinearLayout

        android:layout_width="match_parent"

        android:layout_height="match_parent"

        android:orientation="vertical"

        >

        <com.example.mylibrary.MyGridView

            android:id="@+id/gridView"

            android:layout_width="match_parent"

            android:layout_height="match_parent"

            android:numColumns="3"

            android:horizontalSpacing="10dp"

            android:verticalSpacing="10dp"

            />

        <LinearLayout

            android:layout_width="match_parent"

            android:layout_height="50dp"

            android:background="#ff0077"

            android:gravity="center"

            android:id="@+id/footView"

            >

            <ProgressBar

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                style="@android:style/Widget.ProgressBar.Small"

                />

            <TextView

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:text="玩命加载中..."

                />

        </LinearLayout>

    </LinearLayout>

</com.example.mylibrary.MyScrollView>

</RelativeLayout>

转载于:https://my.oschina.net/moliying/blog/730970

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值