对于下滑更新,谷歌给了个自己的控件,在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(); } } }
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); } }