mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-09 22:43:10 +08:00
Fix RefreshControl race condition
Summary: Improved version of #7317. `setRefreshing` and `setProgressViewOffset` needs to be called after the view has been layed out. Instead of using `post` to do that we update the `refreshing` and `progressViewOffset` values in the first call to `onLayout`. I also noticed that `progressViewOffset` default value wasn't exactly the same as when not calling `setProgressViewOffset` at all. Tweaked the values to match android defaults. **Test plan (required)** Make sure the integration test passes, In UIExplorer: test RefreshControl with `refreshing = true` initially, test `progressViewOffset`. Closes https://github.com/facebook/react-native/pull/7683 Differential Revision: D3334426 fbshipit-source-id: ddd63a5e9a6afe2b8b7fe6a25e875a40f4e888c6
This commit is contained in:
committed by
Facebook Github Bot 9
parent
69bf0bd8c1
commit
bb5aede6e3
@@ -14,16 +14,63 @@ import android.view.MotionEvent;
|
||||
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.uimanager.events.NativeGestureUtil;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
|
||||
/**
|
||||
* Basic extension of {@link SwipeRefreshLayout} with ReactNative-specific functionality.
|
||||
*/
|
||||
public class ReactSwipeRefreshLayout extends SwipeRefreshLayout {
|
||||
|
||||
private static final float DEFAULT_CIRCLE_TARGET = 64;
|
||||
|
||||
private boolean mDidLayout = false;
|
||||
|
||||
private boolean mRefreshing = false;
|
||||
private float mProgressViewOffset = 0;
|
||||
|
||||
|
||||
public ReactSwipeRefreshLayout(ReactContext reactContext) {
|
||||
super(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRefreshing(boolean refreshing) {
|
||||
mRefreshing = refreshing;
|
||||
|
||||
// `setRefreshing` must be called after the initial layout otherwise it
|
||||
// doesn't work when mounting the component with `refreshing = true`.
|
||||
// Known Android issue: https://code.google.com/p/android/issues/detail?id=77712
|
||||
if (mDidLayout) {
|
||||
super.setRefreshing(refreshing);
|
||||
}
|
||||
}
|
||||
|
||||
public void setProgressViewOffset(float offset) {
|
||||
mProgressViewOffset = offset;
|
||||
|
||||
// The view must be measured before calling `getProgressCircleDiameter` so
|
||||
// don't do it before the initial layout.
|
||||
if (mDidLayout) {
|
||||
int diameter = getProgressCircleDiameter();
|
||||
int start = Math.round(PixelUtil.toPixelFromDIP(offset)) - diameter;
|
||||
int end = Math.round(PixelUtil.toPixelFromDIP(offset + DEFAULT_CIRCLE_TARGET) - diameter);
|
||||
setProgressViewOffset(false, start, end);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
|
||||
if (!mDidLayout) {
|
||||
mDidLayout = true;
|
||||
|
||||
// Update values that must be set after initial layout.
|
||||
setProgressViewOffset(mProgressViewOffset);
|
||||
setRefreshing(mRefreshing);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
if (super.onInterceptTouchEvent(ev)) {
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.support.v4.widget.SwipeRefreshLayout.OnRefreshListener;
|
||||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.common.SystemClock;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
@@ -33,8 +32,6 @@ import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
*/
|
||||
public class SwipeRefreshLayoutManager extends ViewGroupManager<ReactSwipeRefreshLayout> {
|
||||
|
||||
public static final float REFRESH_TRIGGER_DISTANCE = 48;
|
||||
|
||||
@Override
|
||||
protected ReactSwipeRefreshLayout createViewInstance(ThemedReactContext reactContext) {
|
||||
return new ReactSwipeRefreshLayout(reactContext);
|
||||
@@ -74,30 +71,13 @@ public class SwipeRefreshLayoutManager extends ViewGroupManager<ReactSwipeRefres
|
||||
}
|
||||
|
||||
@ReactProp(name = "refreshing")
|
||||
public void setRefreshing(final ReactSwipeRefreshLayout view, final boolean refreshing) {
|
||||
// Use `post` otherwise the control won't start refreshing if refreshing is true when
|
||||
// the component gets mounted.
|
||||
view.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
view.setRefreshing(refreshing);
|
||||
}
|
||||
});
|
||||
public void setRefreshing(ReactSwipeRefreshLayout view, boolean refreshing) {
|
||||
view.setRefreshing(refreshing);
|
||||
}
|
||||
|
||||
@ReactProp(name = "progressViewOffset", defaultFloat = 0)
|
||||
public void setProgressViewOffset(final ReactSwipeRefreshLayout view, final float offset) {
|
||||
// Use `post` to get progress circle diameter properly
|
||||
// Otherwise returns 0
|
||||
view.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
int diameter = view.getProgressCircleDiameter();
|
||||
int start = Math.round(PixelUtil.toPixelFromDIP(offset)) - diameter;
|
||||
int end = Math.round(PixelUtil.toPixelFromDIP(offset + REFRESH_TRIGGER_DISTANCE));
|
||||
view.setProgressViewOffset(false, start, end);
|
||||
}
|
||||
});
|
||||
view.setProgressViewOffset(offset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user