Bir ScrollView’u aşağıya kaydırmak mümkün müdür?


90

Sohbet benzeri bir uygulama için, bir ScrollViewbileşeni en alta kaydırmak istiyorum çünkü en yeni mesajlar eski mesajların altında görünüyor. A'nın kaydırma konumunu ayarlayabilir miyiz ScrollView?


3
React-native hakkında hiçbir şey bilmiyorum, ancak bazen kullanıcıların sohbet geçmişini görüntülemek için yukarı kaydırmak istediklerini unutmayın. Yeni bir mesaj geldiğinde sadece sohbet zaten en alta kaydırılmışsa sohbeti kaydırdığınızdan emin olun.
David

Bu iyi bir fikir. Bu sorunu burada takip ediyoruz: github.com/facebook/react-native/issues/107
Eric Vicenti

Sadece benzer bir soru cevap, buradan kontrol edin - stackoverflow.com/a/32652967/1541508
Kohver

Bu sorunuzu yanıtlıyor mu? React Native ListView
TripleM

Yanıtlar:


166

For Native 0,41 Tepki ve daha sonra , sen ile yapabilirsiniz yerleşik scrollToEndyöntemiyle:

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

3
Yerel 0.55.4 ve üstü react'ten rootbaşka türlü kullanmak zorunda kaldım , scrollToEnd tanımsız. yanithis.scrollView.root.scrollToEnd
Simon

4
Şu anda react native 0.58.6 kullanılıyor ve kullanmak rootaslında tanımsız bir hata veriyor .
Jose Bernhardt

1
Bu ref={ref => {this.scrollView = ref}}, ödevi geri vermek istemediğiniz için mi olmalı?
Hampycalc

26

Kaydırma görünümünün (yükseklik) alt Y'sini takip etmek için onContentSizeChange'i kullanın

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

var _scrollToBottomY

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

sonra kaydırma görünümünün ref adını kullanın

this.refs.scrollView.scrollTo(_scrollToBottomY);

2
Bunun görünümü tamamen alta kaydırdığını ve böylece görünümün esasen görünmediğini unutmayın (ölçümden sonra ona bir şey eklemediğiniz sürece). Bu mantıklıdır, çünkü kod kaydırılabilir alandan taşan çocukların yüksekliğine değil (muhtemelen OP'nin istediği DEĞİL) kaydırılabilir alanın yüksekliğine kaydırılır. Bunun yerine stackoverflow.com/a/39563193/1526986 adresine bakın .
xixixao

21

İşte toplayabileceğim en basit çözüm:

 <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
Bu veya benzeri yanıtlar kullandığınızda, listedeki öğeleri (o kaydırma oluyor gibi görünüyor kaybolur yapar çok uzakta, ama emin olamaz). Biraz kaydırmak, her şeyin yeniden ortaya çıkmasını sağlar ve sanki tekrar görünüme kayıyormuş gibi görünür (bu nedenle çok ileri kaydırma teorisi). Bunun neden olabileceği konusunda açık bir fikriniz var mı?
tscizzle

16

Hook kullanabilen işlev bileşeni yazan herkes için,

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 })}
    />
  );
};

1
basit ve zarif. mükemmel istediğimi yapıyor! teşekkür ederim!
Qamar Stationwala

6

2020 veya daha sonraki bir tarihte herhangi birinin bunu işlevsel bileşenlerle nasıl başaracağını merak etmesi durumunda. Ben böyle yaptım:

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

Not: useref kullandığınızı belirtebilirsiniz. çoğu kişi ref kancalarla nasıl kullanılacağını bilmiyor.
ʎzɐɹƆ

Evet. Mesele şu ki, useRef kancasını kullanmadığınızda bile işe yaradı. Ama doğru yol onu kullanmaktır! Haklısın
Marlon Englemam

5

bu çözümü dene

xcode 10.0

RN: 56.0.0

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

neden ref=? bir web geliştiricisi kalıntısı gibi görünüyor
YungGun

4

react-native-invertible-scroll-viewModülü kullanarak kaydırma / liste görünümünü tersine çevirebilir , ardından aşağı ref.scrollTo(0)kaydırmak için aramanız yeterlidir .

Modülü kurun:

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

Ardından bileşeni içe aktarın:

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

Ardından, a yerine aşağıdaki JSX'i kullanın ScrollView:

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

Bu işe react-native-invertible-scroll-viewyarar çünkü tüm görünümün içeriğini çevirir. Görünümün çocuklarının da normal görünümün tersi sırada işleyeceğini unutmayın - ilk çocuk altta görünecektir .


