Implement data detection for android Text elements (#19216)

Summary:
We want the ability to use Linkify on android text elements. This only adds this property to Text and not TextInput since there are some functional differences with how the types could be used between iOS and android - iOS allows one or many types while Linkify restricted us to providing only one option (using the masks).

Performance is affected ONLY FOR TEXT ELEMENTS USING THIS FEATURE since Linkify is searching for patterns.
Pull Request resolved: https://github.com/facebook/react-native/pull/19216

Differential Revision: D14621883

Pulled By: cpojer

fbshipit-source-id: cb692021d314140b9a92b29e23384afd7fd1b09e
This commit is contained in:
Kyle Pinkham
2019-03-26 12:25:33 -07:00
committed by Facebook Github Bot
parent 97c414ec8d
commit b1251d067a
6 changed files with 61 additions and 1 deletions

View File

@@ -66,6 +66,7 @@ const viewConfig = {
minimumFontScale: true,
textBreakStrategy: true,
onTextLayout: true,
dataDetectorType: true,
},
directEventTypes: {
topTextLayout: {

View File

@@ -18,6 +18,8 @@ const TextStylePropTypes = require('TextStylePropTypes');
const stylePropType = DeprecatedStyleSheetPropType(TextStylePropTypes);
const DataDetectorTypes = ['phoneNumber', 'link', 'email', 'none', 'all'];
module.exports = {
/**
* When `numberOfLines` is set, this prop defines how text will be
@@ -132,4 +134,10 @@ module.exports = {
* See https://facebook.github.io/react-native/docs/text.html#disabled
*/
disabled: PropTypes.bool,
/**
* Determines the types of data converted to clickable URLs in text.
*
* See https://facebook.github.io/react-native/docs/text.html#dataDetectorType
*/
dataDetectorType: PropTypes.oneOf(DataDetectorTypes),
};

View File

@@ -158,6 +158,8 @@ export type TextProps = $ReadOnly<{|
*/
selectionColor?: ?string,
dataDetectorType?: ?('phoneNumber' | 'link' | 'email' | 'none' | 'all'),
/**
* Set text break strategy on Android.
*

View File

@@ -623,6 +623,19 @@ class TextExample extends React.Component<{}> {
<RNTesterBlock title="Substring Emoji (should only see 'test')">
<Text>{'test🙃'.substring(0, 5)}</Text>
</RNTesterBlock>
<RNTesterBlock title="Text linkify">
<Text dataDetectorType="phoneNumber">Phone number: 123-123-1234</Text>
<Text dataDetectorType="link">Link: https://www.facebook.com</Text>
<Text dataDetectorType="email">Email: employee@facebook.com</Text>
<Text dataDetectorType="none">
Phone number: 123-123-1234 Link: https://www.facebook.com Email:
employee@facebook.com
</Text>
<Text dataDetectorType="all">
Phone number: 123-123-1234 Link: https://www.facebook.com Email:
employee@facebook.com
</Text>
</RNTesterBlock>
</RNTesterPage>
);
}

View File

@@ -9,6 +9,7 @@ package com.facebook.react.views.text;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.util.Linkify;
import android.view.Gravity;
import android.view.View;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
@@ -160,4 +161,26 @@ public abstract class ReactTextAnchorViewManager<T extends View, C extends React
public void setDisabled(ReactTextView view, boolean disabled) {
view.setEnabled(!disabled);
}
@ReactProp(name = "dataDetectorType")
public void setDataDetectorType(ReactTextView view, @Nullable String type) {
switch (type) {
case "phoneNumber":
view.setLinkifyMask(Linkify.PHONE_NUMBERS);
break;
case "link":
view.setLinkifyMask(Linkify.WEB_URLS);
break;
case "email":
view.setLinkifyMask(Linkify.EMAIL_ADDRESSES);
break;
case "all":
view.setLinkifyMask(Linkify.ALL);
break;
case "none":
default:
view.setLinkifyMask(0);
break;
}
}
}

View File

@@ -14,7 +14,10 @@ import androidx.appcompat.widget.AppCompatTextView;
import android.text.Layout;
import android.text.Spannable;
import android.text.Spanned;
import android.text.Spannable;
import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.view.Gravity;
import android.view.ViewGroup;
import com.facebook.common.logging.FLog;
@@ -35,6 +38,7 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
private int mTextAlign = Gravity.NO_GRAVITY;
private int mNumberOfLines = ViewDefaults.NUMBER_OF_LINES;
private TextUtils.TruncateAt mEllipsizeLocation = TextUtils.TruncateAt.END;
private int mLinkifyMaskType = 0;
private ReactViewBackgroundManager mReactBackgroundManager;
private Spannable mSpanned;
@@ -55,7 +59,12 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
if (getLayoutParams() == null) {
setLayoutParams(EMPTY_LAYOUT_PARAMS);
}
setText(update.getText());
Spannable spannable = update.getText();
if (mLinkifyMaskType > 0) {
Linkify.addLinks(spannable, mLinkifyMaskType);
setMovementMethod(LinkMovementMethod.getInstance());
}
setText(spannable);
setPadding(
(int) Math.floor(update.getPaddingLeft()),
(int) Math.floor(update.getPaddingTop()),
@@ -276,4 +285,8 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
public Spannable getSpanned() {
return mSpanned;
}
public void setLinkifyMask(int mask) {
mLinkifyMaskType = mask;
}
}