web-dev-qa-db-ja.com

React Native-別の画面からのナビゲーション後にScrollViewを指定された場所にスクロールする方法

StackNavigatorを使用して現在の画面に移動したときに、ScrollViewに特定の位置にスクロールするように指示することはできますか?

2つの画面があります。メニューとアイテム。メニューは、各項目に1つずつ、ボタンのリストです。アイテム画面には、ScrollViewを使用して構築されたカルーセルと、各アイテムの画像と詳細な説明が含まれています。

メニュー画面でボタンをクリックすると、アイテム画面に移動し、ボタンが表すアイテムまで自動的にスクロールします。

StackNavigatorを使用するときにパラメーターを渡すことができると読みましたが、[アイテム]画面でそのパラメーターを読み取る方法がわかりません。

navigate('Items', { id: '1' })

これはReact Nativeで可能なことであり、どのようにすればよいですか?または、おそらく間違ったナビゲーターを使用していますか?

これは、私の2つの画面の機能が低下したバージョンです。

App.js:

const SimpleApp = StackNavigator({
    Menu: { screen: MenuScreen},
    Items: { screen: ItemScreen }
  }
);

export default class App extends React.Component {
  render() {
    return <SimpleApp />;
  }
}

Menu.js

export default class Menu extends React.Component {
    constructor(props){
        super(props)
        this.seeDetail = this.seeDetail.bind(this)
    }

    seeDetail(){
        const { navigate } = this.props.navigation;
        navigate('Items')
    }

    render(){
        <Button onPress={this.seeDetail} title='1'/>
        <Button onPress={this.seeDetail} title='2'/>
    }
}

Items.js

export default class Items extends React.Component {
  render(){
    let scrollItems = [] //Somecode that generates and array of items
    return (
      <View>
        <View style={styles.scrollViewContainer}>
          <ScrollView 
          horizontal
          pagingEnabled
          ref={(ref) => this.myScroll = ref}>
            {scrollItems}
          </ScrollView>
        </View>
      </View>
    )
  }  
}

P.S現在私は特にAndroid=をターゲットにしていますが、理想的にはクロスプラットフォームソリューションがある可能性があります。

8
davidx1

StackNavigatorを使用するときにパラメーターを渡すことができると読みましたが、[アイテム]画面でそのパラメーターを読み取る方法がわかりません。

これは、子コンポーネント内のthis.props.navigation.state.paramsにアクセスすることで実現されます。

Scrollview参照でscrollToを呼び出す最適なタイミングは、最初に割り当てられたときだと思います。あなたはすでにそれに参照を与えており、コールバック関数を実行しています-同時にscrollToも呼び出すようにそれを微調整します:

export default class Items extends React.Component {
  render(){
    let scrollItems = [] //Somecode that generates and array of items
    const {id} = this.props.navigation.state.params;

    return (
      <View>
        <View style={styles.scrollViewContainer}>
          <ScrollView 
          horizontal
          pagingEnabled
          ref={(ref) => {
            this.myScroll = ref
            this.myScroll.scrollTo() // !!
          }>
            {scrollItems}
          </ScrollView>
        </View>
      </View>
    )
  }  
}

そして、これがScrollViewsの代わりに FlatLists または SectionListsVirtualizedList から継承)を使用する理由です。 VirtualizedListには scrollToIndex 関数があり、より直感的です。 ScrollViewのscrollToは、xおよびyパラメーターを想定しています。つまり、スクロールする正確なスポットを計算する必要があります。つまり、各スクロールアイテムの幅に、スクロール先のアイテムのインデックスを掛けます。そして、各アイテムに含まれるパディングがある場合、それはより面倒になります。

6
Pat Needham

これはidの小道具にスクロールする例です。

import React, { Component } from 'react';
import { StyleSheet, Text, View, ScrollView, TouchableOpacity, Dimensions, Alert, findNodeHandle, Image } from 'react-native';
class MyCustomScrollToElement extends Component {

constructor(props) {
  super(props)
  this.state = {
  }
  this._nodes = new Map();
}
componentDidMount() {
  const data = ['First Element', 'Second Element', 'Third Element', 'Fourth Element', 'Fifth Element' ];
  data.filter((el, idx) => {
    if(el===this.props.id){
      this.scrollToElement(idx);
    }
  })

}
scrollToElement =(indexOf)=>{
  const node = this._nodes.get(indexOf);
  const position = findNodeHandle(node);
  this.myScroll.scrollTo({ x: 0, y: position, animated: true });
}
render(){
  const data = ['First Element', 'Second Element', 'Third Element', 'Fourth Element', 'Fifth Element' ];
  return (
  <View style={styles.container}>
    <ScrollView ref={(ref) => this.myScroll = ref} style={[styles.container, {flex:0.9}]} keyboardShouldPersistTaps={'handled'}>
      <View style={styles.container}>
          {data.map((Elm, idx) => <View ref={ref => this._nodes.set(idx, ref)} style={{styles.element}}><Text>{Elm}</Text></View>)}
      </View>
    </ScrollView>
  </View>
);

}

const styles = StyleSheet.create({
container: {
  flexGrow: 1,
  backgroundColor:"#d7eff9"
},
element:{
  width: 200,
  height: 200,
  backgroundColor: 'red'
}
});
export default MyCustomScrollToElement;

はい、これはscrollToメソッドを使用することで可能です- docs を参照してください。このメソッドはcomponentDidMountで呼び出すことができます。 this.myScroll.scrollTo(...)のように呼び出すには、参照が必要です。すべて同じタイプの項目の配列がある場合は、代わりにFlatListを使用する必要があることに注意してください。

1
vonovak

IOSの場合-ScrollViewcontentOffsetプロパティを使用する最良の方法。このようにして、最初は正しい位置にレンダリングされます。 scrollToを使用すると、最初のレンダリングの後に余分なレンダリングが追加されます。

Androidの場合-scrollTo以外のオプションはありません

0
Nick Avasiloy