3

Aslında @Aniruddha cevabı benim için işe yaramadı çünkü kullanıyorum "react-native": "0.59.8"ve this.scrollView.root.scrollToEndtanımsız

ama anladım ve bu işe yarıyor this.scrollView.scrollResponderScrollToEnd({animated: true});

Bunu kullanıyorsanız 0.59.8VEYA daha sonraki sürümü kullanıyorsanız çalışacaktır ve bu sizin için çalışır. Başkalarının sorun yaşamaması için lütfen bu yanıta sürümler ekleyin.

Tam Kod burada

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

1

Bu yöntem biraz karmaşık ama daha iyi bir yol bulamadım

  1. Önce ScrollView'unuza bir referans ekleyin.
  2. İkinci olarak, ScrollView etiketinizi kapatmadan önce sahte bir Görünüm ekleyin
  3. O kukla Görünümün y konumunu alın
  4. Aşağıya kaydırmak istediğinizde, kukla Görünümün konumuna gidin

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>
    );
  }


Bu değil oldukça istedi ne; bu, içerik eklendikçe kaydırma görünümünü aşağıya kaydırılmış olarak tutmak yerine, dokunulduğunda aşağıya kaydırır. Her neyse, scrollToBottomReact Native'in yeni sürümlerinde bu gibi yaklaşımları geçersiz kılar.
Mark Amery

1

Sorunuzun cevabı budur: https://stackoverflow.com/a/39563100/1917250

İçeriğin yüksekliği eksi kaydırma Görünümünün yüksekliğini hesaplayarak sürekli olarak sayfanın altına kaydırmaya devam etmeniz gerekir.


Bu sorunun doğru cevabıdır. Kaydırmayı ne zaman gerçekleştireceğiniz konusunda akıllı olabilirsiniz, bağlantıdaki yanıt ihtiyacınız olan numaraları nasıl alacağınızı gösterir. Özellikle, listeye bileşenler ekliyorsanız, componentDidUpdate çağrıldığında içerik yüksekliği bunları içermez, bu nedenle bunun yerine onContentSizeChange'e kaydırmak ve kaydırmak istediğinizi hatırlamak istersiniz.
xixixao

1

TypeScript kullanıyorsanız Bunu yapmanız gerekir

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

Bir süre bununla savaştım ve sonunda benim için gerçekten iyi çalışan ve sorunsuz bir şey buldum. Birçokları gibi ben de .scrollToEndboşuna uğraştım. Benim için çalıştı çözüm bir arada oldu onContentSizeChange,onLayout sahne donanımı ve biraz daha görsel olarak "aşağıya kaydırmanın" gerçekte ne anlama geldiğini düşünmekti. Son kısım şimdi benim için önemsiz görünüyor, ama anlamam sonsuza kadar sürdü.

ScrollViewSabit bir yüksekliğe sahip olduğu göz önüne alındığında , içerik yüksekliği konteynerin yüksekliğini aştığında, ofseti için prevHeight(sabit yüksekliğini ScrollView) çıkararak hesapladım .currHeight (içerik yükseklik). Görsel olarak hayal edebiliyorsanız, y eksenindeki bu farka kaydırarak, içerik yüksekliğini bu uzaklık kadar kapsayıcı üzerinde kaydırır. Ofsetimi artırdım ve şimdi mevcut içerik yüksekliğimi önceki boyum haline getirdim ve yeni bir ofset hesaplamaya devam ettim.

İşte kod. Umarım birine yardımcı olur.

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

Sanırım cevap vermek için çok geç ama bir hack'im var! Eğer kullanırsanız FlatListetkinleştirebilir invertedayarı geri düşer özelliği transform scaleiçin -1(gibi diğer liste bileşenleri için kabul edilebilir olan ScrollView...). Eğer render zaman FlatListverilerle her zaman altta olacak!


-1

Kaydırma görünümünün contentOffset özelliğini içeriğin mevcut yüksekliğine ayarlamayı deneyin .

İhtiyaç duyduğunuz şeyi başarmak için bunu onScroll etkinliğinin bir parçası olarak yapabilirsiniz. Ancak bu, kötü bir kullanıcı deneyimine neden olabilir, bu nedenle bunu yalnızca yeni bir mesaj eklendiğinde yapmak daha kullanıcı dostu olabilir.


-1; Hayır. Burada cevapların birçoğu gibi, bu kaydırma etkisi vardır ScrollViewiçin aşağı aşağıda içeriğinin tümü yerine sadece altına kaydırma.
Mark Amery


Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.