This article shares the specific code of Android refresh loading framework for your reference. The specific content is as follows
1. Define an interface to control pull-down and pull-up
public interface Pullable { /** * Is it possible to pull down */ boolean canPullDown(); /** * Is it possible to pull up */ boolean canPullUp(); }
2. Define a refresh loading layout
public class PullToRefreshLayout extends RelativeLayout { /** * head */ private View headView;//Head view private ImageView headIv;//Head icon private TextView headTv;//Initial text private int headHeight;//Height private float headBorder;//Head critical /** * pull */ private View pullView;//Pull view private int pullHeight;//Pull height private int pullWidth;//Width /** * Final */ private View footView;//Tail view private ImageView footIv;//Tail icon private TextView footTv;//The end text private int footHeight;//Tail height private float footBorder;//Tail critical /** * state */ public static final int INIT = 0;//initial public static final int RELEASE_TO_REFRESH = 1;//Release refresh public static final int REFRESHING = 2;//Refreshing public static final int RELEASE_TO_LOAD = 3;//Release load public static final int LOADING = 4;//Loading public static final int DONE = 5;//Finish private int state = INIT; /** * Interface */ private OnRefreshListener mListener; private float downY;//Y coordinate when pressed private float lastY;//Previous Y coordinate private float pullDownY = 0;// Pull down offset private float pullUpY = 0;//Pull-up offset private int offset;//Offset /** * Animation */ private RotateAnimation rotateAnimation; /** * Thread */ private Handler handler = new Handler() { @Override public void handleMessage(Message msg) { (msg); if (msg != null) { switch () { case 1: (); break; case 2: (); break; default: break; } pullDownY = 0; pullUpY = 0; requestLayout(); state = INIT; refreshViewByState(); isTouch = true; } } }; /** * First execution layout */ private boolean isLayout = false; /** * Slide during refresh */ private boolean isTouch = false; /** * The ratio of the sliding distance between the finger and the sliding distance between the pull-down head will change with the tangent function. */ private float radio = 2; /** * Filter multi-touch */ private int mEvents; /** * These two variables are used to control the direction of pull. If there is no control, it cannot be pulled up when the situation meets the situation. */ private boolean canPullDown = true; private boolean canPullUp = true; public void setOnRefreshListener(OnRefreshListener listener) { mListener = listener; } public PullToRefreshLayout(Context context) { super(context); initView(context); } public PullToRefreshLayout(Context context, AttributeSet attrs) { super(context, attrs); initView(context); } public PullToRefreshLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initView(context); } private void initView(Context context) { rotateAnimation = (RotateAnimation) (context, ); } private void refreshViewByState() { switch (state) { case INIT: // Initial state of pull-down layout ("Drag down to refresh the displayed picture"); ("Drive down to refresh"); // Initial state of pull-up layout ("Pull up to load the displayed picture"); ("Pull-up Loading"); break; case RELEASE_TO_REFRESH: // Release refresh status ("Release refreshed image"); ("Release Refresh"); break; case REFRESHING: // Refreshing status ("Refreshing the displayed image"); ("Refreshing"); break; case RELEASE_TO_LOAD: // Release the loading state ("Release the picture loaded"); ("Release Loading"); break; case LOADING: // Loading status ("The displayed picture is loading"); ("Loading"); break; case DONE: // After refreshing or loading, do nothing break; } } /** * No limit on pull-up or pull-down */ private void releasePull() { canPullDown = true; canPullUp = true; } @Override public boolean dispatchTouchEvent(MotionEvent ev) { switch (()) { case MotionEvent.ACTION_DOWN: downY = (); lastY = downY; mEvents = 0; releasePull(); if (state != REFRESHING && state != LOADING) { isTouch = true; } break; case MotionEvent.ACTION_POINTER_DOWN: case MotionEvent.ACTION_POINTER_UP: // Filter multi-touch mEvents = -1; break; case MotionEvent.ACTION_MOVE: if (mEvents == 0) { if (pullDownY > 0 || (((Pullable) pullView).canPullDown() && canPullDown && state != LOADING && state != REFRESHING)) { // Can be pulled down, but cannot be pulled down when loading // Reduce the actual sliding distance, causing the feeling of pulling with force pullDownY = pullDownY + (() - lastY) / radio; if (pullDownY < 0) { pullDownY = 0; canPullDown = false; canPullUp = true; } if (pullDownY > getMeasuredHeight()) { pullDownY = getMeasuredHeight(); } if (state == REFRESHING) { // Touch to move while refreshing isTouch = false; } } else if (pullUpY < 0 || (((Pullable) pullView).canPullUp() && canPullUp && state != REFRESHING && state != LOADING)) { // Can be pulled up, but cannot be pulled up when refreshing pullUpY = pullUpY + (() - lastY) / radio; if (pullUpY > 0) { pullUpY = 0; canPullDown = true; canPullUp = false; } if (pullUpY < -getMeasuredHeight()) { pullUpY = -getMeasuredHeight(); } if (state == LOADING) { // Touch and move while loading isTouch = false; } } } if (isTouch) { lastY = (); if (pullDownY > 0 || pullUpY < 0) { requestLayout(); } if (pullDownY > 0) { if (pullDownY <= headBorder && (state == RELEASE_TO_REFRESH || state == DONE)) { // If the pull-down distance does not reach the refresh distance and the current state is releasing refresh, change the state to pull-down refresh state = INIT; refreshViewByState(); } if (pullDownY >= headBorder && state == INIT) { // If the pull-down distance reaches the refresh distance and the current state is the initial state refresh, change the state to release refresh state = RELEASE_TO_REFRESH; refreshViewByState(); } } else if (pullUpY < 0) { // The following is to judge the loading of pullup, the same as above, note that pullUpY is a negative value if (-pullUpY <= footBorder && (state == RELEASE_TO_LOAD || state == DONE)) { state = INIT; refreshViewByState(); } // Pull-up operation if (-pullUpY >= footBorder && state == INIT) { state = RELEASE_TO_LOAD; refreshViewByState(); } } // Because refresh and load operations cannot be performed at the same time, pullDownY and pullUpY will not be 0 at the same time, so here (pullDownY + // (pullUpY)) can not distinguish the current status if ((pullDownY + (pullUpY)) > 8) { // Prevent long press and click events from accidentally triggering during pull-down (MotionEvent.ACTION_CANCEL); } } break; case MotionEvent.ACTION_UP: if (pullDownY > headBorder || -pullUpY > footBorder) { // Pull down when refreshing (pull up when loading), and after release, pull down head (pull up head) will not be hidden isTouch = false; } if (state == RELEASE_TO_REFRESH) { state = REFRESHING; refreshViewByState(); // Refresh operation if (mListener != null) { canPullDown = false; pullDownY = headBorder; pullUpY = 0; requestLayout(); (rotateAnimation); (this); } } else if (state == RELEASE_TO_LOAD) { state = LOADING; refreshViewByState(); // Loading operation if (mListener != null) { canPullUp = false; pullDownY = 0; pullUpY = -footBorder; requestLayout(); (rotateAnimation); (this); } } else { pullDownY = 0; pullUpY = 0; requestLayout(); } default: break; } // Event distribution is handed over to the parent class (ev); return true; } public void hideHeadView() { (1); } public void hideFootView() { (2); } private void initView() { // Initialize the drop-down layout headIv = (ImageView) (.iv_head); headTv = (TextView) (.tv_head); //Initialize the pull-up layout footIv = (ImageView) (.iv_foot); footTv = (TextView) (.tv_foot); refreshViewByState(); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { if (!isLayout) { // This is the first time I come in to do some initialization headView = getChildAt(0); pullView = getChildAt(1); footView = getChildAt(2); headBorder = ((ViewGroup) headView).getChildAt(0).getMeasuredHeight(); footBorder = ((ViewGroup) footView).getChildAt(0).getMeasuredHeight(); headHeight = (); pullHeight = (); footHeight = (); pullWidth = (); initView(); isLayout = true; } // Change the layout of the subcontrol, use (pullDownY + pullUpY) as the offset, so that the current state can be distinguished without distinguishing offset = (int) (pullDownY + pullUpY); (0, -headHeight + offset, pullWidth, offset); (0, offset, pullWidth, pullHeight + offset); (0, pullHeight + offset, pullWidth, pullHeight + footHeight + offset); } public interface OnRefreshListener { void onRefresh(PullToRefreshLayout pullToRefreshLayout); void onLoadMore(PullToRefreshLayout pullToRefreshLayout); } }
3. Custom View
ListView
public class PullableListView extends ListView implements Pullable { public PullableListView(Context context) { super(context); } public PullableListView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { if (getCount() == 0) { // When there is no item, you can also pull down and refresh return false; } else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) { // Slide to the top of the ListView return true; } else return false; } @Override public boolean canPullUp() { if (getCount() == 0) { // You can also load when there is no item return false; } else if (getLastVisiblePosition() == (getCount() - 1)) { // Slide to the bottom if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null && getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) .getBottom() <= getMeasuredHeight()) return true; } return false; } }
GridView
public class PullableGridView extends GridView implements Pullable { public PullableGridView(Context context) { super(context); } public PullableGridView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableGridView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { if (getCount() == 0) { // When there is no item, you can also pull down and refresh return false; } else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) { // Slide to the top return true; } else return false; } @Override public boolean canPullUp() { if (getCount() == 0) { // You can also load when there is no item return false; } else if (getLastVisiblePosition() == (getCount() - 1)) { // Slide to the bottom if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null && getChildAt( getLastVisiblePosition() - getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()) return true; } return false; } }
RecyclerView
public class PullableRecyclerView extends RecyclerView implements Pullable { public PullableRecyclerView(Context context) { super(context); } public PullableRecyclerView(Context context, @Nullable AttributeSet attrs) { super(context, attrs); } public PullableRecyclerView(Context context, @Nullable AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { layoutManager = getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; if (() == 0) { return false; } else if (() == 0 && (0).getTop() >= 0) { return true; } else { return false; } } else if (layoutManager instanceof StaggeredGridLayoutManager) { StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager; if (() == 0) { return false; } else { int[] firstVisibleItems = null; firstVisibleItems = (firstVisibleItems); if (firstVisibleItems != null && > 0) { if (() + firstVisibleItems[0] == ()) { return true; } } } } return false; } @Override public boolean canPullUp() { layoutManager = getLayoutManager(); if (layoutManager instanceof LinearLayoutManager) { LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager; if (() == 0) { return false; } else if (() == (() - 1)) { if ((() - ()) != null && (() - ()).getBottom() <= getMeasuredHeight()) { return true; } } } else if (layoutManager instanceof StaggeredGridLayoutManager) { StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager; if (() == 0) { return false; } else { int[] lastPositions = new int[()]; lastPositions = (lastPositions); if (findMax(lastPositions) >= () - 1) { return true; } } } return false; } private int findMax(int[] lastPositions) { int max = lastPositions[0]; for (int value : lastPositions) { if (value > max) { max = value; } } return max; } }
ExpandableListView
public class PullableExpandableListView extends ExpandableListView implements Pullable { public PullableExpandableListView(Context context) { super(context); } public PullableExpandableListView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableExpandableListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { if (getCount() == 0) { // When there is no item, you can also pull down and refresh return false; } else if (getFirstVisiblePosition() == 0 && getChildAt(0).getTop() >= 0) { // Slide to the top return true; } else return false; } @Override public boolean canPullUp() { if (getCount() == 0) { // You can also load when there is no item return false; } else if (getLastVisiblePosition() == (getCount() - 1)) { // Slide to the bottom if (getChildAt(getLastVisiblePosition() - getFirstVisiblePosition()) != null && getChildAt( getLastVisiblePosition() - getFirstVisiblePosition()).getBottom() <= getMeasuredHeight()) return true; } return false; } }
ScrollView
public class PullableScrollView extends ScrollView implements Pullable { public PullableScrollView(Context context) { super(context); } public PullableScrollView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableScrollView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { if (getScrollY() == 0) return true; else return false; } @Override public boolean canPullUp() { if (getScrollY() >= (getChildAt(0).getHeight() - getMeasuredHeight())) return true; else return false; } }
WebView
public class PullableWebView extends WebView implements Pullable { public PullableWebView(Context context) { super(context); } public PullableWebView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableWebView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { if (getScrollY() == 0) return true; else return false; } @Override public boolean canPullUp() { if (getScrollY() >= getContentHeight() * getScale() - getMeasuredHeight()) return true; else return false; } }
ImageView
public class PullableImageView extends ImageView implements Pullable { public PullableImageView(Context context) { super(context); } public PullableImageView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { return true; } @Override public boolean canPullUp() { return true; } }
TextView
public class PullableTextView extends TextView implements Pullable { public PullableTextView(Context context) { super(context); } public PullableTextView(Context context, AttributeSet attrs) { super(context, attrs); } public PullableTextView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); } @Override public boolean canPullDown() { return true; } @Override public boolean canPullUp() { return true; } }
4. Use example (taking ListView as an example)
< android: android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/head" /> < android: android:layout_width="match_parent" android:layout_height="match_parent" /> <include layout="@layout/foot" /> </>
head
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:andro android: android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/darker_gray"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:paddingBottom="20dp" android:paddingTop="20dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"> <ImageView android: android:layout_width="20dp" android:layout_height="20dp" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:scaleType="fitXY" /> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="@android:color/white" android:textSize="16sp" /> </RelativeLayout> </RelativeLayout> </RelativeLayout>
foot
<?xml version="1.0" encoding="UTF-8"?> <RelativeLayout xmlns:andro android: android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/darker_gray"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:paddingBottom="20dp" android:paddingTop="20dp"> <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_centerInParent="true"> <ImageView android: android:layout_width="20dp" android:layout_height="20dp" android:layout_centerVertical="true" android:layout_marginLeft="60dp" android:scaleType="fitXY" /> <TextView android: android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerInParent="true" android:textColor="@android:color/white" android:textSize="16sp" /> </RelativeLayout> </RelativeLayout> </RelativeLayout>
4. Pay attention
There is no difference between custom View and normal View usage
To implement refresh loading, you must make (onRefreshListener);
The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.