支持上拉加载更多的recyclerView

对于下滑更新,谷歌给了个自己的控件,在v4包里,叫SwipeProgressBar,但其实并不好用,上拉加载更多这个功能谷歌直接就不管了,网上有一些用SwipeProgressBar实现的案例,但是效果都不好,所以我仿ListView上滑加载更多的思路给recyclerView用同样方法实现上拉加载。

特性:

下拉到底并且继续上拉超过一定高度后,松手才会开始刷新

松手后有回弹效果

如果没有达到指定高度,也会自动回弹

上拉超过一定高度,但是不松手,放回原来的位置,不会触发刷新

效果图:



首先是自定义一个recyclerView,重点是在里面加入一个滚动监听,代码如下

import android.content.Context;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;

import com.imaginato.qravedconsumer.utils.JLogUtils;

/**
 * Created by Administrator on 2016/1/27.
 */
public class CustomListRecyclerView extends RecyclerView{
    private float mLastY = -1; // save event y
    private int footerHeight = -1;

    // -- footer view
    private CustomDragRecyclerFooterView mFooterView;
    private boolean mEnablePullLoad;
    private boolean mPullLoading;
    private boolean isBottom;
    private boolean mIsFooterReady = false;
    private boolean mIsInertia = false;
    private LoadMoreListener loadMoreListener;

    // total list items, used to detect is at the bottom of listview.

    // for mScroller, scroll back from header or footer.
    private int mScrollBack;
    private final static int SCROLLBACK_FOOTER = 1;

    private final static int SCROLL_DURATION = 400; // scroll back duration
    private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px
    // at bottom, trigger
    // load more.
    private final static float OFFSET_RADIO = 1.8f; // support iOS like pull
    // feature.
    private OnClickListener footerClickListener;


    public CustomListRecyclerView(Context context) {
        super(context);
        initView(context);
    }

    public CustomListRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public CustomListRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    private void updateFooterHeight(float delta) {
        if(mFooterView==null)return;
        if(delta>60)delta = delta/4;
        if(delta>20)delta = delta/2;
//        Log.i("Alex2","delta是"+delta);
        int height = mFooterView.getBottomMargin() + (int) delta;

        if (mEnablePullLoad && !mPullLoading) {
            if (height > 200){
                mFooterView.setState(CustomDragFooterView.STATE_READY);
                mIsFooterReady = true;
//                Log.i("Alex2", "ready");
            } else {
                mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
                mIsFooterReady = false;
//                Log.i("Alex2", "nomal");
            }
        }
            mFooterView.setBottomMargin(height);


    }

    private void resetFooterHeight() {
        int bottomMargin = mFooterView.getBottomMargin()-20;
        if (-bottomMargin < 0) {
            mScrollBack = SCROLLBACK_FOOTER;
            Log.i("Alex2", "准备重置高度,margin是" + bottomMargin + "自高是" + footerHeight);
            this.smoothScrollBy(0,-bottomMargin);
            //一松手就立即开始加载
            if(mIsFooterReady){
                startLoadMore();
            }
        }
    }


    public void setLoadMoreListener(LoadMoreListener listener){
        this.loadMoreListener = listener;
    }

