Анимация одного представления на основе нескольких ScrollView (s)
Я работаю над приложением, в котором я пытаюсь Анимировать View
на основе прокрутки. Позиция нескольких ScrollView
s.
Вот как выглядит экран.
![Экран профиля]()
Вышеуказанный экран имеет 2 части
- Компонент
View
сверху
- Компонент
TabNavigator
в нижней части
каждая вкладка в TabNavigator
имеет в ней ScrollView
(в этом случае 2, но может быть больше). Я хочу достичь, чтобы свернуть View
, когда пользователь прокручивает вниз и расширяет его, когда пользователь прокручивается вверх.
На одной вкладке у меня все было хорошо, она работала именно так, как я этого хотел, но проблема возникла, когда я добавил вторую вкладку.
Проблема
Когда я немного прокручиваю вкладку 1 и перехожу на tab2 и прокручиваю ее, она становится отрывистой. см. GIF, чтобы понять, что я пытаюсь сказать
![React Native Animation Jerk]()
Update
Проверьте эту перекуску на expo.io, чтобы увидеть проблему в режиме реального времени
snack.expo.io/SytBkdBAW
Что я пробовал
App.js
export default class App extends Component {
constructor (props) {
super(props)
this.state = {
/* omitted - not related */
scrollY: new Animated.Value(0)
}
}
render () {
let translateY = this.state.scrollY.interpolate({
inputRange: [0, 600],
outputRange: [0, -290],
extrapolate: 'clamp'
});
let TabsTranslateY = this.state.scrollY.interpolate({
inputRange: [0, 600],
outputRange: [0, -290],
extrapolate: 'clamp'
});
return (
<View style={styles.container}>
<Animated.View style={{transform: [{translateY: translateY}], overflow: 'hidden'}}>
<Text style={styles.welcome}>
Welcome to React Native!!
</Text>
<Text style={styles.time}>
{this.state.hour} : {this.state.minute}
</Text>
<TouchableOpacity onPress={() => { /* omitted */ }} style={styles.button}><Text style={styles.buttonText}>Set Time</Text></TouchableOpacity>
</Animated.View>
<Animated.View style={{
flex: 0,
transform: [{translateY: TabsTranslateY}],
height: Dimensions.get('window').height
}}>
<Tabs removeClippedSubviews={false} screenProps={{animatedScrollY: this.state.scrollY}}/>
</Animated.View>
</View>
)
}
}
const styles = StyleSheet.create({/* omitted styles*/})
Home.js(Tab1)
/* omitted imports */
export default class Home extends Component {
/* omitted navigation options */
constructor (props) {
super(props)
this.state = {
scrollY: this.props.screenProps.animatedScrollY
}
}
render () {
return (
<View>
<Animated.ScrollView onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: this.state.scrollY}}}],
{useNativeDriver: true}
)} scrollEventThrottle={16}>
{Array(90).fill().map((v, i) => {
return <Text key={i}
style={{flex: 1, backgroundColor: '#333', padding: 20, marginVertical: 10, color: 'white'}}>Item
#{i + 1}</Text>
})}
</Animated.ScrollView>
</View>
)
}
}
Photos.js(Tab2)
/* omitted imports */
export default class Photos extends Component {
/* omitted navigation options */
constructor (props) {
super(props)
this.state = {
PhotosScrollY: this.props.screenProps.animatedScrollY
}
}
render () {
return (
<Animated.ScrollView onScroll={Animated.event(
[{nativeEvent: {contentOffset: {y: this.state.PhotosScrollY}}}],
{useNativeDriver: true}
)} scrollEventThrottle={16}>
<View style={{flex: 1,}}>
{Array(90).fill().map((v, i) => {
return <View key={i} style={/* omitted */}>
<Text style={/* omitted */}>
Photo #{i + 1}
</Text>
</View>
})}
</View>
</Animated.ScrollView>
)
}
}
Я не уверен, как преодолеть эту проблему. Любые предложения и решения приветствуются.
Спасибо.
Ответы
Ответ 1
Попробуйте использовать Animated.add()
Итак, вам нужно App
const tab1ScrollY = new Animated.Value(0)
const tab2ScrollY = new Animated.Value(0)
const scrollY = Animated.add(tab1ScrollY,tab2ScrollY)
scrollY
это смещение tab1 scroll
+ tab2 scroll
Ответ 2
Я столкнулся с этой проблемой. Я попытался решить это так. (Оптимизация этого еще...)
<ParentComponent>
<CollapsibleHeader/>
<TabNavigator/>
</ParentComponent>
ScrollState лежит в родительском компоненте, а вкладки внутри TabNavigator имеют scrollView.
Я обновляю состояние в родительском компоненте с помощью обратного вызова после привязки события Animation.
Поэтому всякий раз, когда вы перемещаетесь между двумя вкладками, состояние лежит в родительском компоненте и обновляется из другого места.
Может быть, это может вам помочь.
ПРИМЕЧАНИЕ. Все еще оптимизируя его.
--------- -------- Edit
Родительский компонент:
Состояние: scrollY: new Animated.Value(0)
componentDidMount(){
binding event.
}
componentWillUnmount(){
Unbind event.
}
onScrollEventCaptured(){
(update parent state and send it to <CollapsibleHeader/>)*
}
Вкладка 1:
Это локальное состояние. (Оптимизация этой части)
, scrollY: new Animated.Value(0)
Имеет ListView
onScroll функция в ListView:
onScroll={Animated.event([{
nativeEvent: {
contentOffset: {
y: this.state.scrollY
}
}
}], {
listener: (event) => {
AppEvents.fire("topBar", this.state.scrollY);
},
})}
AppEvents.fire() - это событие, которое записывается в Parent.
(Захваченное событие затем устанавливает состояние, затем передается в качестве опоры, которое на самом деле оживляет.) *
Для вкладки 2:
То же, что вкладка 1.
* Оба одинаковы.
По-прежнему выполняем оптимизационную работу. Анимация для меня немного вялена в iOS, но она отлично смотрится в приложении для iOS. Android без слов повсюду его отрывистый.
Ответ 3
Я никогда не пользовался реакцией, но я определенно могу сказать, почему у вас есть эта проблема. Я использовал инструмент отладки, и я понял, что, когда вы нажимали на вкладку и приложение, каждый раз вызывайте эту часть кода:
let translateY = this.state.scrollY.interpolate({
inputRange: [0, 600],
outputRange: [0, -290],
extrapolate: 'clamp'
});
let TabsTranslateY = this.state.scrollY.interpolate({
inputRange: [0, 600],
outputRange: [0, -290],
extrapolate: 'clamp'
});
где this.state.scrollY = new Animated.Value(0)
все время.
В основном, это означает, что когда вы нажмете на вкладку и начнете прокрутку, она будет прокручиваться с 0. Вам нужно найти решение, помните предыдущее состояние Animated.Value или измените диапазоны ввода/вывода для анимации.
Вот пример того, как получить щелчок по вкладке из App.js:
<Tabs removeClippedSubviews={false} screenProps={{animatedScrollY: this.state.scrollY}}
onNavigationStateChange={(prevState, currentState,action) => {
console.log(currentState);
}}
/>
Надеюсь, это поможет вам.
Ответ 4
какое-нибудь обновление для этой проблемы? пожалуйста, отредактируйте snack.expo.io/SytBkdBAW и поделитесь обновленной ссылкой. Спасибо