เป็นไปได้หรือไม่ที่จะเลื่อน ScrollView ไปที่ด้านล่าง?


90

สำหรับแอปที่คล้ายการแชทฉันต้องการให้ScrollViewส่วนประกอบเลื่อนไปที่ด้านล่างเนื่องจากข้อความใหม่ล่าสุดจะปรากฏอยู่ใต้แอปที่เก่ากว่า เราสามารถปรับตำแหน่งเลื่อนของ a ScrollView?


3
ฉันไม่รู้อะไรเกี่ยวกับ react-native แต่โปรดทราบว่าบางครั้งผู้ใช้ต้องการเลื่อนขึ้นเพื่อดูประวัติการแชท ตรวจสอบให้แน่ใจว่าได้เลื่อนแชทเฉพาะในกรณีที่การแชทถูกเลื่อนไปจนสุดแล้วเมื่อมีข้อความใหม่เข้ามา
David

นี่เป็นความคิดที่ดี เรากำลังติดตามปัญหานี้ที่นี่: github.com/facebook/react-native/issues/107
Eric Vicenti

ฉันเพิ่งตอบคำถามที่คล้ายกันโปรดตรวจสอบที่นี่ - stackoverflow.com/a/32652967/1541508
Kohver

สิ่งนี้ตอบคำถามของคุณหรือไม่? วิธีเลื่อนไปที่ด้านล่างของ React Native ListView
TripleM

คำตอบ:


166

สำหรับReact Native 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
Simon

4
ขณะนี้ใช้ react native 0.58.6 และการใช้rootจริงทำให้เกิดข้อผิดพลาดที่ไม่ได้กำหนด
Jose Bernhardt

1
ควรจะเป็น: ref={ref => {this.scrollView = ref}}ในขณะที่คุณไม่ต้องการส่งคืนงาน
Hampycalc

26

ใช้ 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

21

นี่คือวิธีที่ง่ายที่สุดที่ฉันสามารถรวบรวมได้:

 <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

16

สำหรับใครก็ตามที่เขียนส่วนประกอบของฟังก์ชันที่สามารถใช้ hook ได้

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
เรียบง่ายและสง่างาม ทำในสิ่งที่ฉันต้องการได้อย่างสมบูรณ์แบบ! ขอขอบคุณ!
Qamar Stationwala

6

ในกรณีที่ทุกคนในปี 2020 หรือใหม่กว่านั้นสงสัยว่าจะทำสิ่งนี้ได้อย่างไรด้วยส่วนประกอบที่ใช้งานได้ นี่คือวิธีที่ฉันทำ:

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

หมายเหตุ: คุณสามารถระบุได้ว่าคุณกำลังใช้ useref ppl ส่วนใหญ่ไม่รู้วิธีใช้ ref กับ hooks
ʎzɐɹƆ

ใช่. สิ่งนี้ก็คือมันได้ผลแม้ว่าจะไม่ได้ใช้ตะขอ useRef ก็ตาม แต่วิธีที่ถูกต้องคือการใช้! คุณพูดถูก
Marlon Englemam

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=อะไร? ดูเหมือนของที่ระลึกนักพัฒนาเว็บ
YungGun

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';

จากนั้นใช้ JSX ต่อไปนี้แทน a ScrollView:

<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. ประการที่สองเพิ่ม Dummy View ก่อนปิดแท็ก 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ทำให้แนวทางเช่นนี้ล้าสมัยใน React Native เวอร์ชันใหม่กว่า
Mark Amery

1

สิ่งนี้ตอบคำถามของคุณ: https://stackoverflow.com/a/39563100/1917250

คุณต้องเลื่อนไปที่ด้านล่างของหน้าอย่างต่อเนื่องโดยการคำนวณความสูงของเนื้อหาลบด้วยความสูงของ scrollView


