ScrollViewを一番下までスクロールしたままにすることは可能ですか?


87

チャットのようなアプリの場合、ScrollView最新のメッセージが古いメッセージの下に表示されるため、コンポーネントを一番下までスクロールしたままにしておきます。のスクロール位置を調整できますScrollViewか?


3
私はreact-nativeについて何も知りませんが、ユーザーがチャットの履歴を表示するために上にスクロールしたい場合があることを覚えておいてください。新しいメッセージが到着したときにチャットがすでに一番下までスクロールされている場合にのみ、チャットをスクロールするようにしてください。
デビッド

これは良い考えです。この問題はここで追跡しています:github.com/facebook/react-native/issues/107
Eric

私はちょうど同様の質問に答えました、ここでそれをチェックしてください– stackoverflow.com/a/32652967/1541508
Kohver 2015

これはあなたの質問に答えますか?React Native ListViewの一番下までスクロールする方法
TripleM

回答:


165

以下のためにネイティブ0.41を反応させ、後に、あなたがこれを行うことができます内蔵のscrollToEnd方法:

<ScrollView
    ref={ref => {this.scrollView = ref}}
    onContentSizeChange={() => this.scrollView.scrollToEnd({animated: true})}>
</ScrollView>

3
反応ネイティブ0.55.4以降から、rootそれ以外の方法で使用する必要がありました。scrollToEndは未定義です。すなわちthis.scrollView.root.scrollToEnd
サイモン

4
現在reactnative 0.58.6を使用していて、root実際に使用すると未定義のエラーがスローされます。
ホセ・ベルナール

1
これは次のようになります:ref={ref => {this.scrollView = ref}}割り当てを返したくないので
Hampycalc

25

onContentSizeChangeを使用して、スクロールビューの下部Y(高さ)を追跡します

https://facebook.github.io/react-native/docs/scrollview.html#oncontentsizechange

var _scrollToBottomY

<ScrollView
    onContentSizeChange={(contentWidth, contentHeight)=>{
    _scrollToBottomY = contentHeight;
    }}>
</ScrollView>

次に、次のようなスクロールビューの参照名を使用します

this.refs.scrollView.scrollTo(_scrollToBottomY);

2
これにより、ビューが完全に一番下までスクロールされるため、ビューは基本的に表示されないことに注意してください(測定後に何かを追加した場合を除く)。コードはスクロール可能な領域の高さまでスクロールするので、これは理にかなっています。スクロール可能な領域をオーバーフローする子の高さではありません(おそらく、OPが望んでいたものではありません)。代わりにstackoverflow.com/a/39563193/1526986を参照してください。
xixixao 2017年

20

これが私が集めることができる最も簡単な解決策です:

 <ListView
ref={ref => (this.listView = ref)}
onLayout={event => {
    this.listViewHeight = event.nativeEvent.layout.height;
}}
onContentSizeChange={() => {
    this.listView.scrollTo({
        y: this.listView.getMetrics().contentLength - this.listViewHeight
    });
}}
/>;

1
これまたは他の同様の回答を使用すると、リスト内の項目が消えます(スクロールしすぎているように見えますが、確信が持てません)。少しスクロールすると、すべてが再表示され、スライドして戻ってきたように見えます(したがって、スクロールすぎるという理論です)。なぜそうなるのか明らかな考えはありますか?
tscizzle 2016

11

フックを使用できる関数コンポーネントを作成する人にとっては、

import React, { useRef } from 'react';
import { ScrollView } from 'react-native';

const ScreenComponent = (props) => {
  const scrollViewRef = useRef();
  return (
    <ScrollView
      ref={scrollViewRef}
      onContentSizeChange={() => scrollViewRef.current.scrollToEnd({ animated: true })}
    />
  );
};

5

このソリューションを試してください

xcode 10.0

RN:56.0.0

<ScrollView ref="scrollView"
             onContentSizeChange={(width,height) => this.refs.scrollView.scrollTo({y:height})}>  </ScrollView> // OR height -  width

なぜref=ですか?Web
開発の

5

2020年以降の誰かが、機能コンポーネントを使用してこれを実現する方法を考えている場合に備えて。これは私がした方法です:

