Fix non selectable Text in FlatList (#28952)
Summary: This issue fixes https://github.com/facebook/react-native/issues/26264 fixes https://github.com/facebook/react-native/issues/27107 Text is not selectable inside a FlatList on Android. The solution is to invalidate the ReactTextView after a change of the selectable prop. If the view is visible, onDraw(android.graphics.Canvas) will be called at some point in the future and make the Text selectable. ## Changelog <!-- Help reviewers and the release process by writing your own changelog entry. For an example, see: https://github.com/facebook/react-native/wiki/Changelog --> [Android] [Fixed] - Fix non selectable Text in FlatList Pull Request resolved: https://github.com/facebook/react-native/pull/28952 Test Plan: **<details><summary>CLICK TO OPEN TESTS RESULTS</summary>** <p> The issue was demonstrated in the following [snack](https://snack.expo.io/fabrizio.bertoglio/selectable-bug-in-flatlist) (more info in issue https://github.com/facebook/react-native/issues/26264). The solution is: 1) Calling `invalidate()` from [setSelectableText][1] after changing the `selectable` prop and `mSelectableText` value. [`invalidate()`](https://developer.android.com/reference/android/view/View#invalidate()) triggers the `onDraw` callback. [1]:8027524947/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java (L427-L430)
2) calling `setTextIsSelectable(mSelectableText);` from the [`onDraw`][2] callback [2]:8027524947/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java (L456-L460)
The example below is availabe in RNTester FlatList example. Two options (`onPressDisabled` and `textSelectable`) have been added to test the functionality inside a FlatList. <p align="center"> <img src="https://user-images.githubusercontent.com/24992535/82672536-c2e74d80-9c40-11ea-8fd8-156bfacfac8a.gif" width="200" height="" /> </p> </p> </details> Reviewed By: ShikaSD Differential Revision: D30000870 Pulled By: lunaleaps fbshipit-source-id: 4851a294960df0af057d006793aa9ba97c51e3f9
This commit is contained in:
Родитель
e2e39808d3
Коммит
c360b1d92b
|
@ -56,6 +56,7 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
|
|||
private boolean mAdjustsFontSizeToFit = false;
|
||||
private int mLinkifyMaskType = 0;
|
||||
private boolean mNotifyOnInlineViewLayout;
|
||||
private boolean mTextIsSelectable = false;
|
||||
|
||||
private ReactViewBackgroundManager mReactBackgroundManager;
|
||||
private Spannable mSpanned;
|
||||
|
@ -433,9 +434,16 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTextIsSelectable(boolean selectable) {
|
||||
mTextIsSelectable = selectable;
|
||||
super.setTextIsSelectable(selectable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
setTextIsSelectable(mTextIsSelectable);
|
||||
if (mContainsImages && getText() instanceof Spanned) {
|
||||
Spanned text = (Spanned) getText();
|
||||
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);
|
||||
|
|
|
@ -57,13 +57,14 @@ class ItemComponent extends React.PureComponent<{
|
|||
onPress: (key: string) => void,
|
||||
onShowUnderlay?: () => void,
|
||||
onHideUnderlay?: () => void,
|
||||
textSelectable?: ?boolean,
|
||||
...
|
||||
}> {
|
||||
_onPress = () => {
|
||||
this.props.onPress(this.props.item.key);
|
||||
};
|
||||
render(): React.Node {
|
||||
const {fixedHeight, horizontal, item} = this.props;
|
||||
const {fixedHeight, horizontal, item, textSelectable} = this.props;
|
||||
const itemHash = Math.abs(hashCode(item.title));
|
||||
const imgSource = THUMB_URLS[itemHash % THUMB_URLS.length];
|
||||
return (
|
||||
|
@ -81,6 +82,7 @@ class ItemComponent extends React.PureComponent<{
|
|||
{!item.noImage && <Image style={styles.thumb} source={imgSource} />}
|
||||
<Text
|
||||
style={styles.text}
|
||||
selectable={textSelectable}
|
||||
numberOfLines={horizontal || fixedHeight ? 3 : undefined}>
|
||||
{item.title} - {item.text}
|
||||
</Text>
|
||||
|
|
|
@ -59,6 +59,8 @@ type State = {|
|
|||
empty: boolean,
|
||||
useFlatListItemComponent: boolean,
|
||||
fadingEdgeLength: number,
|
||||
onPressDisabled: boolean,
|
||||
textSelectable: boolean,
|
||||
|};
|
||||
|
||||
class FlatListExample extends React.PureComponent<Props, State> {
|
||||
|
@ -74,6 +76,8 @@ class FlatListExample extends React.PureComponent<Props, State> {
|
|||
empty: false,
|
||||
useFlatListItemComponent: false,
|
||||
fadingEdgeLength: 0,
|
||||
onPressDisabled: false,
|
||||
textSelectable: true,
|
||||
};
|
||||
|
||||
_onChangeFilterText = filterText => {
|
||||
|
@ -161,6 +165,16 @@ class FlatListExample extends React.PureComponent<Props, State> {
|
|||
this.state.debug,
|
||||
this._setBooleanValue('debug'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'onPress Disabled',
|
||||
this.state.onPressDisabled,
|
||||
this._setBooleanValue('onPressDisabled'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'Text Selectable',
|
||||
this.state.textSelectable,
|
||||
this._setBooleanValue('textSelectable'),
|
||||
)}
|
||||
{renderSmallSwitchOption(
|
||||
'Use FlatListItemComponent',
|
||||
this.state.useFlatListItemComponent,
|
||||
|
@ -236,6 +250,12 @@ class FlatListExample extends React.PureComponent<Props, State> {
|
|||
data: state.data.concat(genItemData(100, state.data.length)),
|
||||
}));
|
||||
};
|
||||
_onPressCallback = () => {
|
||||
const {onPressDisabled} = this.state;
|
||||
const warning = () => console.log('onPress disabled');
|
||||
const onPressAction = onPressDisabled ? warning : this._pressItem;
|
||||
return onPressAction;
|
||||
};
|
||||
_onRefresh = () => Alert.alert('onRefresh: nothing to refresh :P');
|
||||
_renderItemComponent = () => {
|
||||
const flatListPropKey = this.state.useFlatListItemComponent
|
||||
|
@ -253,9 +273,10 @@ class FlatListExample extends React.PureComponent<Props, State> {
|
|||
item={item}
|
||||
horizontal={this.state.horizontal}
|
||||
fixedHeight={this.state.fixedHeight}
|
||||
onPress={this._pressItem}
|
||||
onPress={this._onPressCallback()}
|
||||
onShowUnderlay={separators.highlight}
|
||||
onHideUnderlay={separators.unhighlight}
|
||||
textSelectable={this.state.textSelectable}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
Загрузка…
Ссылка в новой задаче