Skip to content

Commit c360b1d

Browse files
fabOnReactfacebook-github-bot
authored andcommitted
Fix non selectable Text in FlatList (#28952)
Summary: This issue fixes #26264 fixes #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: #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 #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]: https://github.com/fabriziobertoglio1987/react-native/blob/8027524947cafd5cbdc492e4ef9c92b346fe23fc/ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java#L427-L430 2) calling `setTextIsSelectable(mSelectableText);` from the [`onDraw`][2] callback [2]: https://github.com/fabriziobertoglio1987/react-native/blob/8027524947cafd5cbdc492e4ef9c92b346fe23fc/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
1 parent e2e3980 commit c360b1d

File tree

3 files changed

+33
-2
lines changed

3 files changed

+33
-2
lines changed

ReactAndroid/src/main/java/com/facebook/react/views/text/ReactTextView.java

+8
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public class ReactTextView extends AppCompatTextView implements ReactCompoundVie
5656
private boolean mAdjustsFontSizeToFit = false;
5757
private int mLinkifyMaskType = 0;
5858
private boolean mNotifyOnInlineViewLayout;
59+
private boolean mTextIsSelectable = false;
5960

6061
private ReactViewBackgroundManager mReactBackgroundManager;
6162
private Spannable mSpanned;
@@ -433,9 +434,16 @@ public void onStartTemporaryDetach() {
433434
}
434435
}
435436

437+
@Override
438+
public void setTextIsSelectable(boolean selectable) {
439+
mTextIsSelectable = selectable;
440+
super.setTextIsSelectable(selectable);
441+
}
442+
436443
@Override
437444
public void onAttachedToWindow() {
438445
super.onAttachedToWindow();
446+
setTextIsSelectable(mTextIsSelectable);
439447
if (mContainsImages && getText() instanceof Spanned) {
440448
Spanned text = (Spanned) getText();
441449
TextInlineImageSpan[] spans = text.getSpans(0, text.length(), TextInlineImageSpan.class);

packages/rn-tester/js/components/ListExampleShared.js

+3-1
Original file line numberDiff line numberDiff line change
@@ -57,13 +57,14 @@ class ItemComponent extends React.PureComponent<{
5757
onPress: (key: string) => void,
5858
onShowUnderlay?: () => void,
5959
onHideUnderlay?: () => void,
60+
textSelectable?: ?boolean,
6061
...
6162
}> {
6263
_onPress = () => {
6364
this.props.onPress(this.props.item.key);
6465
};
6566
render(): React.Node {
66-
const {fixedHeight, horizontal, item} = this.props;
67+
const {fixedHeight, horizontal, item, textSelectable} = this.props;
6768
const itemHash = Math.abs(hashCode(item.title));
6869
const imgSource = THUMB_URLS[itemHash % THUMB_URLS.length];
6970
return (
@@ -81,6 +82,7 @@ class ItemComponent extends React.PureComponent<{
8182
{!item.noImage && <Image style={styles.thumb} source={imgSource} />}
8283
<Text
8384
style={styles.text}
85+
selectable={textSelectable}
8486
numberOfLines={horizontal || fixedHeight ? 3 : undefined}>
8587
{item.title} - {item.text}
8688
</Text>

packages/rn-tester/js/examples/FlatList/FlatListExample.js

+22-1
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ type State = {|
5959
empty: boolean,
6060
useFlatListItemComponent: boolean,
6161
fadingEdgeLength: number,
62+
onPressDisabled: boolean,
63+
textSelectable: boolean,
6264
|};
6365

6466
class FlatListExample extends React.PureComponent<Props, State> {
@@ -74,6 +76,8 @@ class FlatListExample extends React.PureComponent<Props, State> {
7476
empty: false,
7577
useFlatListItemComponent: false,
7678
fadingEdgeLength: 0,
79+
onPressDisabled: false,
80+
textSelectable: true,
7781
};
7882

7983
_onChangeFilterText = filterText => {
@@ -161,6 +165,16 @@ class FlatListExample extends React.PureComponent<Props, State> {
161165
this.state.debug,
162166
this._setBooleanValue('debug'),
163167
)}
168+
{renderSmallSwitchOption(
169+
'onPress Disabled',
170+
this.state.onPressDisabled,
171+
this._setBooleanValue('onPressDisabled'),
172+
)}
173+
{renderSmallSwitchOption(
174+
'Text Selectable',
175+
this.state.textSelectable,
176+
this._setBooleanValue('textSelectable'),
177+
)}
164178
{renderSmallSwitchOption(
165179
'Use FlatListItemComponent',
166180
this.state.useFlatListItemComponent,
@@ -236,6 +250,12 @@ class FlatListExample extends React.PureComponent<Props, State> {
236250
data: state.data.concat(genItemData(100, state.data.length)),
237251
}));
238252
};
253+
_onPressCallback = () => {
254+
const {onPressDisabled} = this.state;
255+
const warning = () => console.log('onPress disabled');
256+
const onPressAction = onPressDisabled ? warning : this._pressItem;
257+
return onPressAction;
258+
};
239259
_onRefresh = () => Alert.alert('onRefresh: nothing to refresh :P');
240260
_renderItemComponent = () => {
241261
const flatListPropKey = this.state.useFlatListItemComponent
@@ -253,9 +273,10 @@ class FlatListExample extends React.PureComponent<Props, State> {
253273
item={item}
254274
horizontal={this.state.horizontal}
255275
fixedHeight={this.state.fixedHeight}
256-
onPress={this._pressItem}
276+
onPress={this._onPressCallback()}
257277
onShowUnderlay={separators.highlight}
258278
onHideUnderlay={separators.unhighlight}
279+
textSelectable={this.state.textSelectable}
259280
/>
260281
);
261282
},

0 commit comments

Comments
 (0)