mirror of
https://github.com/status-im/react-native.git
synced 2025-01-27 17:54:48 +00:00
Open source Modal
Summary: This open sources an internal Modal View Reviewed By: mkonicek Differential Revision: D3065229 fb-gh-sync-id: 763996aef375883d94f70e617bfc7835a9cecb6f shipit-source-id: 763996aef375883d94f70e617bfc7835a9cecb6f
This commit is contained in:
parent
c76523f1ad
commit
db7a154360
@ -19,7 +19,7 @@ var React = require('react-native');
|
||||
var {
|
||||
Modal,
|
||||
StyleSheet,
|
||||
SwitchIOS,
|
||||
Switch,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
View,
|
||||
@ -96,7 +96,9 @@ var ModalExample = React.createClass({
|
||||
<Modal
|
||||
animated={this.state.animated}
|
||||
transparent={this.state.transparent}
|
||||
visible={this.state.modalVisible}>
|
||||
visible={this.state.modalVisible}
|
||||
onRequestClose={() => {this._setModalVisible(false)}}
|
||||
>
|
||||
<View style={[styles.container, modalBackgroundStyle]}>
|
||||
<View style={[styles.innerContainer, innerContainerTransparentStyle]}>
|
||||
<Text>This modal was presented {this.state.animated ? 'with' : 'without'} animation.</Text>
|
||||
@ -111,12 +113,12 @@ var ModalExample = React.createClass({
|
||||
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.rowTitle}>Animated</Text>
|
||||
<SwitchIOS value={this.state.animated} onValueChange={this._toggleAnimated} />
|
||||
<Switch value={this.state.animated} onValueChange={this._toggleAnimated} />
|
||||
</View>
|
||||
|
||||
<View style={styles.row}>
|
||||
<Text style={styles.rowTitle}>Transparent</Text>
|
||||
<SwitchIOS value={this.state.transparent} onValueChange={this._toggleTransparent} />
|
||||
<Switch value={this.state.transparent} onValueChange={this._toggleTransparent} />
|
||||
</View>
|
||||
|
||||
<Button onPress={this._setModalVisible.bind(this, true)}>
|
||||
|
@ -31,6 +31,10 @@ var ComponentExamples: Array<UIExplorerExample> = [
|
||||
key: 'ListViewExample',
|
||||
module: require('./ListViewExample'),
|
||||
},
|
||||
{
|
||||
key: 'ModalExample',
|
||||
module: require('./ModalExample'),
|
||||
},
|
||||
{
|
||||
key: 'PickerAndroidExample',
|
||||
module: require('./PickerAndroidExample'),
|
||||
|
@ -31,8 +31,6 @@ var RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
|
||||
* Navigator instead of Modal. With a top-level Navigator, you have more control
|
||||
* over how to present the modal scene over the rest of your app by using the
|
||||
* configureScene property.
|
||||
*
|
||||
* This component is only available in iOS at this time.
|
||||
*/
|
||||
class Modal extends React.Component {
|
||||
render(): ?ReactElement {
|
||||
|
@ -231,7 +231,7 @@ android {
|
||||
sourceSets.main {
|
||||
jni.srcDirs = []
|
||||
jniLibs.srcDir "$buildDir/react-ndk/exported"
|
||||
res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell']
|
||||
res.srcDirs = ['src/main/res/devsupport', 'src/main/res/shell', 'src/main/res/views/modal']
|
||||
java {
|
||||
srcDirs = ['src/main/java', 'src/main/libraries/soloader']
|
||||
exclude 'com/facebook/react/processing'
|
||||
|
@ -0,0 +1,25 @@
|
||||
include_defs('//ReactAndroid/DEFS')
|
||||
|
||||
android_library(
|
||||
name = 'modal',
|
||||
srcs = glob(['*.java']),
|
||||
deps = [
|
||||
react_native_target('res:modal'),
|
||||
react_native_target('java/com/facebook/react/bridge:bridge'),
|
||||
react_native_target('java/com/facebook/react/common:common'),
|
||||
react_native_target('java/com/facebook/csslayout:csslayout'),
|
||||
react_native_target('java/com/facebook/react/touch:touch'),
|
||||
react_native_target('java/com/facebook/react/uimanager:uimanager'),
|
||||
react_native_target('java/com/facebook/react/uimanager/annotations:annotations'),
|
||||
react_native_target('java/com/facebook/react/views/view:view'),
|
||||
react_native_dep('third-party/java/infer-annotations:infer-annotations'),
|
||||
react_native_dep('third-party/java/jsr-305:jsr-305'),
|
||||
],
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
|
||||
project_config(
|
||||
src_target = ':modal',
|
||||
)
|
@ -0,0 +1,66 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
|
||||
/**
|
||||
* We implement the Modal by using an Android Dialog. That will fill the entire window of the
|
||||
* application. To get layout to work properly, we need to layout all the elements within the
|
||||
* Modal as if they can fill the entire window. To do that, we need to explicitly set the
|
||||
* styleWidth and styleHeight on the LayoutShadowNode to be the window size. This will then cause
|
||||
* the children to layout as if they can fill the window.
|
||||
*
|
||||
* To get that we use information from the WindowManager and default Display. We don't use
|
||||
* DisplayMetricsHolder because it returns values that include the status bar. We only want the
|
||||
* values of what will actually be shown on screen.
|
||||
*/
|
||||
class ModalHostShadowNode extends LayoutShadowNode {
|
||||
|
||||
private final Point mMinPoint = new Point();
|
||||
private final Point mMaxPoint = new Point();
|
||||
/**
|
||||
* Once we have all the properties for the we need to measure the window and set the style
|
||||
* width and height appropriately so that layout is done properly for the view assuming it
|
||||
* fills the entire window instead of the place it is in the view tree
|
||||
*/
|
||||
@Override
|
||||
@TargetApi(16)
|
||||
public void onAfterUpdateTransaction() {
|
||||
super.onAfterUpdateTransaction();
|
||||
|
||||
Context context = getThemedContext();
|
||||
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
|
||||
Display display = wm.getDefaultDisplay();
|
||||
// getCurrentSizeRange will return the min and max width and height that the window can be
|
||||
display.getCurrentSizeRange(mMinPoint, mMaxPoint);
|
||||
|
||||
int width, height;
|
||||
int rotation = display.getRotation();
|
||||
if (rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180) {
|
||||
// If we are vertical the width value comes from min width and height comes from max height
|
||||
width = mMinPoint.x;
|
||||
height = mMaxPoint.y;
|
||||
} else {
|
||||
// If we are horizontal the width value comes from max width and height comes from min height
|
||||
width = mMaxPoint.x;
|
||||
height = mMinPoint.y;
|
||||
}
|
||||
setStyleWidth(width);
|
||||
setStyleHeight(height);
|
||||
}
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import android.content.DialogInterface;
|
||||
|
||||
import com.facebook.react.common.MapBuilder;
|
||||
import com.facebook.react.common.SystemClock;
|
||||
import com.facebook.react.uimanager.LayoutShadowNode;
|
||||
import com.facebook.react.uimanager.ThemedReactContext;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.ViewGroupManager;
|
||||
import com.facebook.react.uimanager.annotations.ReactProp;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
|
||||
/**
|
||||
* View manager for {@link ReactModalHostView} components.
|
||||
*/
|
||||
public class ReactModalHostManager extends ViewGroupManager<ReactModalHostView> {
|
||||
|
||||
private static final String REACT_CLASS = "RCTModalHostView";
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return REACT_CLASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ReactModalHostView createViewInstance(ThemedReactContext reactContext) {
|
||||
return new ReactModalHostView(reactContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutShadowNode createShadowNodeInstance() {
|
||||
return new ModalHostShadowNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends LayoutShadowNode> getShadowNodeClass() {
|
||||
return ModalHostShadowNode.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDropViewInstance(ReactModalHostView view) {
|
||||
super.onDropViewInstance(view);
|
||||
view.dismiss();
|
||||
}
|
||||
|
||||
@ReactProp(name = "animated")
|
||||
public void setAnimated(ReactModalHostView view, boolean animated) {
|
||||
view.setAnimated(animated);
|
||||
}
|
||||
|
||||
@ReactProp(name = "transparent")
|
||||
public void setTransparent(ReactModalHostView view, boolean transparent) {
|
||||
view.setTransparent(transparent);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addEventEmitters(
|
||||
ThemedReactContext reactContext,
|
||||
final ReactModalHostView view) {
|
||||
final EventDispatcher dispatcher =
|
||||
reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
|
||||
view.setOnRequestCloseListener(
|
||||
new ReactModalHostView.OnRequestCloseListener() {
|
||||
@Override
|
||||
public void onRequestClose(DialogInterface dialog) {
|
||||
dispatcher.dispatchEvent(new RequestCloseEvent(view.getId(), SystemClock.nanoTime()));
|
||||
}
|
||||
});
|
||||
view.setOnShowListener(
|
||||
new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onShow(DialogInterface dialog) {
|
||||
dispatcher.dispatchEvent(new ShowEvent(view.getId(), SystemClock.nanoTime()));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getExportedCustomDirectEventTypeConstants() {
|
||||
return MapBuilder.<String, Object>builder()
|
||||
.put(RequestCloseEvent.EVENT_NAME, MapBuilder.of("registrationName", "onRequestClose"))
|
||||
.put(ShowEvent.EVENT_NAME, MapBuilder.of("registrationName", "onShow"))
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAfterUpdateTransaction(ReactModalHostView view) {
|
||||
super.onAfterUpdateTransaction(view);
|
||||
view.showOrUpdate();
|
||||
}
|
||||
}
|
@ -0,0 +1,253 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.facebook.infer.annotation.Assertions;
|
||||
import com.facebook.react.R;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
import com.facebook.react.common.annotations.VisibleForTesting;
|
||||
import com.facebook.react.uimanager.JSTouchDispatcher;
|
||||
import com.facebook.react.uimanager.RootView;
|
||||
import com.facebook.react.uimanager.UIManagerModule;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.views.view.ReactViewGroup;
|
||||
|
||||
/**
|
||||
* ReactModalHostView is a view that sits in the view hierarchy representing a Modal view.
|
||||
*
|
||||
* It does a number of things:
|
||||
* 1. It creates a Dialog. We use this Dialog to actually display the Modal in the window.
|
||||
* 2. It creates a DialogRootViewGroup. This view is the view that is displayed by the Dialog. To
|
||||
* display a view within a Dialog, that view must have its parent set to the window the Dialog
|
||||
* creates. Because of this, we can not use the ReactModalHostView since it sits in the
|
||||
* normal React view hierarchy. We do however want all of the layout magic to happen as if the
|
||||
* DialogRootViewGroup were part of the hierarchy. Therefore, we forward all view changes
|
||||
* around addition and removal of views to the DialogRootViewGroup.
|
||||
*/
|
||||
public class ReactModalHostView extends ViewGroup {
|
||||
|
||||
// This listener is called when the user presses KeyEvent.KEYCODE_BACK
|
||||
// An event is then passed to JS which can either close or not close the Modal by setting the
|
||||
// visible property
|
||||
public interface OnRequestCloseListener {
|
||||
void onRequestClose(DialogInterface dialog);
|
||||
}
|
||||
|
||||
private DialogRootViewGroup mHostView;
|
||||
private @Nullable Dialog mDialog;
|
||||
private boolean mTransparent;
|
||||
private boolean mAnimated;
|
||||
// Set this flag to true if changing a particular property on the view requires a new Dialog to
|
||||
// be created. For instance, animation does since it affects Dialog creation through the theme
|
||||
// but transparency does not since we can access the window to update the property.
|
||||
private boolean mPropertyRequiresNewDialog;
|
||||
private @Nullable DialogInterface.OnShowListener mOnShowListener;
|
||||
private @Nullable OnRequestCloseListener mOnRequestCloseListener;
|
||||
|
||||
public ReactModalHostView(Context context) {
|
||||
super(context);
|
||||
|
||||
mHostView = new DialogRootViewGroup(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
// Do nothing as we are laid out by UIManager
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addView(View child, int index) {
|
||||
mHostView.addView(child, index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getChildCount() {
|
||||
return mHostView.getChildCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getChildAt(int index) {
|
||||
return mHostView.getChildAt(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeView(View child) {
|
||||
mHostView.removeView(child);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeViewAt(int index) {
|
||||
View child = getChildAt(index);
|
||||
mHostView.removeView(child);
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (mDialog != null) {
|
||||
mDialog.dismiss();
|
||||
mDialog = null;
|
||||
|
||||
// We need to remove the mHostView from the parent
|
||||
// It is possible we are dismissing this dialog and reattaching the hostView to another
|
||||
ViewGroup parent = (ViewGroup) mHostView.getParent();
|
||||
parent.removeViewAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
protected void setOnRequestCloseListener(OnRequestCloseListener listener) {
|
||||
mOnRequestCloseListener = listener;
|
||||
}
|
||||
|
||||
protected void setOnShowListener(DialogInterface.OnShowListener listener) {
|
||||
mOnShowListener = listener;
|
||||
}
|
||||
|
||||
protected void setTransparent(boolean transparent) {
|
||||
mTransparent = transparent;
|
||||
}
|
||||
|
||||
protected void setAnimated(boolean animated) {
|
||||
mAnimated = animated;
|
||||
mPropertyRequiresNewDialog = true;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public @Nullable Dialog getDialog() {
|
||||
return mDialog;
|
||||
}
|
||||
|
||||
/**
|
||||
* showOrUpdate will display the Dialog. It is called by the manager once all properties are set
|
||||
* because we need to know all of them before creating the Dialog. It is also smart during
|
||||
* updates if the changed properties can be applied directly to the Dialog or require the
|
||||
* recreation of a new Dialog.
|
||||
*/
|
||||
protected void showOrUpdate() {
|
||||
// If the existing Dialog is currently up, we may need to redraw it or we may be able to update
|
||||
// the property without having to recreate the dialog
|
||||
if (mDialog != null) {
|
||||
if (mPropertyRequiresNewDialog) {
|
||||
dismiss();
|
||||
} else {
|
||||
updateProperties();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Reset the flag since we are going to create a new dialog
|
||||
mPropertyRequiresNewDialog = false;
|
||||
int theme = R.style.Theme_FullScreenDialog;
|
||||
if (mAnimated) {
|
||||
theme = R.style.Theme_FullScreenDialogAnimated;
|
||||
}
|
||||
mDialog = new Dialog(getContext(), theme);
|
||||
|
||||
mDialog.setContentView(mHostView);
|
||||
updateProperties();
|
||||
|
||||
mDialog.setOnShowListener(mOnShowListener);
|
||||
mDialog.setOnKeyListener(
|
||||
new DialogInterface.OnKeyListener() {
|
||||
@Override
|
||||
public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) {
|
||||
// We need to stop the BACK button from closing the dialog by default so we capture that
|
||||
// event and instead inform JS so that it can make the decision as to whether or not to
|
||||
// allow the back button to close the dialog. If it chooses to, it can just set visible
|
||||
// to false on the Modal and the Modal will go away
|
||||
if (keyCode == KeyEvent.KEYCODE_BACK) {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP) {
|
||||
Assertions.assertNotNull(
|
||||
mOnRequestCloseListener,
|
||||
"setOnRequestCloseListener must be called by the manager");
|
||||
mOnRequestCloseListener.onRequestClose(dialog);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
mDialog.show();
|
||||
}
|
||||
|
||||
/**
|
||||
* updateProperties will update the properties that do not require us to recreate the dialog
|
||||
* Properties that do require us to recreate the dialog should set mPropertyRequiresNewDialog to
|
||||
* true when the property changes
|
||||
*/
|
||||
private void updateProperties() {
|
||||
Assertions.assertNotNull(mDialog, "mDialog must exist when we call updateProperties");
|
||||
|
||||
if (mTransparent) {
|
||||
mDialog.getWindow().clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
|
||||
} else {
|
||||
mDialog.getWindow().setDimAmount(0.5f);
|
||||
mDialog.getWindow().setFlags(
|
||||
WindowManager.LayoutParams.FLAG_DIM_BEHIND,
|
||||
WindowManager.LayoutParams.FLAG_DIM_BEHIND);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DialogRootViewGroup is the ViewGroup which contains all the children of a Modal. It gets all
|
||||
* child information forwarded from ReactModalHostView and uses that to create children. It is
|
||||
* also responsible for acting as a RootView and handling touch events. It does this the same
|
||||
* way as ReactRootView.
|
||||
*/
|
||||
static class DialogRootViewGroup extends ReactViewGroup implements RootView {
|
||||
|
||||
private final JSTouchDispatcher mJSTouchDispatcher = new JSTouchDispatcher(this);
|
||||
|
||||
public DialogRootViewGroup(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent event) {
|
||||
mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher());
|
||||
return super.onInterceptTouchEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
mJSTouchDispatcher.handleTouchEvent(event, getEventDispatcher());
|
||||
super.onTouchEvent(event);
|
||||
// In case when there is no children interested in handling touch event, we return true from
|
||||
// the root view in order to receive subsequent events related to that gesture
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onChildStartedNativeGesture(MotionEvent androidEvent) {
|
||||
mJSTouchDispatcher.onChildStartedNativeGesture(androidEvent, getEventDispatcher());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestDisallowInterceptTouchEvent(boolean disallowIntercept) {
|
||||
// No-op - override in order to still receive events to onInterceptTouchEvent
|
||||
// even when some other view disallow that
|
||||
}
|
||||
|
||||
private EventDispatcher getEventDispatcher() {
|
||||
ReactContext reactContext = (ReactContext) getContext();
|
||||
return reactContext.getNativeModule(UIManagerModule.class).getEventDispatcher();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
|
||||
/**
|
||||
* {@link Event} for dismissing a Dialog.
|
||||
*/
|
||||
/* package */ class RequestCloseEvent extends Event<RequestCloseEvent> {
|
||||
|
||||
public static final String EVENT_NAME = "topRequestClose";
|
||||
|
||||
protected RequestCloseEvent(int viewTag, long timestampMs) {
|
||||
super(viewTag, timestampMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventName() {
|
||||
return EVENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), null);
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This source code is licensed under the BSD-style license found in the
|
||||
* LICENSE file in the root directory of this source tree. An additional grant
|
||||
* of patent rights can be found in the PATENTS file in the same directory.
|
||||
*/
|
||||
|
||||
package com.facebook.react.views.modal;
|
||||
|
||||
import com.facebook.react.uimanager.events.Event;
|
||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
|
||||
|
||||
/**
|
||||
* {@link Event} for showing a Dialog.
|
||||
*/
|
||||
/* package */ class ShowEvent extends Event<ShowEvent> {
|
||||
|
||||
public static final String EVENT_NAME = "topShow";
|
||||
|
||||
protected ShowEvent(int viewTag, long timestampMs) {
|
||||
super(viewTag, timestampMs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEventName() {
|
||||
return EVENT_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatch(RCTEventEmitter rctEventEmitter) {
|
||||
rctEventEmitter.receiveEvent(getViewTag(), getEventName(), null);
|
||||
}
|
||||
}
|
@ -17,3 +17,12 @@ android_resource(
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
|
||||
android_resource(
|
||||
name = 'modal',
|
||||
res = 'views/modal',
|
||||
package = 'com.facebook.react',
|
||||
visibility = [
|
||||
'PUBLIC',
|
||||
],
|
||||
)
|
||||
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
android:fromYDelta="0%p"
|
||||
android:toYDelta="100%p"
|
||||
/>
|
6
ReactAndroid/src/main/res/views/modal/anim/slide_up.xml
Normal file
6
ReactAndroid/src/main/res/views/modal/anim/slide_up.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<translate xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:duration="@android:integer/config_shortAnimTime"
|
||||
android:fromYDelta="100%p"
|
||||
android:toYDelta="0%p"
|
||||
/>
|
20
ReactAndroid/src/main/res/views/modal/values/themes.xml
Normal file
20
ReactAndroid/src/main/res/views/modal/values/themes.xml
Normal file
@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="Theme.FullScreenDialog">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="Theme.FullScreenDialogAnimated" parent="Theme.FullScreenDialog">
|
||||
<item name="android:windowAnimationStyle">@style/DialogAnimation</item>
|
||||
</style>
|
||||
|
||||
<style name="DialogAnimation">
|
||||
<item name="android:windowEnterAnimation">@anim/slide_up</item>
|
||||
<item name="android:windowExitAnimation">@anim/slide_down</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
Loading…
x
Reference in New Issue
Block a user