ref={ref => scrollView = ref }
onContentSizeChange={() => scrollView.scrollToEnd({ animated: true })}>

注:userefを使用していることに言及できます。ほとんどのpplは、フックでrefを使用する方法を知りません。
ʎzɐɹƆ

はい。問題は、useRefフックを使用しなくてもうまくいったということです。しかし、正しい方法はそれを使用することです!そうです
Marlon Englemam

4

react-native-invertible-scroll-viewモジュールを使用してスクロール/リストビューを反転し、を呼び出すだけでref.scrollTo(0)一番下までスクロールできます。

モジュールをインストールします。

npm install --save react-native-invertible-scroll-view

次に、コンポーネントをインポートします。

import InvertibleScrollView from 'react-native-invertible-scroll-view';

次に、ScrollView:の代わりに次のJSXを使用します。

<InvertibleScrollView inverted
    ref={ref => { this.scrollView = ref; }}
    onContentSizeChange={() => {
        this.scrollView.scrollTo({y: 0, animated: true});
    }}
>
    { /* content */ }
</InvertibleScrollView>

これreact-native-invertible-scroll-viewは、ビューのコンテンツ全体を反転するために機能します。ビューの子も通常のビューとは逆の順序でレンダリングされることに注意してください。最初の子は下部に表示されます。


3

実際、@ Aniruddhaの回答は、使用"react-native": "0.59.8"this.scrollView.root.scrollToEndていて未定義であるため、機能しません。

しかし、私はそれを理解し、これは機能します this.scrollView.scrollResponderScrollToEnd({animated: true});

これを使用している場合、0.59.8またはそれ以降のバージョンを使用している場合、これは機能します。他の人が問題を起こさないように、この回答にバージョンを追加してください。

完全なコードはこちら

<ScrollView
    ref={ref => this.scrollView = ref}
    onContentSizeChange={(contentWidth, contentHeight)=>{        
        this.scrollView.scrollResponderScrollToEnd({animated: true});
    }}>
</ScrollView>

1

この方法は少しハッキーですが、私はより良い方法を見つけることができませんでした

  1. まず、ScrollViewに参照を追加します。
  2. 次に、ScrollViewタグを閉じる前に、ダミーのビューを追加します
  3. そのダミービューのy位置を取得します
  4. 下にスクロールしたいときはいつでもダミービューの位置にスクロールしてください

var footerY; //Y position of the dummy view
render() {    
    return (
      <View>
          <ScrollView 
          ref='_scrollView'>
            // This is where all the things that you want to display in the scroll view goes
            
            // Below is the dummy View
            <View onLayout={(e)=> {
              footerY = e.nativeEvent.layout.y;
              }}/>
          </ScrollView>
              
          //Below is the button to scroll to the bottom    
          <TouchableHighlight
            onPress={() => { this.refs._scrollView.scrollTo(footerY); }}>
            <Text>Scroll to Bottom</Text>
          </TouchableHighlight>
        
      </View>
    );
  }


これは、求められていたものではありません。これは、コンテンツが追加されたときにスクロールビューを一番下までスクロールしたままにするのではなく、タップすると一番下までスクロールします。とにかく、scrollToBottomこのようなアプローチはReactNativeの新しいバージョンでは廃止されています。
マークアメリー2017

1

これはあなたの質問に答えます:https//stackoverflow.com/a/39563100/1917250

コンテンツの高さからscrollViewの高さを引いたものを計算して、ページの一番下まで常にスクロールし続ける必要があります。


これは質問に対する正解です。いつスクロールを実行するかについて賢くすることができます。リンクの答えは、必要な数を取得する方法を示しています。特に、コンポーネントをリストに追加する場合、componentDidUpdateが呼び出されたときにコンテンツの高さにはコンポーネントが含まれないため、代わりにonContentSizeChangeをスクロールしてスクロールすることを忘れないでください。
xixixao 2017年

1

TypeScriptを使用する場合これを行う必要があります

interface Props extends TextInputProps { 
     scrollRef?: any;
}

