Подтвердить что ты не робот

Анимация одного представления на основе нескольких 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>
    )
  }
}

Я не уверен, как преодолеть эту проблему. Любые предложения и решения приветствуются.

Спасибо.

4b9b3361

Ответ 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 и поделитесь обновленной ссылкой. Спасибо