Merge commit '891b6b0c14d820d38f0a0b8f5ebf749c5cd14a94' into amgleitman/0.64-merge-head
This commit is contained in:
Коммит
4f80fbd4eb
|
@ -39,6 +39,7 @@ rn_android_library(
|
|||
react_native_target("java/com/facebook/react/common:common"),
|
||||
react_native_target("java/com/facebook/react/uimanager:uimanager"),
|
||||
react_native_target("java/com/facebook/react/views/view:view"),
|
||||
react_native_target("java/com/facebook/react/views/text:text"),
|
||||
react_native_target("java/com/facebook/react/touch:touch"),
|
||||
],
|
||||
exported_deps = [
|
||||
|
|
|
@ -37,6 +37,7 @@ import com.facebook.infer.annotation.ThreadConfined;
|
|||
import com.facebook.proguard.annotations.DoNotStrip;
|
||||
import com.facebook.react.ReactRootView;
|
||||
import com.facebook.react.bridge.LifecycleEventListener;
|
||||
import com.facebook.react.bridge.NativeArray;
|
||||
import com.facebook.react.bridge.NativeMap;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContext;
|
||||
|
@ -74,6 +75,7 @@ import com.facebook.react.fabric.mounting.mountitems.UpdatePropsMountItem;
|
|||
import com.facebook.react.fabric.mounting.mountitems.UpdateStateMountItem;
|
||||
import com.facebook.react.modules.core.ReactChoreographer;
|
||||
import com.facebook.react.modules.i18nmanager.I18nUtil;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ReactRoot;
|
||||
import com.facebook.react.uimanager.ReactRootViewTagGenerator;
|
||||
import com.facebook.react.uimanager.StateWrapper;
|
||||
|
@ -82,6 +84,7 @@ import com.facebook.react.uimanager.UIManagerHelper;
|
|||
import com.facebook.react.uimanager.ViewManagerPropertyUpdater;
|
||||
import com.facebook.react.uimanager.ViewManagerRegistry;
|
||||
import com.facebook.react.uimanager.events.EventDispatcher;
|
||||
import com.facebook.react.views.text.TextLayoutManager;
|
||||
import com.facebook.systrace.Systrace;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
|
@ -443,6 +446,18 @@ public class FabricUIManager implements UIManager, LifecycleEventListener {
|
|||
return new BatchMountItem(rootTag, items, size, commitNumber);
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
@SuppressWarnings("unused")
|
||||
private NativeArray measureLines(
|
||||
ReadableMap attributedString, ReadableMap paragraphAttributes, float width, float height) {
|
||||
return (NativeArray)
|
||||
TextLayoutManager.measureLines(
|
||||
mReactApplicationContext,
|
||||
attributedString,
|
||||
paragraphAttributes,
|
||||
PixelUtil.toPixelFromDIP(width));
|
||||
}
|
||||
|
||||
@DoNotStrip
|
||||
@SuppressWarnings("unused")
|
||||
private long measure(
|
||||
|
|
|
@ -27,6 +27,7 @@ import com.facebook.common.logging.FLog;
|
|||
import com.facebook.react.bridge.ReadableArray;
|
||||
import com.facebook.react.bridge.ReadableMap;
|
||||
import com.facebook.react.bridge.ReadableNativeMap;
|
||||
import com.facebook.react.bridge.WritableArray;
|
||||
import com.facebook.react.config.ReactFeatureFlags;
|
||||
import com.facebook.react.uimanager.PixelUtil;
|
||||
import com.facebook.react.uimanager.ReactAccessibilityDelegate;
|
||||
|
@ -257,51 +258,19 @@ public class TextLayoutManager {
|
|||
return sb;
|
||||
}
|
||||
|
||||
public static long measureText(
|
||||
Context context,
|
||||
ReadableMap attributedString,
|
||||
ReadableMap paragraphAttributes,
|
||||
private static Layout createLayout(
|
||||
Spannable text,
|
||||
BoringLayout.Metrics boring,
|
||||
float width,
|
||||
YogaMeasureMode widthYogaMeasureMode,
|
||||
float height,
|
||||
YogaMeasureMode heightYogaMeasureMode,
|
||||
ReactTextViewManagerCallback reactTextViewManagerCallback,
|
||||
@Nullable float[] attachmentsPositions) {
|
||||
|
||||
// TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
|
||||
TextPaint textPaint = sTextPaintInstance;
|
||||
Spannable text;
|
||||
if (attributedString.hasKey("cacheId")) {
|
||||
int cacheId = attributedString.getInt("cacheId");
|
||||
if (sTagToSpannableCache.containsKey(cacheId)) {
|
||||
text = sTagToSpannableCache.get(cacheId);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
text = getOrCreateSpannableForText(context, attributedString, reactTextViewManagerCallback);
|
||||
}
|
||||
|
||||
int textBreakStrategy =
|
||||
TextAttributeProps.getTextBreakStrategy(
|
||||
paragraphAttributes.getString(TEXT_BREAK_STRATEGY_KEY));
|
||||
boolean includeFontPadding =
|
||||
paragraphAttributes.hasKey(INCLUDE_FONT_PADDING_KEY)
|
||||
? paragraphAttributes.getBoolean(INCLUDE_FONT_PADDING_KEY)
|
||||
: DEFAULT_INCLUDE_FONT_PADDING;
|
||||
|
||||
if (text == null) {
|
||||
throw new IllegalStateException("Spannable element has not been prepared in onBeforeLayout");
|
||||
}
|
||||
|
||||
BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
|
||||
float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN;
|
||||
|
||||
// technically, width should never be negative, but there is currently a bug in
|
||||
boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0;
|
||||
|
||||
boolean includeFontPadding,
|
||||
int textBreakStrategy) {
|
||||
Layout layout;
|
||||
int spanLength = text.length();
|
||||
boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0;
|
||||
TextPaint textPaint = sTextPaintInstance;
|
||||
float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN;
|
||||
|
||||
if (boring == null
|
||||
&& (unconstrainedWidth
|
||||
|| (!YogaConstants.isUndefined(desiredWidth) && desiredWidth <= width))) {
|
||||
|
@ -367,6 +336,55 @@ public class TextLayoutManager {
|
|||
.build();
|
||||
}
|
||||
}
|
||||
return layout;
|
||||
}
|
||||
|
||||
public static long measureText(
|
||||
Context context,
|
||||
ReadableMap attributedString,
|
||||
ReadableMap paragraphAttributes,
|
||||
float width,
|
||||
YogaMeasureMode widthYogaMeasureMode,
|
||||
float height,
|
||||
YogaMeasureMode heightYogaMeasureMode,
|
||||
ReactTextViewManagerCallback reactTextViewManagerCallback,
|
||||
@Nullable float[] attachmentsPositions) {
|
||||
|
||||
// TODO(5578671): Handle text direction (see View#getTextDirectionHeuristic)
|
||||
TextPaint textPaint = sTextPaintInstance;
|
||||
Spannable text;
|
||||
if (attributedString.hasKey("cacheId")) {
|
||||
int cacheId = attributedString.getInt("cacheId");
|
||||
if (sTagToSpannableCache.containsKey(cacheId)) {
|
||||
text = sTagToSpannableCache.get(cacheId);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
text = getOrCreateSpannableForText(context, attributedString, reactTextViewManagerCallback);
|
||||
}
|
||||
|
||||
int textBreakStrategy =
|
||||
TextAttributeProps.getTextBreakStrategy(
|
||||
paragraphAttributes.getString(TEXT_BREAK_STRATEGY_KEY));
|
||||
boolean includeFontPadding =
|
||||
paragraphAttributes.hasKey(INCLUDE_FONT_PADDING_KEY)
|
||||
? paragraphAttributes.getBoolean(INCLUDE_FONT_PADDING_KEY)
|
||||
: DEFAULT_INCLUDE_FONT_PADDING;
|
||||
|
||||
if (text == null) {
|
||||
throw new IllegalStateException("Spannable element has not been prepared in onBeforeLayout");
|
||||
}
|
||||
|
||||
BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
|
||||
float desiredWidth = boring == null ? Layout.getDesiredWidth(text, textPaint) : Float.NaN;
|
||||
|
||||
// technically, width should never be negative, but there is currently a bug in
|
||||
boolean unconstrainedWidth = widthYogaMeasureMode == YogaMeasureMode.UNDEFINED || width < 0;
|
||||
|
||||
Layout layout =
|
||||
createLayout(
|
||||
text, boring, width, widthYogaMeasureMode, includeFontPadding, textBreakStrategy);
|
||||
|
||||
int maximumNumberOfLines =
|
||||
paragraphAttributes.hasKey(MAXIMUM_NUMBER_OF_LINES_KEY)
|
||||
|
@ -408,9 +426,9 @@ public class TextLayoutManager {
|
|||
// follows a similar logic than used in pre-fabric (see ReactTextView.onLayout method).
|
||||
int attachmentIndex = 0;
|
||||
int lastAttachmentFoundInSpan;
|
||||
for (int i = 0; i < spanLength; i = lastAttachmentFoundInSpan) {
|
||||
for (int i = 0; i < text.length(); i = lastAttachmentFoundInSpan) {
|
||||
lastAttachmentFoundInSpan =
|
||||
text.nextSpanTransition(i, spanLength, TextInlineViewPlaceholderSpan.class);
|
||||
text.nextSpanTransition(i, text.length(), TextInlineViewPlaceholderSpan.class);
|
||||
TextInlineViewPlaceholderSpan[] placeholders =
|
||||
text.getSpans(i, lastAttachmentFoundInSpan, TextInlineViewPlaceholderSpan.class);
|
||||
for (TextInlineViewPlaceholderSpan placeholder : placeholders) {
|
||||
|
@ -432,7 +450,7 @@ public class TextLayoutManager {
|
|||
// There's a bug on Samsung devices where calling getPrimaryHorizontal on
|
||||
// the last offset in the layout will result in an endless loop. Work around
|
||||
// this bug by avoiding getPrimaryHorizontal in that case.
|
||||
if (start == spanLength - 1) {
|
||||
if (start == text.length() - 1) {
|
||||
placeholderLeftPosition =
|
||||
isRtlParagraph
|
||||
// Equivalent to `layout.getLineLeft(line)` but `getLineLeft` returns incorrect
|
||||
|
@ -502,6 +520,29 @@ public class TextLayoutManager {
|
|||
return YogaMeasureOutput.make(widthInSP, heightInSP);
|
||||
}
|
||||
|
||||
public static WritableArray measureLines(
|
||||
@NonNull Context context,
|
||||
ReadableMap attributedString,
|
||||
ReadableMap paragraphAttributes,
|
||||
float width) {
|
||||
TextPaint textPaint = sTextPaintInstance;
|
||||
Spannable text = getOrCreateSpannableForText(context, attributedString, null);
|
||||
BoringLayout.Metrics boring = BoringLayout.isBoring(text, textPaint);
|
||||
|
||||
int textBreakStrategy =
|
||||
TextAttributeProps.getTextBreakStrategy(
|
||||
paragraphAttributes.getString(TEXT_BREAK_STRATEGY_KEY));
|
||||
boolean includeFontPadding =
|
||||
paragraphAttributes.hasKey(INCLUDE_FONT_PADDING_KEY)
|
||||
? paragraphAttributes.getBoolean(INCLUDE_FONT_PADDING_KEY)
|
||||
: DEFAULT_INCLUDE_FONT_PADDING;
|
||||
|
||||
Layout layout =
|
||||
createLayout(
|
||||
text, boring, width, YogaMeasureMode.EXACTLY, includeFontPadding, textBreakStrategy);
|
||||
return FontMetricsUtil.getFontMetrics(text, layout, sTextPaintInstance, context);
|
||||
}
|
||||
|
||||
// TODO T31905686: This class should be private
|
||||
public static class SetSpanOperation {
|
||||
protected int start, end;
|
||||
|
|
|
@ -169,7 +169,6 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
|
|||
content.paragraphAttributes,
|
||||
layoutConstraints);
|
||||
|
||||
#ifndef ANDROID
|
||||
if (getConcreteProps().onTextLayout) {
|
||||
auto linesMeasurements = textLayoutManager_->measureLines(
|
||||
content.attributedString,
|
||||
|
@ -177,7 +176,6 @@ void ParagraphShadowNode::layout(LayoutContext layoutContext) {
|
|||
measurement.size);
|
||||
getConcreteEventEmitter().onTextLayout(linesMeasurements);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (content.attachments.empty()) {
|
||||
// No attachments to layout.
|
||||
|
|
|
@ -10,6 +10,40 @@
|
|||
namespace facebook {
|
||||
namespace react {
|
||||
|
||||
static Rect rectFromDynamic(folly::dynamic const &data) {
|
||||
Point origin;
|
||||
origin.x = data.getDefault("x", 0).getDouble();
|
||||
origin.y = data.getDefault("y", 0).getDouble();
|
||||
Size size;
|
||||
size.width = data.getDefault("width", 0).getDouble();
|
||||
size.height = data.getDefault("height", 0).getDouble();
|
||||
Rect frame;
|
||||
frame.origin = origin;
|
||||
frame.size = size;
|
||||
return frame;
|
||||
}
|
||||
|
||||
LineMeasurement::LineMeasurement(
|
||||
std::string text,
|
||||
Rect frame,
|
||||
Float descender,
|
||||
Float capHeight,
|
||||
Float ascender,
|
||||
Float xHeight)
|
||||
: text(text),
|
||||
frame(frame),
|
||||
descender(descender),
|
||||
capHeight(capHeight),
|
||||
ascender(ascender) {}
|
||||
|
||||
LineMeasurement::LineMeasurement(folly::dynamic const &data)
|
||||
: text(data.getDefault("text", "").getString()),
|
||||
frame(rectFromDynamic(data)),
|
||||
descender(data.getDefault("descender", 0).getDouble()),
|
||||
capHeight(data.getDefault("capHeight", 0).getDouble()),
|
||||
ascender(data.getDefault("ascender", 0).getDouble()),
|
||||
xHeight(data.getDefault("xHeight", 0).getDouble()) {}
|
||||
|
||||
bool LineMeasurement::operator==(LineMeasurement const &rhs) const {
|
||||
return std::tie(
|
||||
this->text,
|
||||
|
|
|
@ -24,6 +24,16 @@ struct LineMeasurement {
|
|||
Float ascender;
|
||||
Float xHeight;
|
||||
|
||||
LineMeasurement(
|
||||
std::string text,
|
||||
Rect frame,
|
||||
Float descender,
|
||||
Float capHeight,
|
||||
Float ascender,
|
||||
Float xHeight);
|
||||
|
||||
LineMeasurement(folly::dynamic const &data);
|
||||
|
||||
bool operator==(LineMeasurement const &rhs) const;
|
||||
};
|
||||
|
||||
|
|
|
@ -98,6 +98,50 @@ TextMeasurement TextLayoutManager::measureCachedSpannableById(
|
|||
return TextMeasurement{size, attachments};
|
||||
}
|
||||
|
||||
LinesMeasurements TextLayoutManager::measureLines(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
Size size) const {
|
||||
const jni::global_ref<jobject> &fabricUIManager =
|
||||
contextContainer_->at<jni::global_ref<jobject>>("FabricUIManager");
|
||||
static auto measureLines =
|
||||
jni::findClassStatic("com/facebook/react/fabric/FabricUIManager")
|
||||
->getMethod<NativeArray::javaobject(
|
||||
ReadableMap::javaobject,
|
||||
ReadableMap::javaobject,
|
||||
jfloat,
|
||||
jfloat)>("measureLines");
|
||||
|
||||
auto serializedAttributedString = toDynamic(attributedString);
|
||||
|
||||
local_ref<ReadableNativeMap::javaobject> attributedStringRNM =
|
||||
ReadableNativeMap::newObjectCxxArgs(serializedAttributedString);
|
||||
local_ref<ReadableNativeMap::javaobject> paragraphAttributesRNM =
|
||||
ReadableNativeMap::newObjectCxxArgs(toDynamic(paragraphAttributes));
|
||||
|
||||
local_ref<ReadableMap::javaobject> attributedStringRM = make_local(
|
||||
reinterpret_cast<ReadableMap::javaobject>(attributedStringRNM.get()));
|
||||
local_ref<ReadableMap::javaobject> paragraphAttributesRM = make_local(
|
||||
reinterpret_cast<ReadableMap::javaobject>(paragraphAttributesRNM.get()));
|
||||
|
||||
auto array = measureLines(
|
||||
fabricUIManager,
|
||||
attributedStringRM.get(),
|
||||
paragraphAttributesRM.get(),
|
||||
size.width,
|
||||
size.height);
|
||||
|
||||
auto dynamicArray = cthis(array)->consume();
|
||||
LinesMeasurements lineMeasurements;
|
||||
lineMeasurements.reserve(dynamicArray.size());
|
||||
|
||||
for (auto const &data : dynamicArray) {
|
||||
lineMeasurements.push_back(LineMeasurement(data));
|
||||
}
|
||||
|
||||
return lineMeasurements;
|
||||
}
|
||||
|
||||
TextMeasurement TextLayoutManager::doMeasure(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
|
|
|
@ -46,6 +46,15 @@ class TextLayoutManager {
|
|||
ParagraphAttributes paragraphAttributes,
|
||||
LayoutConstraints layoutConstraints) const;
|
||||
|
||||
/*
|
||||
* Measures lines of `attributedString` using native text rendering
|
||||
* infrastructure.
|
||||
*/
|
||||
LinesMeasurements measureLines(
|
||||
AttributedString attributedString,
|
||||
ParagraphAttributes paragraphAttributes,
|
||||
Size size) const;
|
||||
|
||||
/*
|
||||
* Returns an opaque pointer to platform-specific TextLayoutManager.
|
||||
* Is used on a native views layer to delegate text rendering to the manager.
|
||||
|
|
|
@ -510,8 +510,8 @@ SPEC CHECKSUMS:
|
|||
CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845
|
||||
CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f
|
||||
DoubleConversion: 2b45d0f8e156a5b02354c8a4062de64d41ccb4e0
|
||||
FBLazyVector: be96ff5ddc8762ebad9f7aa25ec5548d92f6eb13
|
||||
FBReactNativeSpec: 2f6114e367cc9f9330fd6cf145dd56a41ac0a5c2
|
||||
FBLazyVector: ab9bc1abaad967275f368fec7338076623de84bc
|
||||
FBReactNativeSpec: 725315ac74f0e173d6b5051e7612fc3bf7196ea5
|
||||
Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365
|
||||
Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41
|
||||
Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3
|
||||
|
@ -522,33 +522,33 @@ SPEC CHECKSUMS:
|
|||
glog: 789873d01e4b200777d0a09bc23d548446758699
|
||||
OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355
|
||||
RCT-Folly: 55d0039b24e192081ec0b2257f7bd9f42e382fb7
|
||||
RCTRequired: 29abaea42d11b55dc4416cf3c6fc63a2a2f8a4f6
|
||||
RCTTypeSafety: 2d6fdb69390d492bb0121be8e362b936d89a83d0
|
||||
React: 2e77ccbe3820e5b726c1bfa5d76ebf3639d2e624
|
||||
React-callinvoker: f83f10e61f666362d63045bd2e9fa0ac4c562eb2
|
||||
React-Core: 0f533e477a7d85f616767a8378ce3ecdf0a107c3
|
||||
React-CoreModules: 1bb04ffd718f50ac6c905badd07c33fd73c2ee44
|
||||
React-cxxreact: f4bca80e9a784bd9103dad290e98e8b8db01e903
|
||||
React-jsi: ebc752bab65e3584fd8d6bb42fa203998ca128ab
|
||||
React-jsiexecutor: e54040f675335398696bf98c3a96e5c3ab25310a
|
||||
React-jsinspector: a26fdcbb1ddeef87b48c7d245dcfafc947b28349
|
||||
React-perflogger: 5d58ef97cdfe17c09913a76c73787afa4d8293a4
|
||||
React-RCTActionSheet: cd7ee54205dc9cb5e314ac47c6f86bd7ee318c95
|
||||
React-RCTAnimation: eafc659e92f8a4042a183c303e019da27c7f70c0
|
||||
React-RCTBlob: f37c088901d659b998624a82c0743f6d06857855
|
||||
React-RCTImage: c09da3d5aa56d904960cbbf8053721442dc16bb0
|
||||
React-RCTLinking: 42aea5beb1b916998888108b21c84aa04006c47c
|
||||
React-RCTNetwork: bf0375d06bafbfbbcf13432a8e29cb566a23802d
|
||||
React-RCTPushNotification: b4acb243224b167ea548777c93915b93381ca9b6
|
||||
React-RCTSettings: 393cce35dc361345af1f3df79d39ecac0ee40d20
|
||||
React-RCTTest: 6c08cc250a83a74c0112e4f620630762cc7238df
|
||||
React-RCTText: dd6fbf4ee023124a4fe0bfb1cc0689d453979625
|
||||
React-RCTVibration: 9ab10ad1c8a47a520b85b345ab9a4f4128ddece5
|
||||
React-runtimeexecutor: f38d137573b912af78493a139b3d6ee24af03b98
|
||||
RCTRequired: be09d070a0403ab5fd4a61d2d0e33c7934606dd8
|
||||
RCTTypeSafety: d535db16fe11a7aeefab886b248f9f40553fc35b
|
||||
React: 632d9bfd0d2ebb2ee59da8f2ea30e86332a93db1
|
||||
React-callinvoker: 7e80b7c0234aa4641d9f0c430a0e351ad88be343
|
||||
React-Core: fb995a2ae7deb27d3a28ce59e76fb16f66240c1d
|
||||
React-CoreModules: 47a1a2e8511b1becd6c517ffb9f845e277d2a0cc
|
||||
React-cxxreact: 9027d3fea2551ae0baf6459b52920a0058d98a17
|
||||
React-jsi: ab6099830710881c6fb9e8a8625a99a8d7ffa8b7
|
||||
React-jsiexecutor: d1b26623ceaa1a3463d6dbbbdee78b25dbd2933d
|
||||
React-jsinspector: 5617c75b22620490c4eba6aec6e3f413b307cdbf
|
||||
React-perflogger: b1ab1854dc90b1e30dfcefe891ccbf1ee7ad91f2
|
||||
React-RCTActionSheet: 23fa3ab74a8df6a0304bb80675b62cca9f48eb3c
|
||||
React-RCTAnimation: 199458414744d214f07e692f2b480c7b6f4ba306
|
||||
React-RCTBlob: 86a4bd10ead2375038102f9377c49d38e917979c
|
||||
React-RCTImage: 3d39033c9164a61b34603d47db9460c9b75891d3
|
||||
React-RCTLinking: 0ec1b549935c2202f8d6d0db3c7b119a49cea088
|
||||
React-RCTNetwork: 7734aee17f2af29832f09fafa88e7bb7482741e6
|
||||
React-RCTPushNotification: f6eeb265e0c7d554e7a0dd6c6788c7b25b2e4d4e
|
||||
React-RCTSettings: aadf840e47aa7633d9137f59cc4a21645855fdad
|
||||
React-RCTTest: e6fafe4a579cf2f717703b73f61b3e3cccf595a3
|
||||
React-RCTText: 0111ffb42e2a9dec3333e370eae6b8ce2a8f05b9
|
||||
React-RCTVibration: d5503cee4b3c774fd229b6ab70da280ed4697a5d
|
||||
React-runtimeexecutor: 0219cbeaaf15cd8aa2de564f63f0a5ff194f8b03
|
||||
React-TurboModuleCxx-RNW: 18bb71af41fe34c8b12a56bef60aae7ee32b0817
|
||||
React-TurboModuleCxx-WinRTPort: f42f2365a3bb1aa71594dd755665cb0db98fe2bf
|
||||
ReactCommon: d9bc39a8ec4f930bf47723072e94f9978882a339
|
||||
Yoga: 19f37db1c20d7fd087ac7da338920ca7e3204110
|
||||
React-TurboModuleCxx-WinRTPort: 858129d8ad888b26e8c2140be144184d78613b30
|
||||
ReactCommon: dfec2c622c81cf59f382729fbd1eb95e6d51df71
|
||||
Yoga: 49925aeb9303e7336561ca244f4d3c70a5757c5f
|
||||
YogaKit: f782866e155069a2cca2517aafea43200b01fd5a
|
||||
|
||||
PODFILE CHECKSUM: cb260f8f7765c910b68f8267cbd74709f6ae6e54
|
||||
|
|
|
@ -12,115 +12,96 @@
|
|||
|
||||
const React = require('react');
|
||||
|
||||
const {
|
||||
StyleSheet,
|
||||
View,
|
||||
Text,
|
||||
TouchableHighlight,
|
||||
Share,
|
||||
} = require('react-native');
|
||||
const {StyleSheet, View, Text, Button, Share} = require('react-native');
|
||||
|
||||
type Props = $ReadOnly<{||}>;
|
||||
type State = {|result: string|};
|
||||
const shareMessage = () => {
|
||||
Share.share({
|
||||
message: ('Our top priority for React Native is to match the expectations people have for each platform. This is why React Native renders to platform primitives. We value native look-and-feel over cross-platform consistency.' +
|
||||
'For example, the TextInput in React Native renders to a UITextField on iOS. This ensures that integration with password managers and keyboard controls work out of the box. By using platform primitives, React Native apps are also able to stay up-to-date with design and behavior changes from new releases of Android and iOS.': string),
|
||||
});
|
||||
};
|
||||
|
||||
class ShareMessageExample extends React.Component<Props, State> {
|
||||
_shareMessage: Function;
|
||||
_shareText: Function;
|
||||
_showResult: Function;
|
||||
const shareText = () => {
|
||||
Share.share(
|
||||
{
|
||||
title: 'Massive Scale',
|
||||
message: ('Hundreds of screens in the Facebook app are implemented with React Native. The Facebook app is used by billions of people on a huge range of devices. This is why we invest in the most challenging problems at scale.' +
|
||||
'Deploying React Native in our apps lets us identify problems that we wouldn’t see at a smaller scale. For example, Facebook focuses on improving performance across a broad spectrum of devices from the newest iPhone to many older generations of Android devices. This focus informs our architecture projects such as Hermes, Fabric, and TurboModules.': string),
|
||||
url: 'https://reactnative.dev/blog/2020/07/17/react-native-principles',
|
||||
},
|
||||
{
|
||||
subject: 'MUST READ: Massive Scale',
|
||||
dialogTitle: 'Share React Native Blog',
|
||||
excludedActivityTypes: ['com.apple.UIKit.activity.PostToTwitter'],
|
||||
tintColor: 'blue',
|
||||
},
|
||||
);
|
||||
};
|
||||
|
||||
constructor(props) {
|
||||
super(props);
|
||||
const ShareMessageWithoutTitle = () => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Native Experience</Text>
|
||||
<Text>
|
||||
Our top priority for React Native is to match the expectations people
|
||||
have for each platform. This is why React Native renders to platform
|
||||
primitives. We value native look-and-feel over cross-platform
|
||||
consistency. For example, the TextInput in React Native renders to a
|
||||
UITextField on iOS. This ensures that integration with password managers
|
||||
and keyboard controls work out of the box. By using platform primitives,
|
||||
React Native apps are also able to stay up-to-date with design and
|
||||
behavior changes from new releases of Android and iOS.
|
||||
</Text>
|
||||
<Button title="SHARE" onPress={shareMessage} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
this._shareMessage = this._shareMessage.bind(this);
|
||||
this._shareText = this._shareText.bind(this);
|
||||
this._showResult = this._showResult.bind(this);
|
||||
|
||||
this.state = {
|
||||
result: '',
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<View>
|
||||
<TouchableHighlight style={styles.wrapper} onPress={this._shareMessage}>
|
||||
<View style={styles.button}>
|
||||
<Text>Click to share message</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<TouchableHighlight style={styles.wrapper} onPress={this._shareText}>
|
||||
<View style={styles.button}>
|
||||
<Text>Click to share message, URL and title</Text>
|
||||
</View>
|
||||
</TouchableHighlight>
|
||||
<Text>{this.state.result}</Text>
|
||||
</View>
|
||||
);
|
||||
}
|
||||
|
||||
_shareMessage() {
|
||||
Share.share({
|
||||
message:
|
||||
'React Native | A framework for building native apps using React',
|
||||
})
|
||||
.then(this._showResult)
|
||||
.catch(error => this.setState({result: 'error: ' + error.message}));
|
||||
}
|
||||
|
||||
_shareText() {
|
||||
Share.share(
|
||||
{
|
||||
message: 'A framework for building native apps using React',
|
||||
url: 'https://reactnative.dev/',
|
||||
title: 'React Native',
|
||||
},
|
||||
{
|
||||
subject: 'A subject to go in the email heading',
|
||||
dialogTitle: 'Share React Native website',
|
||||
excludedActivityTypes: ['com.apple.UIKit.activity.PostToTwitter'],
|
||||
tintColor: 'green',
|
||||
},
|
||||
)
|
||||
.then(this._showResult)
|
||||
.catch(error => this.setState({result: 'error: ' + error.message}));
|
||||
}
|
||||
|
||||
_showResult(result) {
|
||||
if (result.action === Share.sharedAction) {
|
||||
if (result.activityType) {
|
||||
this.setState({
|
||||
result: 'shared with an activityType: ' + result.activityType,
|
||||
});
|
||||
} else {
|
||||
this.setState({result: 'shared'});
|
||||
}
|
||||
} else if (result.action === Share.dismissedAction) {
|
||||
this.setState({result: 'dismissed'});
|
||||
}
|
||||
}
|
||||
}
|
||||
const ShareMessageWithTitle = () => {
|
||||
return (
|
||||
<View style={styles.container}>
|
||||
<Text style={styles.title}>Massive Scale</Text>
|
||||
<Text>
|
||||
Hundreds of screens in the Facebook app are implemented with React
|
||||
Native. The Facebook app is used by billions of people on a huge range
|
||||
of devices. This is why we invest in the most challenging problems at
|
||||
scale. Deploying React Native in our apps lets us identify problems that
|
||||
we wouldn’t see at a smaller scale. For example, Facebook focuses on
|
||||
improving performance across a broad spectrum of devices from the newest
|
||||
iPhone to many older generations of Android devices. This focus informs
|
||||
our architecture projects such as Hermes, Fabric, and TurboModules.
|
||||
</Text>
|
||||
<Button title="SHARE" onPress={shareText} />
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
wrapper: {
|
||||
borderRadius: 5,
|
||||
marginBottom: 5,
|
||||
container: {
|
||||
flex: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
button: {
|
||||
backgroundColor: '#eeeeee',
|
||||
padding: 10,
|
||||
title: {
|
||||
fontSize: 30,
|
||||
margin: 10,
|
||||
textAlign: 'center',
|
||||
},
|
||||
});
|
||||
|
||||
exports.framework = 'React';
|
||||
exports.title = 'Share';
|
||||
exports.category = 'Basic';
|
||||
exports.documentationURL = 'https://reactnative.dev/docs/share';
|
||||
exports.description = 'Share data with other Apps.';
|
||||
exports.examples = [
|
||||
{
|
||||
title: 'Share Text Content',
|
||||
title: 'Share message',
|
||||
render(): React.Node {
|
||||
return <ShareMessageExample />;
|
||||
return <ShareMessageWithoutTitle />;
|
||||
},
|
||||
},
|
||||
{
|
||||
title: 'Share message, URL (iOS) and title (Android)',
|
||||
render(): React.Node {
|
||||
return <ShareMessageWithTitle />;
|
||||
},
|
||||
},
|
||||
];
|
||||
|
|
Загрузка…
Ссылка в новой задаче