Clean up View Recycling
Summary: Followups to View Recycling diffs to improve things / clean up things a bit. This also fixes memory warnings which were not hooked up before. Changelog: [Internal] Reviewed By: mdvacca Differential Revision: D36707792 fbshipit-source-id: 410e70bf0eeec5569566138af547e1601394d0e6
This commit is contained in:
Родитель
bffad4351c
Коммит
a68dca3c46
|
@ -166,6 +166,7 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||||
@NonNull private final MountingManager mMountingManager;
|
@NonNull private final MountingManager mMountingManager;
|
||||||
@NonNull private final EventDispatcher mEventDispatcher;
|
@NonNull private final EventDispatcher mEventDispatcher;
|
||||||
@NonNull private final MountItemDispatcher mMountItemDispatcher;
|
@NonNull private final MountItemDispatcher mMountItemDispatcher;
|
||||||
|
@NonNull private final ViewManagerRegistry mViewManagerRegistry;
|
||||||
|
|
||||||
@NonNull private final EventBeatManager mEventBeatManager;
|
@NonNull private final EventBeatManager mEventBeatManager;
|
||||||
|
|
||||||
|
@ -226,6 +227,9 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||||
mShouldDeallocateEventDispatcher = false;
|
mShouldDeallocateEventDispatcher = false;
|
||||||
mEventBeatManager = eventBeatManager;
|
mEventBeatManager = eventBeatManager;
|
||||||
mReactApplicationContext.addLifecycleEventListener(this);
|
mReactApplicationContext.addLifecycleEventListener(this);
|
||||||
|
|
||||||
|
mViewManagerRegistry = viewManagerRegistry;
|
||||||
|
mReactApplicationContext.registerComponentCallbacks(viewManagerRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FabricUIManager(
|
public FabricUIManager(
|
||||||
|
@ -244,6 +248,9 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||||
mShouldDeallocateEventDispatcher = true;
|
mShouldDeallocateEventDispatcher = true;
|
||||||
mEventBeatManager = eventBeatManager;
|
mEventBeatManager = eventBeatManager;
|
||||||
mReactApplicationContext.addLifecycleEventListener(this);
|
mReactApplicationContext.addLifecycleEventListener(this);
|
||||||
|
|
||||||
|
mViewManagerRegistry = viewManagerRegistry;
|
||||||
|
mReactApplicationContext.registerComponentCallbacks(viewManagerRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO (T47819352): Rename this to startSurface for consistency with xplat/iOS
|
// TODO (T47819352): Rename this to startSurface for consistency with xplat/iOS
|
||||||
|
@ -451,6 +458,8 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
||||||
mEventDispatcher.removeBatchEventDispatchedListener(mEventBeatManager);
|
mEventDispatcher.removeBatchEventDispatchedListener(mEventBeatManager);
|
||||||
mEventDispatcher.unregisterEventEmitter(FABRIC);
|
mEventDispatcher.unregisterEventEmitter(FABRIC);
|
||||||
|
|
||||||
|
mReactApplicationContext.unregisterComponentCallbacks(mViewManagerRegistry);
|
||||||
|
|
||||||
// Remove lifecycle listeners (onHostResume, onHostPause) since the FabricUIManager is going
|
// Remove lifecycle listeners (onHostResume, onHostPause) since the FabricUIManager is going
|
||||||
// away. Then stop the mDispatchUIFrameCallback false will cause the choreographer
|
// away. Then stop the mDispatchUIFrameCallback false will cause the choreographer
|
||||||
// callbacks to stop firing.
|
// callbacks to stop firing.
|
||||||
|
|
|
@ -105,6 +105,36 @@ public abstract class BaseViewManager<T extends View, C extends LayoutShadowNode
|
||||||
view.setOutlineAmbientShadowColor(Color.BLACK);
|
view.setOutlineAmbientShadowColor(Color.BLACK);
|
||||||
view.setOutlineSpotShadowColor(Color.BLACK);
|
view.setOutlineSpotShadowColor(Color.BLACK);
|
||||||
|
|
||||||
|
// Focus IDs
|
||||||
|
// Also see in AOSP source:
|
||||||
|
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#4493
|
||||||
|
view.setNextFocusDownId(View.NO_ID);
|
||||||
|
view.setNextFocusForwardId(View.NO_ID);
|
||||||
|
view.setNextFocusRightId(View.NO_ID);
|
||||||
|
view.setNextFocusUpId(View.NO_ID);
|
||||||
|
|
||||||
|
// This is possibly subject to change and overrideable per-platform, but these
|
||||||
|
// are the default view flags in View.java:
|
||||||
|
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#2712
|
||||||
|
// `mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | LAYOUT_DIRECTION_INHERIT`
|
||||||
|
// Therefore we set the following options as such:
|
||||||
|
view.setFocusable(false);
|
||||||
|
view.setFocusableInTouchMode(false);
|
||||||
|
|
||||||
|
// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r96/core/java/android/view/View.java#5491
|
||||||
|
view.setElevation(0);
|
||||||
|
|
||||||
|
// Predictably, alpha defaults to 1:
|
||||||
|
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#2186
|
||||||
|
// This accounts for resetting mBackfaceOpacity and mBackfaceVisibility
|
||||||
|
view.setAlpha(1);
|
||||||
|
|
||||||
|
// setPadding is a noop for most View types, but it is not for Text
|
||||||
|
setPadding(view, 0, 0, 0, 0);
|
||||||
|
|
||||||
|
// Other stuff
|
||||||
|
view.setForeground(null);
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -207,6 +207,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||||
@Override
|
@Override
|
||||||
public void initialize() {
|
public void initialize() {
|
||||||
getReactApplicationContext().registerComponentCallbacks(mMemoryTrimCallback);
|
getReactApplicationContext().registerComponentCallbacks(mMemoryTrimCallback);
|
||||||
|
getReactApplicationContext().registerComponentCallbacks(mViewManagerRegistry);
|
||||||
mEventDispatcher.registerEventEmitter(
|
mEventDispatcher.registerEventEmitter(
|
||||||
DEFAULT, getReactApplicationContext().getJSModule(RCTEventEmitter.class));
|
DEFAULT, getReactApplicationContext().getJSModule(RCTEventEmitter.class));
|
||||||
}
|
}
|
||||||
|
@ -234,6 +235,7 @@ public class UIManagerModule extends ReactContextBaseJavaModule
|
||||||
|
|
||||||
ReactApplicationContext reactApplicationContext = getReactApplicationContext();
|
ReactApplicationContext reactApplicationContext = getReactApplicationContext();
|
||||||
reactApplicationContext.unregisterComponentCallbacks(mMemoryTrimCallback);
|
reactApplicationContext.unregisterComponentCallbacks(mMemoryTrimCallback);
|
||||||
|
reactApplicationContext.unregisterComponentCallbacks(mViewManagerRegistry);
|
||||||
YogaNodePool.get().clear();
|
YogaNodePool.get().clear();
|
||||||
ViewManagerPropertyUpdater.clear();
|
ViewManagerPropertyUpdater.clear();
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,15 +41,23 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||||
* null signals that View Recycling is disabled. `enableViewRecycling` must be explicitly called
|
* null signals that View Recycling is disabled. `enableViewRecycling` must be explicitly called
|
||||||
* in a concrete constructor to enable View Recycling per ViewManager.
|
* in a concrete constructor to enable View Recycling per ViewManager.
|
||||||
*/
|
*/
|
||||||
private HashMap<Integer, Stack<T>> mRecyclableViews = null;
|
@Nullable private HashMap<Integer, Stack<T>> mRecyclableViews = null;
|
||||||
|
|
||||||
|
private int mRecyclableViewsBufferSize = 1024;
|
||||||
|
|
||||||
/** Call in constructor of concrete ViewManager class to enable. */
|
/** Call in constructor of concrete ViewManager class to enable. */
|
||||||
protected void enableViewRecycling() {
|
protected void setupViewRecycling() {
|
||||||
if (ReactFeatureFlags.enableViewRecycling) {
|
if (ReactFeatureFlags.enableViewRecycling) {
|
||||||
mRecyclableViews = new HashMap<>();
|
mRecyclableViews = new HashMap<>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Call in constructor of concrete ViewManager class to enable. */
|
||||||
|
protected void setupViewRecycling(int bufferSize) {
|
||||||
|
mRecyclableViewsBufferSize = bufferSize;
|
||||||
|
setupViewRecycling();
|
||||||
|
}
|
||||||
|
|
||||||
private @Nullable Stack<T> getRecyclableViewStack(int surfaceId) {
|
private @Nullable Stack<T> getRecyclableViewStack(int surfaceId) {
|
||||||
if (mRecyclableViews == null) {
|
if (mRecyclableViews == null) {
|
||||||
return null;
|
return null;
|
||||||
|
@ -191,12 +199,16 @@ public abstract class ViewManager<T extends View, C extends ReactShadowNode>
|
||||||
* {@link ViewManager} subclass.
|
* {@link ViewManager} subclass.
|
||||||
*/
|
*/
|
||||||
public void onDropViewInstance(@NonNull T view) {
|
public void onDropViewInstance(@NonNull T view) {
|
||||||
@Nullable
|
// View recycling
|
||||||
Stack<T> recyclableViews =
|
ThemedReactContext themedReactContext = (ThemedReactContext) view.getContext();
|
||||||
getRecyclableViewStack(((ThemedReactContext) view.getContext()).getSurfaceId());
|
int surfaceId = themedReactContext.getSurfaceId();
|
||||||
// By default we treat views as recyclable
|
@Nullable Stack<T> recyclableViews = getRecyclableViewStack(surfaceId);
|
||||||
if (recyclableViews != null) {
|
|
||||||
recyclableViews.push(prepareToRecycleView((ThemedReactContext) view.getContext(), view));
|
// Any max buffer size <0 results in an infinite buffer size
|
||||||
|
if (recyclableViews != null
|
||||||
|
&& (mRecyclableViewsBufferSize < 0
|
||||||
|
|| recyclableViews.size() < mRecyclableViewsBufferSize)) {
|
||||||
|
recyclableViews.push(prepareToRecycleView(themedReactContext, view));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,11 +19,10 @@ import java.util.Map;
|
||||||
* Class that stores the mapping between native view name used in JS and the corresponding instance
|
* Class that stores the mapping between native view name used in JS and the corresponding instance
|
||||||
* of {@link ViewManager}.
|
* of {@link ViewManager}.
|
||||||
*/
|
*/
|
||||||
public final class ViewManagerRegistry {
|
public final class ViewManagerRegistry implements ComponentCallbacks2 {
|
||||||
|
|
||||||
private final Map<String, ViewManager> mViewManagers;
|
private final Map<String, ViewManager> mViewManagers;
|
||||||
private final @Nullable ViewManagerResolver mViewManagerResolver;
|
private final @Nullable ViewManagerResolver mViewManagerResolver;
|
||||||
private final MemoryTrimCallback mMemoryTrimCallback = new MemoryTrimCallback();
|
|
||||||
|
|
||||||
public ViewManagerRegistry(ViewManagerResolver viewManagerResolver) {
|
public ViewManagerRegistry(ViewManagerResolver viewManagerResolver) {
|
||||||
mViewManagers = MapBuilder.newHashMap();
|
mViewManagers = MapBuilder.newHashMap();
|
||||||
|
@ -46,40 +45,6 @@ public final class ViewManagerRegistry {
|
||||||
mViewManagerResolver = null;
|
mViewManagerResolver = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Trim View Recycling memory aggressively. Whenever the system is running even slightly low on
|
|
||||||
* memory or is backgrounded, we immediately flush all recyclable Views. GC and memory swaps cause
|
|
||||||
* intense CPU pressure, so we always favor low memory usage over View recycling, even if there is
|
|
||||||
* only "moderate" pressure.
|
|
||||||
*/
|
|
||||||
private class MemoryTrimCallback implements ComponentCallbacks2 {
|
|
||||||
@Override
|
|
||||||
public void onTrimMemory(int level) {
|
|
||||||
Runnable runnable =
|
|
||||||
new Runnable() {
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
for (Map.Entry<String, ViewManager> entry : mViewManagers.entrySet()) {
|
|
||||||
entry.getValue().trimMemory();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (UiThreadUtil.isOnUiThread()) {
|
|
||||||
runnable.run();
|
|
||||||
} else {
|
|
||||||
UiThreadUtil.runOnUiThread(runnable);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onConfigurationChanged(Configuration newConfig) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onLowMemory() {
|
|
||||||
this.onTrimMemory(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param className {@link String} that identifies the {@link ViewManager} inside the {@link
|
* @param className {@link String} that identifies the {@link ViewManager} inside the {@link
|
||||||
* ViewManagerRegistry}. This methods {@throws IllegalViewOperationException} if there is no
|
* ViewManagerRegistry}. This methods {@throws IllegalViewOperationException} if there is no
|
||||||
|
@ -147,4 +112,33 @@ public final class ViewManagerRegistry {
|
||||||
UiThreadUtil.runOnUiThread(runnable);
|
UiThreadUtil.runOnUiThread(runnable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** ComponentCallbacks2 method. */
|
||||||
|
@Override
|
||||||
|
public void onTrimMemory(int level) {
|
||||||
|
Runnable runnable =
|
||||||
|
new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
for (Map.Entry<String, ViewManager> entry : mViewManagers.entrySet()) {
|
||||||
|
entry.getValue().trimMemory();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (UiThreadUtil.isOnUiThread()) {
|
||||||
|
runnable.run();
|
||||||
|
} else {
|
||||||
|
UiThreadUtil.runOnUiThread(runnable);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ComponentCallbacks2 method. */
|
||||||
|
@Override
|
||||||
|
public void onConfigurationChanged(Configuration newConfig) {}
|
||||||
|
|
||||||
|
/** ComponentCallbacks2 method. */
|
||||||
|
@Override
|
||||||
|
public void onLowMemory() {
|
||||||
|
this.onTrimMemory(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -96,16 +96,18 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
|
||||||
mSpanned = null;
|
mSpanned = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* package */ void recycleView(ReactTextView defaultView) {
|
/* package */ void recycleView() {
|
||||||
// Set default field values
|
// Set default field values
|
||||||
initView();
|
initView();
|
||||||
|
|
||||||
setForeground(null);
|
// Defaults for these fields:
|
||||||
|
// https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/widget/TextView.java#L1061
|
||||||
|
setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE);
|
||||||
|
setMovementMethod(getDefaultMovementMethod());
|
||||||
|
setJustificationMode(Layout.JUSTIFICATION_MODE_NONE);
|
||||||
|
|
||||||
// reset text
|
// reset text
|
||||||
setLayoutParams(EMPTY_LAYOUT_PARAMS);
|
setLayoutParams(EMPTY_LAYOUT_PARAMS);
|
||||||
setMovementMethod(defaultView.getMovementMethod());
|
|
||||||
setBreakStrategy(defaultView.getBreakStrategy());
|
|
||||||
super.setText(null);
|
super.setText(null);
|
||||||
|
|
||||||
// Call setters to ensure that any super setters are called
|
// Call setters to ensure that any super setters are called
|
||||||
|
@ -124,21 +126,8 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
|
||||||
// reset data detectors
|
// reset data detectors
|
||||||
setLinkifyMask(0);
|
setLinkifyMask(0);
|
||||||
|
|
||||||
setJustificationMode(defaultView.getJustificationMode());
|
|
||||||
|
|
||||||
setEllipsizeLocation(mEllipsizeLocation);
|
setEllipsizeLocation(mEllipsizeLocation);
|
||||||
|
|
||||||
// Focus IDs
|
|
||||||
// Also see in AOSP source:
|
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#4493
|
|
||||||
setNextFocusDownId(View.NO_ID);
|
|
||||||
setNextFocusForwardId(View.NO_ID);
|
|
||||||
setNextFocusRightId(View.NO_ID);
|
|
||||||
setNextFocusUpId(View.NO_ID);
|
|
||||||
|
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r96/core/java/android/view/View.java#5491
|
|
||||||
setElevation(0);
|
|
||||||
|
|
||||||
// View flags - defaults are here:
|
// View flags - defaults are here:
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/98e54bb941cb6feb07127b75da37833281951d52/core/java/android/view/View.java#5311
|
// https://android.googlesource.com/platform/frameworks/base/+/98e54bb941cb6feb07127b75da37833281951d52/core/java/android/view/View.java#5311
|
||||||
// mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED |
|
// mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED |
|
||||||
|
@ -146,8 +135,7 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
|
||||||
setEnabled(true);
|
setEnabled(true);
|
||||||
setFocusable(View.FOCUSABLE_AUTO);
|
setFocusable(View.FOCUSABLE_AUTO);
|
||||||
|
|
||||||
// Things that could be set as a result of updateText/setText
|
setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE);
|
||||||
setPadding(0, 0, 0, 0);
|
|
||||||
|
|
||||||
updateView(); // call after changing ellipsizeLocation in particular
|
updateView(); // call after changing ellipsizeLocation in particular
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,33 +45,25 @@ public class ReactTextViewManager
|
||||||
|
|
||||||
@VisibleForTesting public static final String REACT_CLASS = "RCTText";
|
@VisibleForTesting public static final String REACT_CLASS = "RCTText";
|
||||||
|
|
||||||
private ReactTextView mDefaultViewForRecycling = null;
|
|
||||||
|
|
||||||
protected @Nullable ReactTextViewManagerCallback mReactTextViewManagerCallback;
|
protected @Nullable ReactTextViewManagerCallback mReactTextViewManagerCallback;
|
||||||
|
|
||||||
public ReactTextViewManager() {
|
public ReactTextViewManager() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
enableViewRecycling();
|
setupViewRecycling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ReactTextView prepareToRecycleView(
|
protected ReactTextView prepareToRecycleView(
|
||||||
@NonNull ThemedReactContext reactContext, ReactTextView view) {
|
@NonNull ThemedReactContext reactContext, ReactTextView view) {
|
||||||
// TODO: use context as key
|
|
||||||
if (mDefaultViewForRecycling == null) {
|
|
||||||
mDefaultViewForRecycling = createViewInstance(reactContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BaseViewManager
|
// BaseViewManager
|
||||||
super.prepareToRecycleView(reactContext, view);
|
super.prepareToRecycleView(reactContext, view);
|
||||||
|
|
||||||
// Resets background and borders
|
// Resets background and borders
|
||||||
view.recycleView(mDefaultViewForRecycling);
|
view.recycleView();
|
||||||
|
|
||||||
// Defaults from ReactTextAnchorViewManager
|
// Defaults from ReactTextAnchorViewManager
|
||||||
setSelectionColor(view, null);
|
setSelectionColor(view, null);
|
||||||
setAndroidHyphenationFrequency(view, null);
|
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
|
@ -176,32 +176,6 @@ public class ReactViewGroup extends ViewGroup
|
||||||
// Reset background, borders
|
// Reset background, borders
|
||||||
updateBackgroundDrawable(null);
|
updateBackgroundDrawable(null);
|
||||||
|
|
||||||
setForeground(null);
|
|
||||||
|
|
||||||
// This is possibly subject to change and overrideable per-platform, but these
|
|
||||||
// are the default view flags in View.java:
|
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#2712
|
|
||||||
// `mViewFlags = SOUND_EFFECTS_ENABLED | HAPTIC_FEEDBACK_ENABLED | LAYOUT_DIRECTION_INHERIT`
|
|
||||||
// Therefore we set the following options as such:
|
|
||||||
setFocusable(false);
|
|
||||||
setFocusableInTouchMode(false);
|
|
||||||
|
|
||||||
// Focus IDs
|
|
||||||
// Also see in AOSP source:
|
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#4493
|
|
||||||
setNextFocusDownId(View.NO_ID);
|
|
||||||
setNextFocusForwardId(View.NO_ID);
|
|
||||||
setNextFocusRightId(View.NO_ID);
|
|
||||||
setNextFocusUpId(View.NO_ID);
|
|
||||||
|
|
||||||
// Predictable, alpha defaults to 1:
|
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/a175a5b/core/java/android/view/View.java#2186
|
|
||||||
// This accounts for resetting mBackfaceOpacity and mBackfaceVisibility
|
|
||||||
setAlpha(1);
|
|
||||||
|
|
||||||
// https://android.googlesource.com/platform/frameworks/base/+/refs/tags/android-mainline-12.0.0_r96/core/java/android/view/View.java#5491
|
|
||||||
setElevation(0);
|
|
||||||
|
|
||||||
resetPointerEvents();
|
resetPointerEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -813,11 +787,6 @@ public class ReactViewGroup extends ViewGroup
|
||||||
mOverflowInset.set(left, top, right, bottom);
|
mOverflowInset.set(left, top, right, bottom);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setOverflowInset(Rect overflowInset) {
|
|
||||||
mOverflowInset.set(
|
|
||||||
overflowInset.left, overflowInset.top, overflowInset.right, overflowInset.bottom);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Rect getOverflowInset() {
|
public Rect getOverflowInset() {
|
||||||
return mOverflowInset;
|
return mOverflowInset;
|
||||||
|
|
|
@ -52,12 +52,10 @@ public class ReactViewManager extends ReactClippingViewManager<ReactViewGroup> {
|
||||||
private static final int CMD_SET_PRESSED = 2;
|
private static final int CMD_SET_PRESSED = 2;
|
||||||
private static final String HOTSPOT_UPDATE_KEY = "hotspotUpdate";
|
private static final String HOTSPOT_UPDATE_KEY = "hotspotUpdate";
|
||||||
|
|
||||||
private ReactViewGroup mDefaultViewForRecycling = null;
|
|
||||||
|
|
||||||
public ReactViewManager() {
|
public ReactViewManager() {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
enableViewRecycling();
|
setupViewRecycling();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
Загрузка…
Ссылка в новой задаче