export class Input extends React.Component<Props, any> {
     scrollRef;
constructor(props) {
    this.scrollRef = React.createRef();
}
<ScrollView
    ref={ref => (this.scrollRef = ref)}
    onContentSizeChange={() => {
    this.scrollRef.scrollToEnd();
    }}
>
</ScrollView>

0

私はしばらくこれと戦い、ついに私にとって本当にうまく機能する何かを思いついた。多くの人のように、私は.scrollToEnd無駄にしようとしました。私のために働いた解決策はonContentSizeChangeonLayout小道具と、「一番下までスクロールすること」が実際に何を意味するのかを視覚的に考えることの組み合わせでした。最後の部分は今では些細なことのように思えますが、理解するのに永遠にかかりました。

ScrollView固定の高さであるとすると、コンテンツの高さがコンテナの高さを超える場合、prevHeight(コンテンツの高さ)から(の固定の高さScrollView)を差し引いてオフセットを計算しましたcurrHeight。視覚的に想像できる場合は、y軸の違いまでスクロールして、コンテンツの高さをそのオフセットだけコンテナ上でスライドさせます。オフセットをインクリメントし、現在のコンテンツの高さを以前の高さにして、新しいオフセットを計算し続けました。

これがコードです。それが誰かを助けることを願っています。

class ChatRoomCorrespondence extends PureComponent {
  currHeight = 0;
  prevHeight = 0;
  scrollHeight = 0;

  scrollToBottom = () => {
    this.refs.scrollView.getScrollResponder().scrollResponderScrollTo({
      x: 0,
      y: this.scrollHeight,
      animated: true
    });
  };

  render() {
    return (
      <ScrollView
        style={Styles.container}
        ref="scrollView"
        onContentSizeChange={(w, h) => {
          this.currHeight = h;

          if (
            this.prevHeight > 0 &&
            this.currHeight - this.scrollHeight > this.prevHeight
          ) {
            this.scrollHeight += this.currHeight - this.prevHeight;
            console.log("--------------------------------------------");
            console.log("Curr: ", this.currHeight);
            console.log("Prev: ", this.prevHeight);
            console.log("Scroll: ", this.scrollHeight);
            this.prevHeight = this.currHeight;
            console.log("PREV: ", this.prevHeight);
            console.log("--------------------------------------------");

            this.scrollToBottom();
          }
        }}
        onLayout={ev => {
          // Fires once
          const fixedContentHeight = ev.nativeEvent.layout.height;
          this.prevHeight = fixedContentHeight;
        }}
      >
        <FlatList
          data={this.props.messages}
          renderItem={({ item }) => (
            <ChatMessage
              text={item.text}
              sender={item.sender}
              time={item.time}
              username={this.props.username}
            />
          )}
          keyExtractor={(item, index) => index.toString()}
        />
      </ScrollView>
    );
  }
}

0

答えるには遅すぎると思いますが、ハックが1つあります。を使用するFlatList場合は、inverted設定transform scaleにフォールバックするプロパティを有効にできます-1(これはScrollView...などの他のリストコンポーネントで受け入れられます)。FlatListデータを使用してレンダリングすると、常に下部に表示されます。


-1

スクロールビューのcontentOffsetプロパティをコンテンツの現在の高さに設定してみてください。

必要なことを達成するには、onScrollイベントの一部としてこれを行うことができます。ただし、これによりユーザーエクスペリエンスが低下する可能性があるため、新しいメッセージが追加された場合にのみこれを行う方がユーザーフレンドリーであることがわかる場合があります。


-1; いいえ。ここにある多くの回答と同様に、これには、単に下にスクロールするのではなく、すべてのコンテンツのScrollView下ににスクロールする効果があります。
マークアメリー2017

-1

私も同様の問題を抱えていましたが、このページを読んだ後(頭痛の種です!)、ListViewを反転してチャットアプリケーションのすべてを簡単にするこの非常に素晴らしいnpmパッケージを見つけました!!


-1; これは、以前にここに投稿された回答と重複しています(また、少し混乱しています。この質問はScrollView、 `ListView`ではなく、に関するものです)。
マークアメリー2017

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.