-
Notifications
You must be signed in to change notification settings - Fork 24.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Inverted FlatList accessibility order #30373
Comments
are there any updates for this ticket ? |
I had the same problem. The VirtualizedList implementation seems to styling react-native/Libraries/Lists/VirtualizedList.js Lines 864 to 868 in b28fa2d
I don't understand the implementation context, but changing this to |
unfortunately this will "break" scroll and infinite loading pagination |
We're interested in getting this issue fixed and willing to compensate to do so. View issue Expensify/App#1341 |
Is it possible to add the "Accessibility" tag to this issue? Not sure how closely the task board is still being tracked but this is a pretty fundamental issue for Android in an important control. This breaks Android screen reader support in any inverted list which is common e.g. for chat scenarios. |
I had the same problem. Are there any updates for this ticket ? |
One possible solution would be not using transform to visually invert the list. Android/iOS Solution
Javascript Solution tasks - planning a solution for the issue
|
FlatList inverted - The accessibility focus order is from top to bottom, but applying FlatList inverted property makes the order swap to bottom to top
Example Inverted set to false
inverted_false_480.mp4Inverted set to true
inverted_true_480.mp4Manually inverted FlatList - does not cause issues with TalkBack
https://snack.expo.dev/@fabrizio.bertoglio/manually-inverting-flatlist invert_manually_in_js_480.mp4 |
Evaluate the performance implications of using transform vs JavaScript vs Native Solution.
Transform
Reverse Array instead of using Transform |
implement scroll to top optimization for inverted FlatList
The normal FlatList keeps the first initialNumToRender items always rendered (first page) and immediately renders the items starting at this initial index. The same optimization needs to be implemented for inverted FlatList.
if there is a react-native/Libraries/Lists/VirtualizedList.js Lines 944 to 955 in 3da3d82
how initialScrollIndex changes the items rendered on the screen
react-native/Libraries/Lists/VirtualizedList.js Lines 719 to 729 in 873ff0c
the items between first and last are added in the cells variables which is called on render react-native/Libraries/Lists/VirtualizedList.js Lines 816 to 846 in 873ff0c
In the CellRenderer class onLayout is undefined if we use getItemLayout. There is no need to use onLayout to calculate the cell height/width. react-native/Libraries/Lists/VirtualizedList.js Lines 2102 to 2108 in 873ff0c
|
use initialScrollIndex to start from bottom, but keep scrollToBottom optimization
the android ScrollView widget method fullScroll allow to start the ScrollView from the Button https://stackoverflow.com/a/30224427/7295772 my current solution uses solved with fabOnReact@5b2cb47 scroll to top optimization (from main) react-native/Libraries/Lists/VirtualizedList.js Lines 944 to 955 in 3da3d82
scroll top bottom optimization (from pr) |
nested FlatList with different orientation does not scroll to the end when inverted
nested FlatList with different orientation does not scroll to the end when inverted scrollToEnd does not work because this._scrollRef is null
the scrollToEnd does not work with nested FlatList with different orientation (children is horizontal) react-native/Libraries/Lists/VirtualizedList.js Lines 520 to 525 in 06fb1dd
The ref is set here react-native/Libraries/Lists/VirtualizedList.js Lines 1132 to 1134 in 06fb1dd
using componentDidMount fixes this issue, but this.scrollToEnd does not correctly work. The offset is 0 when using scrollToEnd. react-native/Libraries/Lists/VirtualizedList.js Lines 391 to 397 in 06fb1dd
seems caused by this line react-native/Libraries/Lists/VirtualizedList.js Line 1573 in 3da3d82
when use trigger scrollToEnd, frame.offset is 0
if you wait 1 second, _onContentSize changes and frame.offset is valorized (for ex. 1200 px). Related https://stackoverflow.com/a/72906476/7295772 https://stackoverflow.com/questions/44418990/using-a-flatlist-with-scrolltoend Tasks
scrollToEnd does not work:
Understand why frame.offset and frame.length are equal to 0 instead of 1300:
Low Priority
|
main branch - scrollToEnd does not work for nested FlatList with different orientations (horizontal/vertical)
In the example above the FlatList is not inverted.
SourceCode of the example
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
} from 'react-native';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb',
title: 'Fourth Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97676',
title: 'Fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e27234',
title: 'Sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29234',
title: 'Seven Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571429234',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-115571429234',
title: 'Nine Item',
},
{
id: '58694a0f-3da1-471f-bd96-1155h1429234',
title: 'Ten Item',
},
];
const Item = ({title}) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({item}) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;
const renderFlatList = ({item}) => <NestedFlatList item={item} />;
function NestedFlatList(props) {
let flatlist = React.useRef(0);
React.useEffect(() => {
// flatlist.scrollToOffset({offset: 697.5, animated: false});
flatlist.scrollToEnd({animated: false});
}, []);
return (
<View>
<Text>Flatlist {props.item}</Text>
<FlatList
// inverted={true}
ref={ref => (flatlist = ref)}
renderItem={renderItem}
data={DATA}
/>
</View>
);
}
const FlatList_nested = () => {
let flatlist = React.useRef(0);
React.useEffect(() => {
// flatlist.scrollToOffset({offset: 1300, animated: false});
// flatlist.scrollToEnd({animated: false})
}, []);
return (
<FlatList
ref={ref => (flatlist = ref)}
data={[1]}
horizontal
inverted={false}
renderItem={renderFlatList}
keyExtractor={item => item.toString()}
/>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Nested',
name: 'nested',
description: 'Test inverted prop on FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample); Screen.Recording.2022-07-08.at.09.34.43.mov |
Main - Normal FlatList behaviour scroll position adding new items
sourcecode example
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from 'react-native';
const Item = ({title}) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({item}) => <Text style={styles.item}>{item.title}</Text>;
const ITEM_HEIGHT = 50;
const renderFlatList = ({item}) => <NestedFlatList item={item} />;
const FlatList_nested = () => {
let flatlist = React.useRef(null);
const [items, addItem] = React.useState(DATA);
return (
<>
<Button
title="add an item"
onPress={() => addItem([...items, {title: 'new item'}])}
/>
<FlatList
// inverted={true}
horizontal
onContentSizeChange={() => flatlist.scrollToEnd()}
ref={ref => (flatlist = ref)}
renderItem={renderItem}
data={items}
/>
</>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Nested',
name: 'nested',
description: 'Test inverted prop on FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample);
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb',
title: 'Fourth Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97676',
title: 'Fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e27234',
title: 'Sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29234',
title: 'Seven Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571429234',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-115571429234',
title: 'Nine Item',
},
{
id: '58694a0f-3da1-471f-bd96-1155h1429234',
title: 'Ten Item',
},
]; Screen.Recording.2022-07-08.at.12.07.38.movMain - Inverted FlatList behaviour scroll position adding new items
sourcecode example
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import React from 'react';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from 'react-native';
const Item = ({title}) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({item}) => <Text style={styles.item}>{item.title}</Text>;
const ITEM_HEIGHT = 50;
const renderFlatList = ({item}) => <NestedFlatList item={item} />;
const FlatList_nested = () => {
let flatlist = React.useRef(null);
const [items, addItem] = React.useState(DATA);
return (
<>
<Button
title="add an item"
onPress={() => addItem([...items, {title: 'new item'}])}
/>
<FlatList
inverted={true}
horizontal
onContentSizeChange={() => flatlist.scrollToEnd()}
ref={ref => (flatlist = ref)}
renderItem={renderItem}
data={items}
/>
</>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Nested',
name: 'nested',
description: 'Test inverted prop on FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample);
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb',
title: 'Fourth Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97676',
title: 'Fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e27234',
title: 'Sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29234',
title: 'Seven Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571429234',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-115571429234',
title: 'Nine Item',
},
{
id: '58694a0f-3da1-471f-bd96-1155h1429234',
title: 'Ten Item',
},
]; Screen.Recording.2022-07-08.at.12.12.07.movBranch - Inverted FlatList behaviour scroll position adding new items
sourcecode example
import React from "react";
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from "react-native";
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Item",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Item",
},
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb",
title: "Fourth Item",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97676",
title: "Fifth Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e27234",
title: "Sixth Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29234",
title: "Seven Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571429234",
title: "Eight Item",
},
{
id: "58694a0f-3da1-471f-bd96-115571429234",
title: "Nine Item",
},
{
id: "58694a0f-3da1-471f-bd96-1155h1429234",
title: "Ten Item",
},
];
const Item = ({ title }) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({ item }) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;
const renderFlatList = ({ item }) => (
<NestedFlatList item={item} />
);
function NestedFlatList(props) {
const [items, addItem] = React.useState(DATA);
return (
<View>
<Button
title="add an item"
onPress={() => addItem([...items, {title: 'new item'}])}
/>
<Text>Flatlist</Text>
<FlatList
style={{height: 400}}
inverted={true}
renderItem={renderItem} data={items} />
</View>
)
}
const FlatList_nested = () => {
let flatlist = React.useRef(0);
return (
<FlatList
ref={(ref) => flatlist = ref}
data={[1,2,3]}
horizontal
renderItem={renderFlatList}
keyExtractor={(item) => item.toString()}
/>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: "#f9c2ff",
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Nested',
name: 'nested',
description: 'nested FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample); Screen.Recording.2022-07-08.at.12.42.42.mov |
addresses issues explained in facebook#30373 (comment) handles cases when adding new item to inverted flatlist (flatlist has to scroll up to the new item) test cases facebook#30373 (comment)
Testing TalkBack navigation in an inverted nested Flatlist
sourcecode example
import React from "react";
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from "react-native";
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb28ba",
title: "First Item",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97f63",
title: "Second Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29d72",
title: "Third Item",
},
{
id: "bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb",
title: "Fourth Item",
},
{
id: "3ac68afc-c605-48d3-a4f8-fbd91aa97676",
title: "Fifth Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e27234",
title: "Sixth Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571e29234",
title: "Seven Item",
},
{
id: "58694a0f-3da1-471f-bd96-145571429234",
title: "Eight Item",
},
{
id: "58694a0f-3da1-471f-bd96-115571429234",
title: "Nine Item",
},
{
id: "58694a0f-3da1-471f-bd96-1155h1429234",
title: "Ten Item",
},
];
const Item = ({ title }) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({ item }) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;
const renderFlatList = ({ item }) => (
<NestedFlatList item={item} />
);
function NestedFlatList(props) {
const [items, setItems] = React.useState(DATA);
return (
<View>
<Button
title="add an item"
onPress={() => setItems([...items, {title: 'new item'}])}
/>
<Button
title="remove an item"
onPress={() => {
const newItems = [...items];
newItems.splice(items.length - 1, 1)
setItems(newItems);
}}
/>
<Text>Flatlist</Text>
<FlatList
style={{height: 400}}
inverted={true}
renderItem={renderItem} data={items} />
</View>
)
}
const FlatList_nested = () => {
let flatlist = React.useRef(0);
return (
<FlatList
ref={(ref) => flatlist = ref}
data={[1,2,3]}
horizontal
renderItem={renderFlatList}
keyExtractor={(item) => item.toString()}
/>
);
};
const styles = StyleSheet.create({
item: {
backgroundColor: "#f9c2ff",
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Nested',
name: 'nested',
description: 'nested FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample); Screen.Recording.2022-07-08.at.14.49.01.mov |
iOS - Test not-nested inverted FlatList
RecordIt-D03B66C7-7232-40C7-A557-9FBB1AE9247D.mp4iOS - Test nested inverted FlatList
RecordIt-B49349EC-626C-4311-8409-DAA8EA636225.mp4 |
nested horizontal inverted flatlist starts scrolled to the end
Screen.Recording.2022-07-11.at.21.45.29.mov |
children should not be inverted if nested in a FlatList with prop inverted
Screen.Recording.2022-07-11.at.21.52.53.mov |
FlatList automatically scrolls after prepending new items #25239 (Android)
Documented in #25239. The issue already present in main. click to open example
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import * as React from 'react';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from 'react-native';
const DATA = [
{
id: 1,
title: 'First Item',
},
{
id: 2,
title: 'Second Item',
},
{
id: 3,
title: 'Third Item',
},
{
id: 4,
title: 'Fourth Item',
},
{
id: 5,
title: 'Fifth Item',
},
{
id: 6,
title: 'Sixth Item',
},
{
id: 7,
title: 'Seven Item',
},
{
id: 8,
title: 'Eight Item',
},
{
id: 9,
title: 'Nine Item',
},
{
id: 10,
title: 'Ten Item',
},
];
const Item = ({title}) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({item}) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;
function NestedFlatList(props) {
const [items, setItems] = React.useState(DATA);
const [index, setIndex] = React.useState(11);
return (
<View>
<Button
title="add an item"
onPress={() => {
setItems([{id: index, title: 'new item'}, ...items]);
setIndex(index + 1);
}}
/>
<Button
title="remove an item"
onPress={() => {
const newItems = [...items];
newItems.splice(items.length - 1, 1);
setItems(newItems);
}}
/>
<Text>Flatlist</Text>
<FlatList
style={{height: 400}}
keyExtractor={(item, index) => item.id}
renderItem={renderItem}
data={items}
/>
</View>
);
}
const FlatList_nested = (): React.Node => {
return <NestedFlatList />;
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Inverted',
name: 'inverted',
description: 'Test inverted prop on FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample); Main Branch Screen.Recording.2022-07-12.at.22.32.15.movPR Branch Screen.Recording.2022-07-12.at.23.10.27.mov |
FlatList does not scroll after appending new items (Android)
This is the expected behavior on Android. click to open sourcecode
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import * as React from 'react';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from 'react-native';
const DATA = [
{
id: 1,
title: 'First Item',
},
{
id: 2,
title: 'Second Item',
},
{
id: 3,
title: 'Third Item',
},
{
id: 4,
title: 'Fourth Item',
},
{
id: 5,
title: 'Fifth Item',
},
{
id: 6,
title: 'Sixth Item',
},
{
id: 7,
title: 'Seven Item',
},
{
id: 8,
title: 'Eight Item',
},
{
id: 9,
title: 'Nine Item',
},
{
id: 10,
title: 'Ten Item',
},
];
const Item = ({title}) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({item}) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;
function NestedFlatList(props) {
const [items, setItems] = React.useState(DATA);
const [index, setIndex] = React.useState(11);
return (
<View>
<Button
title="add an item"
onPress={() => {
setItems([...items, {id: index, title: 'new item'}]);
setIndex(index + 1);
}}
/>
<Button
title="remove an item"
onPress={() => {
const newItems = [...items];
newItems.splice(items.length - 1, 1);
setItems(newItems);
}}
/>
<Text>Flatlist</Text>
<FlatList
style={{height: 400}}
keyExtractor={(item, index) => item.id}
renderItem={renderItem}
data={items}
/>
</View>
);
}
const FlatList_nested = (): React.Node => {
return <NestedFlatList />;
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Inverted',
name: 'inverted',
description: 'Test inverted prop on FlatList',
render: () => <FlatList_nested />,
}: RNTesterModuleExample); Main Screen.Recording.2022-07-12.at.22.46.44.movBranch Screen.Recording.2022-07-12.at.23.13.25.mov |
when items are appended to the end of the list, the view needs to stay in the same position
Related to #34141 (comment) #34141 (comment)
Option 2) Find the x/y coordinate and scroll to that position after the item is appended Option 3) Store the x,y coordinates of each child to trigger scrollToOffeset(first.coodinates.x) Option 4) Support for ScrollView.maintainVisibleContentPosition on Android Option 5) Use not optimized scrollToItem(first) only when TalkBack is Enabled |
Option 2) Find the x/y coordinate and scroll to that position after the item is appended
Draft solution only using JavaScript. It is not optimized but will be useful to implement the solution in Java/Javascript step by step. click to open sourcecode of the example
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* @flow strict-local
* @format
*/
import * as React from 'react';
import {useState, useRef} from 'react';
import type {RNTesterModuleExample} from '../../types/RNTesterTypes';
import {
SafeAreaView,
View,
FlatList,
StyleSheet,
Text,
StatusBar,
Button,
} from 'react-native';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb8bbb',
title: 'Fourth Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97676',
title: 'Fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e27234',
title: 'Sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29234',
title: 'Seven Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571429234',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-115571429234',
title: 'Nine Item',
},
{
id: '58694a0f-3da1-471f-bd96-1155h1429234',
title: 'Ten Item',
},
];
const Item = ({title}) => (
<Text style={[styles.item, styles.title]}>{title}</Text>
);
const renderItem = ({item}) => <Item title={item.title} />;
const ITEM_HEIGHT = 50;
const renderFlatList = ({item}) => <NestedFlatList item={item} />;
function NestedFlatList(props) {
let flatlist = useRef(null);
let bottomY = 0;
const [bottomHeight, setBottomHeight] = useState(0);
const [height, setHeight] = useState(undefined);
const [items, setItems] = useState(DATA);
const [disabled, setDisabled] = useState(false);
const [index, setIndex] = useState(DATA.length + 1);
const [resetScrollPosition, setResetScrollPosition] = useState(false);
React.useEffect(() => {
if (resetScrollPosition && bottomHeight && flatlist) {
flatlist.scrollToOffset({
offset: height - bottomHeight,
animated: false,
});
setResetScrollPosition(false);
}
}, [resetScrollPosition, bottomHeight, height]);
return (
<View>
<Button
title="append an item"
onPress={() => {
setBottomHeight(bottomY);
setItems([...items, {title: `new item ${index}`}]);
setIndex(index + 1);
}}
/>
<Button
title="prepend an item"
onPress={() => {
setItems([{title: `new item ${index}`}, ...items]);
setIndex(index + 1);
}}
/>
<Button
title="remove an item"
onPress={() => {
const newItems = [...items];
newItems.splice(items.length - 1, 1);
setItems(newItems);
}}
/>
<Text>Flatlist</Text>
<FlatList
ref={ref => (flatlist = ref)}
inverted
style={{height: 400}}
renderItem={renderItem}
data={items}
onScroll={e => {
const scrollY = e.nativeEvent.contentOffset.y;
const height = e.nativeEvent.contentSize.height;
bottomY = height - scrollY;
}}
onContentSizeChange={(width, height) => {
setHeight(height);
setResetScrollPosition(true);
}}
/>
</View>
);
}
const FlatList_nested = (): React.Node => {
return <NestedFlatList />;
};
const styles = StyleSheet.create({
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 16,
},
});
export default ({
title: 'Inverted',
name: 'inverted',
description: 'Test inverted prop on FlatList',
render: () => <FlatList_nested />,
} video of the test case - with fix to keep scroll position
2022-07-15.13-09-15.mp4video of the test case - without fix
2022-07-15.13-39-56.mp4
|
…s to stay in the same position it works when _onScroll is triggered: - the user scroll the list - the bottomY state is updated - appending item to the list will not change position still does not work when the user appends a second item Related facebook#30373 (comment) Was implemented on a Javascript example above, which had similar issues - did not work if no scroll was triggered - did not work if triggering many times fast appends of items Reason for this issues needs to be investigated, but the solution only be for TalkBack users to avoid using transform
|
…y in the same position >when items are appended to the end of the list, the view needs to stay in the same position This functionality will be introduced with a separate PR with the following improvement (OPTIONAL) instead of using onScroll to save scroll x/y coordinates, use the screenreaderFocus facebook#30373 (comment) Related facebook#34141 (comment)
- Import improvements from PR facebook#26444 _maybeCallOnEndReached: https://github.com/facebook/react-native/pull/26444/files#diff-7481ec8ed5532798b075df637e805a8e439807aa2ce671208c24068c286361e8L1374-R1413 https://github.com/facebook/react-native/blob/2d3f6ca9801ef92b446458a2efc795db4ec17021/Libraries/Lists/VirtualizedList.js#L1372-L1414 - Additional check _hasDoneFirstScroll for maybeCallOnEndReached (added in onScroll callback) - Add improved logic start/endPositionReached and isScrollingForward - Add threeshold instead of 2 - Use default threeshold 30 for iOS - Add other improvements from method _maybeCallOnEndReached
I quote Eric Rozell #34141 (comment)
Now that PR Add fabric support for maintainVisibleContentPosition on Android #35994 is merged, I can build the above functionalities for the inverted flatlist. Issues Expensify/App#1341 and Expensify/App#3381 were closed. |
This issue is stale because it has been open 180 days with no activity. Remove stale label or comment or this will be closed in 7 days. |
This issue was closed because it has been stalled for 7 days with no activity. |
@fabOnReact yes, we would love if this was re-opened and worked on! This is still actively affecting our project. |
Any updates? @react-native-bot |
Description
In normal FlatList the accessibility focus order is from top to bottom but applying inverted property makes the order swap to bottom to top. This breaks the accessibility navigation flow as it is assumed that it should go from top of the screen to the bottom.
React Native version:
RN 0.63 and Android 9 with enabled TalkBack
Steps To Reproduce
Use FlatList component like
<FlatList ... inverted={ true } />
Expected Results
The order of items should stay inverted but the accessibility order should be maintained top to bottom.
Snack, code example, screenshot, or link to a repository:
Please provide a Snack (https://snack.expo.io/), a link to a repository on GitHub, or provide a minimal code example that reproduces the problem.
You may provide a screenshot of the application if you think it is relevant to your bug report.
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve
The text was updated successfully, but these errors were encountered: