У меня есть элементы списка дел, которые можно разворачивать и сворачивать, нажимая соответствующую кнопку.
При нажатии на кнопку EXPAND регулируется высота анимированного ScrollView. От 0 до 100 при расширении и от 100 до 0 при сворачивании. Когда мы разворачиваем два списка-объекта одновременно, экран начинает мерцать.
Вот код одного единственного todo-элемента (он сокращен, значит кнопки DONE в нем нет):
import React, { useState, useRef, memo } from 'react';
import { Animated, Text, View, Button, ScrollView } from 'react-native';
import longText from '../data/data';
const ListObject = (props) => {
//Object Expand and Collapse feature
const expandValue = useRef(new Animated.Value(0)).current;
const [expandState, setExpand] = useState(false);
const expandAnimation = () => {
Animated.timing(expandValue, {toValue: 100, duration: 1000, useNativeDriver: false}).start();
setExpand(true);
}
const collapseAnimation = () => {
Animated.timing(expandValue, {toValue: 0, duration: 1000, useNativeDriver: false}).start();
setExpand(false);
}
return (
<View style = {{ margin: props.margin }}>
<View style = {{
flexDirection: 'row',
backgroundColor: 'grey',
borderRadius: 10,
}}>
<Button title='EXPAND' style = {{
flex: 1,
backgroundColor: 'blue',
}}
onPress = { expandState ? collapseAnimation : expandAnimation }
/>
</View>
<Animated.ScrollView style = {{
flex: 1,
paddingHorizontal: 40,
backgroundColor: 'grey',
borderRadius: 10,
maxHeight: expandValue
}}>
<Text>{ props.text }</Text>
</Animated.ScrollView>
</View>
);
}
export default memo(ListObject);
Вот код для приложения. Чтобы создать коллекцию всех элементов todo, я сопоставляю список и назначаю ключ каждому элементу:
mport React, { useRef, useState } from 'react';
import { Animated, StyleSheet, ScrollView, Text, View, SafeAreaView, Button } from 'react-native';
import longText from './src/data/data';
import ListObject from './src/components/list-object'
const styles = StyleSheet.create({
safeContainer: {
flex: 1.2
},
headerContainer: {
flex: 0.2,
flexDirection: 'column',
justifyContent: 'center',
backgroundColor: 'lightblue',
},
headerFont: {
fontSize: 50,
textAlign: 'center',
},
scrollContainer: {
flex: 1
}
});
const App = () => {
const numbers = [1,2,3,4,5,6,7,8,9];
const listItems = numbers.map((number) =>
<ListObject key = {number.toString()} margin = {10} headerText='I am the header of the to-do element' text = {longText} />
)
return (
<SafeAreaView style = { styles.safeContainer } >
<View style = { styles.headerContainer }>
<Text style = { [styles.headerFont] }>LIST MAKER</Text>
</View>
<ScrollView style = { styles.scrollContainer }>
{listItems}
</ScrollView>
</SafeAreaView>
);
};
export default App;
Я не ожидал мерцания. Мерцание появляется также на моем физическом устройстве Android. Я искал похожие проблемы и проверял другие библиотеки, как они это реализуют.
Для этого можно использовать react-native-collapsible
import Accordion from 'react-native-collapsible/Accordion';
const [activeSections, setActiveSessions] = useState([])
const _updateSections = (activeSections) => {
setActiveSessions(activeSections.includes(undefined) ? [] : activeSections)
}
<Accordion
sections = {data}
activeSections = {activeSections}
duration = {400}
renderHeader = {_renderHeader}
renderContent = {_renderContent}
onChange = {_updateSections}
touchableComponent = {TouchableOpacity}
renderAsFlatList = {true}
expandMultiple = {true}
/>
Для лучшей производительности и плавного опыта используйте этот.
Вы можете найти весь пример здесь github.com/oblador/react-native-collapsible/blob/master/Example/…
Ошибку нашел сам, это ошибка новичка.
Вместо того, чтобы управлять состоянием компонента в самом компоненте, мне пришлось поднимать состояние до родителя.
Вот ссылка на обучающий документ ReactJS.
Спасибо за ваш ответ. Я хотел бы реализовать это самостоятельно. Я начал с реакции неделю назад и хотел бы понять детали.