    public void initView(Context context){
        final LinearLayoutManager layoutManager = new LinearLayoutManager(context);
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        this.setLayoutManager(layoutManager);
        this.footerClickListener = new footerViewClickListener();
        this.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState){
                    case RecyclerView.SCROLL_STATE_IDLE:
                        Log.i("Alex2", "停下了||放手了");
                        if(isBottom)resetFooterHeight();
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING:
                        Log.i("Alex2", "开始拖了,现在margin是" + (mFooterView == null ? "" : mFooterView.getBottomMargin()));
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING:
                        Log.i("Alex2", "开始惯性移动");
                        break;
                }

            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int lastItemPosition = layoutManager.findLastVisibleItemPosition();
                Log.i("Alex2","mEnable是"+mEnablePullLoad+"lastitemPosition是"+lastItemPosition+" itemcount是"+layoutManager.getItemCount());
                if(lastItemPosition == layoutManager.getItemCount()-1 && mEnablePullLoad) {
                    isBottom = true;
                    mFooterView = (CustomDragRecyclerFooterView)layoutManager.findViewByPosition(layoutManager.findLastVisibleItemPosition());//一开始还不能hide,因为hide得到最后一个可见的就不是footerview了
                    Log.i("Alex2","到底啦!!"+"mfooterView是"+mFooterView);
                    if(mFooterView!=null) mFooterView.setOnClickListener(footerClickListener);
                    if(footerHeight==-1 && mFooterView!=null){
                        mFooterView.show();
                        mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
                        footerHeight = mFooterView.getMeasuredHeight();//这里的测量一般不会出问题
                        Log.i("Alex2", "底部高度为" + footerHeight);
                    }
                    updateFooterHeight(dy);
                }else {
                    isBottom = false;
                }
            }
        });
    }

    /**
     * enable or disable pull up load more feature.
     *
     * @param enable
     */
    public void setPullLoadEnable(boolean enable) {
        mPullLoading = false;
        mEnablePullLoad = enable;
        if(mFooterView==null)return;
        if (!mEnablePullLoad) {
//            this.smoothScrollBy(0,-footerHeight);
            mFooterView.hide();
            mFooterView.setOnClickListener(null);
            mFooterView.setBottomMargin(0);
            //make sure "pull up" don't show a line in bottom when listview with one page
        } else {
            mFooterView.show();
            mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
            mFooterView.setVisibility(VISIBLE);
            //make sure "pull up" don't show a line in bottom when listview with one page
            // both "pull up" and "click" will invoke load more.
            mFooterView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    startLoadMore();
                }
            });
        }
    }

    /**
     * stop load more, reset footer view.
     */
    public void stopLoadMore() {
        if (mPullLoading == true) {
            mPullLoading = false;
            mFooterView.show();
            mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
        }
    }

    private void startLoadMore() {
        mPullLoading = true;
        mFooterView.setState(CustomDragFooterView.STATE_LOADING);
        Log.i("Alex2", "现在开始加载");
        mIsFooterReady = false;
        if (loadMoreListener != null) {
            loadMoreListener.onLoadMore();
        }
    }

    /**
     * 在刷新时要执行的方法
     */
    public interface LoadMoreListener{
        public void onLoadMore();
    }

    /**
     * 点击loadMore后要执行的事件
     */
    class footerViewClickListener implements OnClickListener {

        @Override
        public void onClick(View v) {
            startLoadMore();
        }
    }

}




然后是底部的自定义View,我这里是一个LinearLayout


import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.qraved.app.R;


public class CustomDragRecyclerFooterView extends LinearLayout {
    public final static int STATE_NORMAL = 0;
    public final static int STATE_READY = 1;
    public final static int STATE_LOADING = 2;

    private Context mContext;

    private View mContentView;
    private View mProgressBar;
    private TextView mHintView;

    public CustomDragRecyclerFooterView(Context context) {
        super(context);
        initView(context);
    }

    public CustomDragRecyclerFooterView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }


    public void setState(int state) {
        mHintView.setVisibility(View.INVISIBLE);
        mProgressBar.setVisibility(View.INVISIBLE);
        mHintView.setVisibility(View.INVISIBLE);
        if (state == STATE_READY) {
            mHintView.setVisibility(View.VISIBLE);
            mHintView.setText(R.string.xlistview_footer_hint_ready);
        } else if (state == STATE_LOADING) {
            mProgressBar.setVisibility(View.VISIBLE);
        } else {
            mHintView.setVisibility(View.VISIBLE);
            mHintView.setText(R.string.xlistview_footer_hint_normal);
        }
    }

    public void setBottomMargin(int height) {
        if (height < 0) return ;
        LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
        lp.bottomMargin = height;
        mContentView.setLayoutParams(lp);
    }

    public int getBottomMargin() {
        LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
        return lp.bottomMargin;
    }


    /**
     * normal status
     */
    public void normal() {
        mHintView.setVisibility(View.VISIBLE);
        mProgressBar.setVisibility(View.GONE);
    }


    /**
     * loading status
     */
    public void loading() {
        mHintView.setVisibility(View.GONE);
        mProgressBar.setVisibility(View.VISIBLE);
    }

    /**
     * hide footer when disable pull load more
     */
    public void hide() {
        LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
        lp.height = 1;//这里如果设为0那么layoutManger就会抓不到
        mContentView.setLayoutParams(lp);
        mContentView.setBackgroundColor(Color.BLACK);//这里的颜色要和自己的背景色一致
    }

    /**
     * show footer
     */
    public void show() {
        LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
        lp.height = LayoutParams.WRAP_CONTENT;
        lp.width =  LayoutParams.MATCH_PARENT;
        mContentView.setLayoutParams(lp);
        mContentView.setBackgroundColor(Color.WHITE);//这里的颜色要和自己的背景色一致
    }

    private void initView(Context context) {
        mContext = context;
        this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));//recyclerView里不加这句话的话宽度就会不够
        LinearLayout moreView = (LinearLayout)LayoutInflater.from(mContext).inflate(R.layout.layout_customdragfooterview, null);
        addView(moreView);
        moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
        mContentView = moreView.findViewById(R.id.rlContentView);
        mProgressBar = moreView.findViewById(R.id.pbContentView);
        mHintView = (TextView)moreView.findViewById(R.id.ctvContentView);
    }
}

顺便把自定义的布局也贴出来

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:imaginato="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <RelativeLayout
        android:id="@+id/rlContentView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="10dp">

        <ProgressBar
            android:id="@+id/pbContentView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:visibility="invisible" />

        <TextView
            android:id="@+id/ctvContentView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:textSize="13sp"
             />
    </RelativeLayout>

    <View
        android:id="@+id/line"
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#CCCCCC"
        android:visibility="gone" />

</LinearLayout>



最最重要的是适配器的写法,这里我考虑了一个recyclerView有头部,有中间很多item,还有显示loadmore的脚部,对应三个ViewHolder,下面给出一个适配器的案例