นี่คือคำตอบที่ถูกต้องสำหรับคำถาม คุณฉลาดได้ว่าจะเลื่อนเมื่อใดคำตอบในลิงค์จะแสดงวิธีรับตัวเลขที่คุณต้องการ โดยเฉพาะอย่างยิ่งหากคุณกำลังเพิ่มส่วนประกอบในรายการความสูงของเนื้อหาจะไม่รวมส่วนประกอบเหล่านั้นเมื่อมีการเรียก componentDidUpdate ดังนั้นคุณต้องจำไว้ว่าคุณต้องการเลื่อนและเลื่อนบน onContentSizeChange แทน
xixixao

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จะไม่มีประโยชน์ วิธีการแก้ปัญหาที่ทำงานสำหรับฉันคือการรวมกันของonContentSizeChange,onLayoutอุปกรณ์ประกอบฉากและน้อยมากขึ้นอีกนิดคิดสายตาเกี่ยวกับ "สิ่งที่เลื่อนไปที่ด้านล่าง" หมายจริงๆ ตอนสุดท้ายดูเหมือนจะไม่สำคัญสำหรับฉันในตอนนี้ แต่ฉันต้องใช้เวลาตลอดไปในการคิดออก

เนื่องจาก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

ฉันเดาว่ามันสายเกินไปที่จะตอบ แต่ฉันได้แฮ็คหนึ่งครั้ง! หากคุณใช้FlatListคุณสามารถเปิดใช้งานinvertedคุณสมบัติซึ่งกลับไปที่การตั้งค่าtransform scaleเป็น-1(ซึ่งเป็นที่ยอมรับสำหรับส่วนประกอบรายการอื่น ๆ เช่นScrollView... ) เมื่อคุณแสดงผลFlatListด้วยข้อมูลข้อมูลจะอยู่ด้านล่างเสมอ!


-1

ลองตั้งค่าคุณสมบัติcontentOffsetของมุมมองเลื่อนเป็นความสูงปัจจุบันของเนื้อหา

เพื่อให้บรรลุสิ่งที่คุณต้องการคุณสามารถทำได้โดยเป็นส่วนหนึ่งของกิจกรรม onScroll อย่างไรก็ตามสิ่งนี้อาจทำให้ผู้ใช้ได้รับประสบการณ์ที่ไม่ดีดังนั้นจึงอาจพิสูจน์ได้ว่าเป็นมิตรกับผู้ใช้มากขึ้นเพียงทำสิ่งนี้เมื่อมีการต่อท้ายข้อความใหม่


-1; ไม่ เช่นเดียวกับคำตอบหลาย ๆ คำตอบที่นี่มีผลจากการเลื่อนScrollViewลงไปด้านล่างของเนื้อหาทั้งหมดแทนที่จะเลื่อนไปที่ด้านล่าง
Mark Amery

-1

ฉันมีปัญหาคล้าย ๆ กัน แต่หลังจากอ่านหน้านี้ (ซึ่งทำให้ฉันปวดหัว!) ฉันพบแพ็คเกจ npm ที่ดีมากซึ่งจะกลับรายการ ListView และทำให้ทุกอย่างเป็นเรื่องง่ายสำหรับแอปพลิเคชันแชท !!


-1; สิ่งนี้ซ้ำกับคำตอบที่โพสต์ไว้ก่อนหน้านี้ที่นี่ (และค่อนข้างสับสนเล็กน้อยคำถามนี้เกี่ยวกับ a ScrollViewไม่ใช่ "ListView")
Mark Amery

-3

ช้าไปหน่อย ... แต่ดูคำถามนี้สิ เลื่อนไปด้านบนสุดของ ScrollView

ScrollView มีเมธอด "scrollTo"


1
ใช่มีวิธี scrollTo ใน ScrollView แต่คำถามนี้ถามโดยเฉพาะเกี่ยวกับการเลื่อนไปที่ด้านล่างซึ่งไม่ตรงไปตรงมา
Southerneer
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.