Flama
Flama

Reputation: 868

RefreshControl with ScrollView moves screen content down with each refresh

I've got a screen with a ScrollView that has a refreshControl property. Turns out that when I refresh my screen, the whole content of the screen moves a few positions down. If I refresh again it keeps going down and so on.

enter image description here enter image description here

This screenshots are taken right before refreshing and right after. As you see after refreshing some space was added on top of the screen. Why?

Here's what's inside my render function:

render() {
  if(this.state.isLoading || this.state.user === null) {
   // IF I PUT RETURN NULL HERE IT WORKS FINE,AND THE CONTENT DOESNT GO DOWN
    return(<ScrollView contentContainerStyle={{alignItems: "center", flex: 1, justifyContent: 'center'}}>
      <Spinner isVisible={true} size={100} type={'Pulse'} color={'#013773'}/>
      <DropdownAlert ref={ref => this.dropDownAlertRef = ref} /> 
    </ScrollView>);
  }
  else {
    return (
      <ScrollView
      refreshControl={
        <RefreshControl
          refreshing={this.state.isLoading}
          onRefresh={this._onRefresh.bind(this)}
        />
      }>
        <View style={styles.whiteContainer}>
          <View style={{backgroundColor: colors.white,paddingVertical: 10, borderStyle: 'solid', borderColor: colors.black}}>
              <Text style={{fontStyle: 'italic', fontWeight: 'bold', fontSize:20, marginLeft:20, color: colors.grey}}>
                Mis donaciones
              </Text>
          </View>
          {this.state.myDonations.length > 0 ? 
          <Carousel
            ref={(c) => { this._carousel = c; }}
            data={this.state.myDonations}
            renderItem={this._renderDonation}
            sliderWidth={SLIDER_WIDTH}
            itemWidth={ITEM_WIDTH2}
            inactiveSlideShift={0}
            onSnapToItem={(index) => this.setState({ index })}
            scrollInterpolator={scrollInterpolator}
            slideInterpolatedStyle={animatedStyles}
            useScrollView={true}
            />: 
            <Text style={{fontStyle: 'italic', alignSelf: 'center', fontWeight: 'bold', fontSize:20, marginTop:20, marginBottom: 40, color: colors.grey}}>
            ¡Nada para mostrar!
          </Text>}
        </View>
        {this.state.user.category === "Voluntario" ? 
        <View style={styles.whiteContainer2}>
        <View style={{backgroundColor: colors.white,paddingVertical:10, borderStyle: 'solid', borderColor: colors.black}}>
            <Text style={{fontStyle: 'italic', fontWeight: 'bold', fontSize:20, marginLeft:20, color: colors.grey}}>
              Mis entregas
            </Text>
        </View>
        {this.state.myDeliveries.length > 0 ? 
        <Carousel
        ref={(c) => { this._carousel = c; }}
        data={this.state.myDeliveries}
        renderItem={this._renderDelivery}
        sliderWidth={SLIDER_WIDTH}
        itemWidth={ITEM_WIDTH2}
        inactiveSlideShift={0}
        onSnapToItem={(index) => this.setState({ index })}
        scrollInterpolator={scrollInterpolator}
        slideInterpolatedStyle={animatedStyles}
        useScrollView={true}
      /> : <Text style={{fontStyle: 'italic', alignSelf: 'center', fontWeight: 'bold', fontSize:20, marginTop:20, marginBottom: 40, color: colors.grey}}>
      ¡Nada para mostrar!
    </Text>}
      </View>
        : null}
        <View style={styles.whiteContainer2}>
          <View style={{backgroundColor: colors.white, paddingVertical:10, borderStyle: 'solid', borderColor: colors.black}}>
              <Text style={{fontStyle: 'italic', fontWeight: 'bold', fontSize:20, marginLeft:20, color: colors.grey}}>
                Pedidos
              </Text>
          </View>
          {this.state.requests.length > 0 ? 
          <Carousel
              ref={(c) => { this._carousel = c; }}
              data={this.state.requests}
              renderItem={this._renderRequest}
              sliderWidth={SLIDER_WIDTH}
              itemWidth={ITEM_WIDTH}
              inactiveSlideShift={0}
              onSnapToItem={(index) => this.setState({ index })}
              scrollInterpolator={scrollInterpolator}
              slideInterpolatedStyle={animatedStyles}
              useScrollView={true}
            /> : <Text style={{fontStyle: 'italic', alignSelf: 'center', fontWeight: 'bold', fontSize:20, marginTop:20, marginBottom: 40, color: colors.grey}}>
            ¡Nada para mostrar!
          </Text>}
        </View>
        <DropdownAlert ref={ref => this.dropDownAlertRef = ref} /> 
      </ScrollView>
    );
  }
}

_onRefresh looks like this:

_onRefresh = () => {   
  this.setState({
    user: null,
    isLoading: true
  });
}

isLoading is later set on false when methods inside componentDidUpdate finish loading.

I'm importing RefreshControl and ScrollView from "react-native": "~0.61.4".

Update: As you see inside my render method I got an if-else statement. Turns out if I put return null instead of my spinner inside of the first block, the problem is solved. Why?

Upvotes: 3

Views: 1961

Answers (2)

Zafer ATLI
Zafer ATLI

Reputation: 81

Never needed double render condition, just simply add key . when key change its trigger to remount of ui and its simply fix

render() {
    return(
       <ScrollView
       key={`${this.state.isRefreshing}`}
       refreshControl={
         <RefreshControl
           refreshing={this.state.isRefreshing}
           onRefresh={this._onRefresh.bind(this)}
         />
       }>
         ...
       </ScrollView>
    );
}

Upvotes: 0

Flama
Flama

Reputation: 868

Ok, I found the issue. As you see I had a conditional if-else statement in my render method. Turns out I had to add RefreshControl to the ScrollView of the first block of the statement as well.

render() {
  if(this.state.isLoading || this.state.user === null) {
    return(
    <ScrollView contentContainerStyle={{alignItems: "center", flex: 1, justifyContent: 'center'}}
    refreshControl={
      <RefreshControl
        refreshing={false}
        onRefresh={this._onRefresh.bind(this)}
      />
    }>
      ...
    </ScrollView>);
  }
  else {
    return (
      <ScrollView
      refreshControl={
        <RefreshControl
          refreshing={this.state.isLoading}
          onRefresh={this._onRefresh.bind(this)}
        />
      }>
        ...
      </ScrollView>
    );
  }
}

Upvotes: 2

Related Questions