public class EventDetailAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
        private static final int TYPE_HEADER = 0;
        private static final int TYPE_ITEM = 1;
        private static final int TYPE_FOOTER = 2;

        private final int HEADER = 0;
        private final int ITEM = 0;
        boolean loadMore;
        int restraurantCount;



        public EventDetailAdapter(){
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_ITEM) {
                //inflate your layout and pass it to view holder
                View itemView = LayoutInflater.from(parent.getContext()).inflate(ITEM,null);
                return new VHItem(itemView);
            } else if (viewType == TYPE_HEADER) {
                //inflate your layout and pass it to view holder
                View headerView = LayoutInflater.from(parent.getContext()).inflate(HEADER,null);
                return new VHHeader(headerView);
            } else if(viewType==TYPE_FOOTER){
                CustomDragRecyclerFooterView footerView = new CustomDragRecyclerFooterView(parent.getContext());
                return new VHFooter(footerView);
            }

            throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
        }

        public void setPullLoadMoreEnable(boolean enable){
            this.loadMore = enable;
        }
        public boolean getPullLoadMoreEnable(){return loadMore;}

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {//相当于getView
            Log.i("Alex","正在绑定"+position+"    "+holder);
            if (holder instanceof VHItem) {
                //cast holder to VHItem and set data
                initItemView((VHItem) holder,restaurants.get(position-1),position);
            }else if (holder instanceof VHHeader) {
                //cast holder to VHHeader and set data for header.
            }else if(holder instanceof VHFooter){
                if(!loadMore)((VHFooter)holder).footerView.hide();//第一次初始化显示的时候要不要显示footerView
            }
        }

        @Override
        public int getItemCount() {
            return restaurants==null?1:restaurants.size() + 2;
        }//这里要考虑到头尾部,多以要加2

        /**
         * 根据位置判断这里该用哪个ViewHolder
         * @param position
         * @return
         */
        @Override
        public int getItemViewType(int position) {
            if (isPositionHeader(position))return TYPE_HEADER;
            else if(isPositonFooter(position))return TYPE_FOOTER;
            return TYPE_ITEM;
        }

        /**
         * 根据position判断现在是不是头部
         * @param position
         * @return
         */
        private boolean isPositionHeader(int position) {
            return position == 0;
        }
        private boolean isPositonFooter(int position){//这里的position从0算起
            if(restaurants==null && position==1)return true;
            return position==restaurants.size()+1;
        }

        class VHItem extends RecyclerView.ViewHolder {
            RelativeLayout rlRestaurantImage;
            ImageView iv_restarantImage,iv_start1,iv_start2,iv_start3,iv_start4,iv_start5;
            LinearLayout llBookNow,ll_off;
            List<ImageView>starsList = new ArrayList<ImageView>();
            CustomTextView tv_reviewNum,tv_detail,tv_distance,tv_restarantName,tv_off;
            View itemView,v_divider;
            public VHItem(View itemView) {
                super(itemView);
                rlRestaurantImage = (RelativeLayout)itemView.findViewById(R.id.rlRestaurantImage);
                iv_restarantImage = (ImageView)itemView.findViewById(R.id.iv_restarantImage);
                llBookNow = (LinearLayout)itemView.findViewById(R.id.llBookNow);
                iv_start1 = (ImageView)itemView.findViewById(R.id.iv_start1);
                iv_start2 = (ImageView)itemView.findViewById(R.id.iv_start2);
                iv_start3 = (ImageView)itemView.findViewById(R.id.iv_start3);
                iv_start4 = (ImageView)itemView.findViewById(R.id.iv_start4);
                iv_start5 = (ImageView)itemView.findViewById(R.id.iv_start5);
                tv_reviewNum = (CustomTextView)itemView.findViewById(R.id.tv_reviewNum);
                tv_detail = (CustomTextView)itemView.findViewById(R.id.tv_detail);
                tv_distance = (CustomTextView)itemView.findViewById(R.id.tv_distance);
                tv_restarantName = (CustomTextView)itemView.findViewById(R.id.tv_restarantName);
                v_divider = itemView.findViewById(R.id.v_divider);
                starsList.add(iv_start1);starsList.add(iv_start2);starsList.add(iv_start3);starsList.add(iv_start4);starsList.add(iv_start5);
                ll_off = (LinearLayout)itemView.findViewById(R.id.ll_off);
                tv_off = (CustomTextView)itemView.findViewById(R.id.tv_off);
            }
            public View getItemView(){return itemView;}
        }

        class VHHeader extends RecyclerView.ViewHolder {

            public VHHeader(View headerView) {
                super(headerView);

            }
        }

        class VHFooter extends RecyclerView.ViewHolder {
            CustomDragRecyclerFooterView footerView;

            public VHFooter(View itemView) {
                super(itemView);
                footerView = (CustomDragRecyclerFooterView)itemView;
            }
        }

        private void initItemView(VHItem holder,EventDetailRestaurantEntity restaurant,int posion){
            if(restaurants==null||restaurants.size()==0){//如果没有restaurant
                if(holder.getItemView()!=null)holder.getItemView().setVisibility(View.GONE);
                return;
            }
            holder.tv_reviewNum.setText(restaurant.getRatingCount()+"");
            holder.tv_detail.setText(EventProducer.generateDetail(holder.tv_detail.getContext(),restaurant));//计算价格区间
            holder.tv_distance.setText(EventProducer.calculateDistance(holder.tv_distance.getContext(), restaurant));
            holder.tv_restarantName.setText(restaurant.getTitle()+"");
        }



        private void initHeaderView(final VHHeader holder) {

        }



    }



 调用方法: 
 

 EventDetailAdapter adapter;
            adapter = new EventDetailAdapter(banner,restaurants,true);recyclerView.setPullLoadEnable(true);

 
 
