平常开发我们需要使用ListView下拉刷新或者其上滑加载的时候,不是自己写就是用别人写好了,但是编程中有一点是不变的,就是一般封装好的东西,其扩展性极低,比如你使用xutils,imageloader等开源框架的时候,它允许你扩展吗?答案当然是否,那我想要实现自己非常酷酷的ListView时候,只有自己动手实现。不过,谷歌在2015在v4开发包加入 豪华套餐SwipeRefreshLayout供你享用。
1.SwipeRefreshLayout使用注意说明
㈠SwipeRefreshLayout默认只能包含一个滑动控件,比如本文使用的RecyclerView。
㈡一般使用ListView组件都有一个需求,那么就是没有网络的情况下,将显示其他控件提示用户加载失败或者需要联网。那么,SwipeRefreshLayout可以包含有且仅有一个布局,布局里面可以添加你需要的控件。
㈢如果你按㈡这样做,那么SwipeRefreshLayout默认只会监听一个滑动控件,当你有多个控件的时候会使其找不到监听的滑动控件。这样SwipeRefreshLayout功能就不复存在了。
㈣那么今天我们将实现的下拉刷新和上滑加载该怎么办呢?答案就是重写SwipeRefreshLayout。
2.重写SwipeRefreshLayout
当我们重写SwipeRefreshLayout,需要使用到如下一个方法:
㈠canChildScrollUp
我们来看看其文档说明:
public boolean canChildScrollUp () Returns Whether it is possible for the child view of this layout to scroll up. Override this if the child view is a custom view.
如果子视图为自定义视图那么必须重写该方法。同理,当你的子视图用布局包裹的时候,其就是你自定义的,除非你的子视图只有ListView,当有多个控件时候,其默认找不到ListView监听其滑动事件,必须重写该方法。
㈡重写SwipeRefreshLayout
既然找不到该子视图,那么就必须传入子视图的控件,以监听其滑动状态,也就是自定义一个属性:
<declare-styleable name="LYJSwipeLayoutAttrs"> <attr name="scrollableChildId" format="reference" /> </declare-styleable>
下面源码是怎么写的canChildScrollUp:
public boolean canChildScrollUp() { if (android.os.Build.VERSION.SDK_INT < 14) { if (mTarget instanceof AbsListView) { final AbsListView absListView = (AbsListView) mTarget; return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) .getTop() < absListView.getPaddingTop()); } else { return ViewCompat.canScrollVertically(mTarget, -1) || mTarget.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(mTarget, -1); } }
下面我们来依葫芦画瓢重写SwipeRefreshLayout:
public class LYJSwipeRefreshLayout extends SwipeRefreshLayout { private static final String TAG = LYJSwipeRefreshLayout.class.getCanonicalName(); private int mScrollableChildId;//控件ID private View mScrollableChild;//子控件 public LYJSwipeRefreshLayout(Context context) { this(context, null); } public LYJSwipeRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); //获取监听子控件的ID TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.LYJSwipeLayoutAttrs); mScrollableChildId = a.getResourceId(R.styleable.LYJSwipeLayoutAttrs_scrollableChildId, 0); mScrollableChild = findViewById(mScrollableChildId); a.recycle(); } @Override public boolean canChildScrollUp() { //判断有没有传入子控件 ensureScrollableChild(); if (android.os.Build.VERSION.SDK_INT < 14) { if (mScrollableChild instanceof AbsListView) { final AbsListView absListView = (AbsListView) mScrollableChild; return absListView.getChildCount() > 0 && (absListView.getFirstVisiblePosition() > 0 || absListView.getChildAt(0) .getTop() < absListView.getPaddingTop()); } else { return mScrollableChild.getScrollY() > 0; } } else { return ViewCompat.canScrollVertically(mScrollableChild, -1); } } private void ensureScrollableChild() { if (mScrollableChild == null) { mScrollableChild = findViewById(mScrollableChildId); } } }
布局文件如下:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <android.support.v7.widget.Toolbar android:id="@+id/activity_main_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="@color/activity_main_tablayout_bg"> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:layout_gravity="center" android:text="@string/app_name" android:textColor="@android:color/black" android:textSize="20sp" android:textStyle="bold" /> </android.support.v7.widget.Toolbar> <com.example.liyuanjing.welltestdemo.LYJSwipeRefreshLayout xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/activity_main_swipe" android:layout_width="match_parent" android:layout_height="match_parent" app:scrollableChildId="@+id/activity_main_recyclerview" android:background="@android:color/transparent"> <FrameLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.RecyclerView android:id="@+id/activity_main_recyclerview" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="@null" android:scrollbars="vertical" /> <LinearLayout android:id="@+id/activity_main_linearlayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"/> </FrameLayout> </com.example.liyuanjing.welltestdemo.LYJSwipeRefreshLayout> </LinearLayout>
红色标记的为传入子控件ID的属性。这样SwipeRefreshLayout就可以监听recyclerview了。