Drop-down refresh in development is a common need that can no longer be perceived. There are also many excellent third-party frameworks on the Internet. However, there was a project that required a refreshed layout to appear from below rather than above, because no suitable third-party library was found on the Internet, so I wrote a demo myself, and share it with you here.
First of all, we will talk about how to realize it.
- We need a head and body that are superimposed by default.
- Gets the two View s and the maximum sliding range is the height of the head.
- Set sliding event monitoring for the body, change the height of the body, and judge whether it is refreshed when lifted.
- Provide an aspect that can dynamically change whether drop-down refresh.
The most troublesome thing is whether the dynamic change is visible or not, because to resolve the conflict of events, not every finger slide represents the user's desire to refresh the data. This is very well solved in ListView. It only needs to judge whether the displayed item is the first one, but in actual demand, it may only be a common layout that needs refreshing, and here we can not know whether the slide to. Is the following data displayed or refreshed? Here I use ViewDrag Helper to solve this problem.
Effect Realization and ViewDragHelper Usage
Step 1: Write a class that inherits FrameLayout to superimpose the head and body.
public class Luffy extends FrameLayout
Then get the head and body and their height.
@Override
protected void onFinishInflate() {
if(getChildCount() != 2)
throw new IllegalStateException("There are only two sons. View");
mContentView = getChildAt(1);
}
------------------------------------------------------------
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
mHeight = getMeasuredHeight();
mMaxDrag = (int) (mHeight * 0.2);
}
onFinishInflate is called after the layout file is loaded. We can get subclasses here. onSizeChanged calls back after the measurement. Here we get the height and set the maximum drag range.
Step 2: Create a ViewDragHelper object, which receives two parameters, ViewGroup and Callback. Note that Callback is the key class for our effect. Hand over touch events and interception events to ViewDragHelper.
ViewDragHelper.create(this, new RefurbishCallBack());
-------------------------------------------------------------
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
-------------------------------------------------------------
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true; // Return true to trigger subsequent events.
}
Callback maintains an abstract method, tryCaptureView, whose return value determines whether or not we trigger drag events. Here we trigger drag events on two conditions: Touch View for Content and isRefurbish for true. When we touch View as a body and isRefurbish for true, we allow refreshing other situations without triggering.
/**
* ViewDragHelper Callback method
*/
private class RefurbishCallBack extends ViewDragHelper.Callback{
// Capture view
@Override
public boolean tryCaptureView(View child, int pointerId) {
if(child == mContentView && isRefurbish){
return true;
}
return isRefurbish;
}
// Restrict view Mobility
// Here we rewrite the clampViewPositionVertical method, which is called when we slide vertically.
// And return the touch View and move size
@Override
public int clampViewPositionVertical(View child, int top, int dy) {
top = (int) (top * 0.93f); // Damping coefficient
if(child == mContentView){
if(top < 0) top = 0;
}
return top;
}
// Release view callback, i.e. raise your hand
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if(releasedChild != mContentView) return;
// The callback method is called to determine whether the maximum drag range is reached or not.
if(mContentView.getTop() >= mMaxDrag){
onRefurbishListener.onRefurbish();
scrollDown();
}else {
scrollUp();
}
}
// This method is important. When the child view also needs events, rewrite the method and return positive numbers. What I return here is the trigger point.
@Override
public int getViewVerticalDragRange(View child) {
return mMaxDrag;
}
}
This is where the core code is written. Finally, it provides a way to change the isRefurbish value to achieve dynamic refresh.
public void isRefurbish(boolean isRefurbish){
this.isRefurbish = isRefurbish;
}
Here's the code in Activity
luffy.setOnRefurbishListener(new RefurbishLayout.OnRefurbishListener() {
@Override
public void onRefurbish() {
//Load data... call method to hide header after completion
refurbishLayout.setRefurbish(true);
}
};
--------------------------------------------------
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// Determine switch refresh based on whether the first entry is visible.
refurbishLayout.isRefurbish(firstVisibleItem == 0);
}