recyclerView.setLoadMoreListener(new LoadMoreListener{
@Override
                    public void onLoadMore() {
                        JLogUtils.i("Alex","执行onLoadMore方法");
                        
                    }
});
 
 

根据上面的原理,可以把recyclerView控件,adapter和footerVIew整合到一个类当中去,方便开发的时候调用,如下

底下这个类具备如下特性:

1、封装了LayoutManager,不要再在外面设置了。

2、内置了FooterVIew及其控制逻辑。

3、给这个recyclerView设置的适配器要用这个recycler里封装好的AlxDragRecyclerViewAdapter,泛型是list的元素。继承这个抽象类,并在这个抽象类的内部写类继承ViewHolder,然后在set...ViewHolder方法中实例化自定义Viewholder,在构造函数中传入布局的id,如果没有头部就把头部的id传0,并且让setHeaderViewHolder方法返回null

import android.content.Context;
import android.graphics.Color;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;

import com.qraved.app.R;

import java.util.List;

/**
 * Created by Administrator on 2016/1/27.
 */
public class CustomDragRecyclerView extends RecyclerView{
    private int footerHeight = -1;

    // -- footer view
    private CustomDragRecyclerFooterView mFooterView;
    private boolean mEnablePullLoad;
    private boolean mPullLoading;
    private boolean isBottom;
    private boolean mIsFooterReady = false;
    private LoadMoreListener loadMoreListener;

    private AlxDragRecyclerViewAdapter adapter;

    // total list items, used to detect is at the bottom of listview.

    // for mScroller, scroll back from header or footer.
    private int mScrollBack;
    private final static int SCROLLBACK_FOOTER = 1;

    private final static int SCROLL_DURATION = 400; // scroll back duration
    private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px
    // at bottom, trigger
    // load more.
    private final static float OFFSET_RADIO = 1.8f; // support iOS like pull
    // feature.
    private View.OnClickListener footerClickListener;


    public CustomDragRecyclerView(Context context) {
        super(context);
        initView(context);
    }

    public CustomDragRecyclerView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initView(context);
    }

    public CustomDragRecyclerView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        initView(context);
    }

    public void setAdapter(AlxDragRecyclerViewAdapter adapter){
        super.setAdapter(adapter);
        this.adapter = adapter;
    }

    private void updateFooterHeight(float delta) {
        if(mFooterView==null)return;
        if(delta>60)delta = delta/4;
        if(delta>20)delta = delta/2;
//        Log.i("Alex2","delta是"+delta);
        int height = mFooterView.getBottomMargin() + (int) delta;

        if (mEnablePullLoad && !mPullLoading) {
            if (height > 150){
                mFooterView.setState(CustomDragFooterView.STATE_READY);
                mIsFooterReady = true;
//                Log.i("Alex2", "ready");
            } else {
                mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
                mIsFooterReady = false;
//                Log.i("Alex2", "nomal");
            }
        }
        mFooterView.setBottomMargin(height);


    }

    private void resetFooterHeight() {
        int bottomMargin = mFooterView.getBottomMargin()-20;
        if (-bottomMargin < 0) {
            mScrollBack = SCROLLBACK_FOOTER;
            Log.i("Alex2", "准备重置高度,margin是" + bottomMargin + "自高是" + footerHeight);
            this.smoothScrollBy(0,-bottomMargin);
            //一松手就立即开始加载
            if(mIsFooterReady){
                startLoadMore();
            }
        }
    }


    public void setLoadMoreListener(LoadMoreListener listener){
        this.loadMoreListener = listener;
    }

    public void initView(Context context){
        final LinearLayoutManager layoutManager = new LinearLayoutManager(context);//自带layoutManager,请勿设置
        layoutManager.setOrientation(LinearLayoutManager.VERTICAL);
        this.setLayoutManager(layoutManager);
        this.footerClickListener = new footerViewClickListener();
        this.addOnScrollListener(new RecyclerView.OnScrollListener() {

            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
                switch (newState){
                    case RecyclerView.SCROLL_STATE_IDLE:
                        Log.i("Alex2", "停下了||放手了");
                        if(isBottom)resetFooterHeight();
                        break;
                    case RecyclerView.SCROLL_STATE_DRAGGING:
                        Log.i("Alex2", "开始拖了,现在margin是" + (mFooterView == null ? "" : mFooterView.getBottomMargin()));
                        break;
                    case RecyclerView.SCROLL_STATE_SETTLING:
                        Log.i("Alex2", "开始惯性移动");
                        break;
                }

            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                int lastItemPosition = layoutManager.findLastVisibleItemPosition();
                Log.i("Alex2","mEnable是"+mEnablePullLoad+"lastitemPosition是"+lastItemPosition+" itemcount是"+layoutManager.getItemCount());
                if(lastItemPosition == layoutManager.getItemCount()-1 && mEnablePullLoad) {
                    isBottom = true;
                    mFooterView = (CustomDragRecyclerFooterView)layoutManager.findViewByPosition(layoutManager.findLastVisibleItemPosition());//一开始还不能hide,因为hide得到最后一个可见的就不是footerview了
                    Log.i("Alex2","到底啦!!"+"mfooterView是"+mFooterView);
                    if(mFooterView!=null) mFooterView.setOnClickListener(footerClickListener);
                    if(footerHeight==-1 && mFooterView!=null){
                        mFooterView.show();
                        mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
                        footerHeight = mFooterView.getMeasuredHeight();//这里的测量一般不会出问题
                        Log.i("Alex2", "底部高度为" + footerHeight);
                    }
                    updateFooterHeight(dy);
                }else {
                    isBottom = false;
                }
            }
        });
    }

    /**
     * enable or disable pull up load more feature.
     *
     * @param enable
     */
    public void setPullLoadEnable(boolean enable) {
        mPullLoading = false;
        mEnablePullLoad = enable;
        if(adapter!=null)adapter.setPullLoadMoreEnable(enable);//adapter和recyclerView要同时设置
        if(mFooterView==null)return;
        if (!mEnablePullLoad) {
//            this.smoothScrollBy(0,-footerHeight);
            mFooterView.hide();
            mFooterView.setOnClickListener(null);
            mFooterView.setBottomMargin(0);
            //make sure "pull up" don't show a line in bottom when listview with one page
        } else {
            mFooterView.show();
            mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
            mFooterView.setVisibility(VISIBLE);
            //make sure "pull up" don't show a line in bottom when listview with one page
            // both "pull up" and "click" will invoke load more.
            mFooterView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    startLoadMore();
                }
            });
        }
    }

    /**
     * stop load more, reset footer view.
     */
    public void stopLoadMore() {
        if (mPullLoading == true) {
            mPullLoading = false;
            mFooterView.show();
            mFooterView.setState(CustomDragFooterView.STATE_NORMAL);
        }
    }

    private void startLoadMore() {
        mPullLoading = true;
        mFooterView.setState(CustomDragFooterView.STATE_LOADING);
        Log.i("Alex2", "现在开始加载");
        mIsFooterReady = false;
        if (loadMoreListener != null) {
            loadMoreListener.onLoadMore();
        }
    }

    /**
     * 在刷新时要执行的方法
     */
    public interface LoadMoreListener{
        public void onLoadMore();
    }

    /**
     * 点击loadMore后要执行的事件
     */
    class footerViewClickListener implements View.OnClickListener {

        @Override
        public void onClick(View v) {
            startLoadMore();
        }
    }


    public static class CustomDragRecyclerFooterView extends LinearLayout {
        public final static int STATE_NORMAL = 0;
        public final static int STATE_READY = 1;
        public final static int STATE_LOADING = 2;

        private Context mContext;

        private View mContentView;
        private View mProgressBar;
        private TextView mHintView;

        public CustomDragRecyclerFooterView(Context context) {
            super(context);
            initView(context);
        }

        public CustomDragRecyclerFooterView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView(context);
        }


        public void setState(int state) {
            mHintView.setVisibility(View.INVISIBLE);
            mProgressBar.setVisibility(View.INVISIBLE);
            mHintView.setVisibility(View.INVISIBLE);
            if (state == STATE_READY) {
                mHintView.setVisibility(View.VISIBLE);
                mHintView.setText(R.string.xlistview_footer_hint_ready);
            } else if (state == STATE_LOADING) {
                mProgressBar.setVisibility(View.VISIBLE);
            } else {
                mHintView.setVisibility(View.VISIBLE);
                mHintView.setText(R.string.xlistview_footer_hint_normal);
            }
        }

        public void setBottomMargin(int height) {
            if (height < 0) return ;
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.bottomMargin = height;
            mContentView.setLayoutParams(lp);
        }

        public int getBottomMargin() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            return lp.bottomMargin;
        }


        /**
         * normal status
         */
        public void normal() {
            mHintView.setVisibility(View.VISIBLE);
            mProgressBar.setVisibility(View.GONE);
        }


        /**
         * loading status
         */
        public void loading() {
            mHintView.setVisibility(View.GONE);
            mProgressBar.setVisibility(View.VISIBLE);
        }

        /**
         * hide footer when disable pull load more
         */
        public void hide() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.height = 1;//这里如果设为0那么layoutManger就会抓不到
            mContentView.setLayoutParams(lp);
            mContentView.setBackgroundColor(Color.BLACK);//这里的颜色要和自己的背景色一致
        }

        /**
         * show footer
         */
        public void show() {
            LayoutParams lp = (LayoutParams)mContentView.getLayoutParams();
            lp.height = LayoutParams.WRAP_CONTENT;
            lp.width =  LayoutParams.MATCH_PARENT;
            mContentView.setLayoutParams(lp);
            mContentView.setBackgroundColor(Color.WHITE);//这里的颜色要和自己的背景色一致
        }

        private void initView(Context context) {
            mContext = context;
            this.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            LinearLayout moreView = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_customdragfooterview, null);
            addView(moreView);
            moreView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT));
            mContentView = moreView.findViewById(R.id.rlContentView);
            mProgressBar = moreView.findViewById(R.id.pbContentView);
            mHintView = (TextView)moreView.findViewById(R.id.ctvContentView);
        }
    }

    public static abstract class AlxDragRecyclerViewAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
        private static final int TYPE_HEADER = 0;
        private static final int TYPE_ITEM = 1;
        private static final int TYPE_FOOTER = 2;

        private int ITEM;
        private int HEADER;

        private ViewHolder vhHeader;
        private ViewHolder vhItem;
        boolean loadMore;

        private List<T> dataList;

        public List<T> getDataList() {
            return dataList;
        }

        public void setDataList(List<T> dataList) {
            this.dataList = dataList;
        }

        public AlxDragRecyclerViewAdapter(List<T> dataList,int headerLayout,int itemLayout,boolean pullEnable){
            this.dataList = dataList;
            this.ITEM = itemLayout;
            this.HEADER = headerLayout;
            this.loadMore = pullEnable;
        }

        public abstract ViewHolder setItemViewHolder(View itemView);
        public abstract ViewHolder setHeaderViewHolder(View headerView);

        private T getObject(int position){
            if(HEADER!=0 && dataList!=null && dataList.size()>=position)return dataList.get(position-1);//如果有header
            if(dataList!=null && dataList.size() >= (position+1))return dataList.get(position);//如果没有header
            return null;
        }

        @Override
        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            if (viewType == TYPE_ITEM) {
                //inflate your layout and pass it to view holder
                View itemView = LayoutInflater.from(parent.getContext()).inflate(ITEM,null);
                Log.i("Alex","itemView是"+itemView);
                this.vhItem = setItemViewHolder(itemView);
                Log.i("Alex","vhItem是"+vhItem);
                return vhItem;
            } else if (viewType == TYPE_HEADER) {
                //inflate your layout and pass it to view holder
                View headerView = LayoutInflater.from(parent.getContext()).inflate(HEADER,null);
                Log.i("Alex","headerView是"+headerView);
                this.vhHeader = setHeaderViewHolder(headerView);
                Log.i("Alex","vhItem是"+vhItem);
                return this.vhHeader;
            } else if(viewType==TYPE_FOOTER){
                CustomDragRecyclerFooterView footerView = new CustomDragRecyclerFooterView(parent.getContext());
                return new VHFooter(footerView);
            }

            throw new RuntimeException("there is no type that matches the type " + viewType + " + make sure your using types correctly");
        }

        public void setPullLoadMoreEnable(boolean enable){
            this.loadMore = enable;
        }
        public boolean getPullLoadMoreEnable(){return loadMore;}

        @Override
        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {//相当于getView
            Log.i("Alex","正在绑定"+position+"    "+holder.getClass());
            if (vhItem!=null && holder.getClass() == vhItem.getClass()) {
                //cast holder to VHItem and set data
                initItemView(holder,position,getObject(position));
            }else if (vhHeader!=null && holder.getClass() == vhHeader.getClass()) {
                //cast holder to VHHeader and set data for header.
                initHeaderView(holder);
            }else if(holder instanceof AlxDragRecyclerViewAdapter.VHFooter){
                if(!loadMore)((VHFooter)holder).footerView.hide();//第一次初始化显示的时候要不要显示footerView
            }
        }

        @Override
        public int getItemCount() {
            if(HEADER==0)return dataList==null?0:dataList.size() + 1;//如果没有header
            return dataList==null?1:dataList.size() + 2;//如果有header
        }//这里要考虑到头尾部,多以要加2

        /**
         * 根据位置判断这里该用哪个ViewHolder
         * @param position
         * @return
         */
        @Override
        public int getItemViewType(int position) {
            if (position == 0 && HEADER!=0)return TYPE_HEADER;
            else if(isPositonFooter(position))return TYPE_FOOTER;
            return TYPE_ITEM;
        }

        private boolean isPositonFooter(int position){//这里的position从0算起
            if(HEADER!=0) {//如果有header
                if (dataList == null && position == 1) return true;//如果没有item
                return position == dataList.size() + 1;//如果有item(也许为0)
            }
            //如果没有header
            if (dataList == null && position == 0) return true;//第一行就是footer
            return position == dataList.size();
        }
//自定义Viewholder的事例
//        class VHItem extends RecyclerView.ViewHolder {
//            public VHItem(View itemView) {
//                super(itemView);
//            }
//            public View getItemView(){return itemView;}
//        }
//
//        class VHHeader extends RecyclerView.ViewHolder {
//
//            public VHHeader(View headerView) {
//                super(headerView);
//
//            }
//        }

        class VHFooter extends RecyclerView.ViewHolder {
            CustomDragRecyclerFooterView footerView;

            public VHFooter(View itemView) {
                super(itemView);
                footerView = (CustomDragRecyclerFooterView)itemView;
            }
        }

        public abstract void initItemView(ViewHolder itemHolder,int posion,T entity);

        public abstract void initHeaderView(final ViewHolder headerHolder);

    }


}







你可能感兴趣的:(ListView,RecyclerView)