Search code examples
javascriptreactjsreact-nativescrollviewsticky

How to put a sticky Touchable within an horizontal ScrollView in React Native?


I am trying to make a simple application/game to learn and practice React Native. Currently, I am trying to create a sticky TouchableNativeFeedback that moves with the screen as I am using the ScrollView.

The idea is that left half of the screen would move the character to the left and the right half of the screen would move it to the right. I want these controls to be fixed in the display and not move.

This is how it starts

Initial Screen

This is after moving the scrollView a bit

After moving

I've initially tried to change value of style.left as I scrolled but that doesn't seem to be a good/stable solution.

Here is the current code:

render() {     
    return (
        <ScrollView 
            //onScroll={this._onScroll}
            ref={(scrollView) => { this.scrollView = scrollView; }}
            style={styles.container}
            horizontal= {true}
            snapToAlignment={"center"}
        >
            <View style={styles.wrapperView}>
                    <ImageBackground
                        style={styles.container}
                        source={require('../images/second.png')}
                    >

                    <TouchableNativeFeedback onPressIn={this._onPressButton} onPressOut={this._onPressButton}>
                        <View style={
                                {
                                    width: width/2,
                                    height: '100%',
                                    position: 'absolute',
                                    left: this.state.touchableLeft,
                                    backgroundColor: 'red',
                                }
                            }>

                        </View>
                    </TouchableNativeFeedback>

                    ... (code about the character)

                </ImageBackground>
            </View>
       </ScrollView>
    );
  }

and the styles code

const styles = StyleSheet.create({
    container: {
        width: '100%',
        height: '100%',

    },
    wrapperView:{
        width: width*3 + 300,
    },
  });

and just to have it as a reference, this is what I originally tried:

_onScroll = (event) => {
    this.setState( {
        touchableLeft: this.state.touchableLeft + event.nativeEvent.contentOffset.x
     } )
}

I've looked at the following questions and articles but I couldn't really get to a solution that would help me. Usually people use flex to make their headers sticky above a ScrollView and that is incredibly handy but in this situation I am unsure about how to continue. Articles/Questions:

How to Get ListView Section Header to Stick

http://docs.nativebase.io/docs/examples/StickyHeaderExample.html

Sticky Component inside scrollview


Solution

  • What solved my problem was to take the TouchableNativeFeedback outside of the class. The class in the question was called Background and it was rendered in the class called App.

      <View style={styles.container}>
        <Background />
        <TouchableNativeFeedback onPressIn={this._onPressButton} onPressOut={this._onPressButton}>
            <View style={
                    {
                        width: '50%',
                        height: '100%',
                        position: 'absolute',
                        left:0,
                        //left: this.state.touchableLeft,
                        //backgroundColor: 'red',
    
                    }
                }>
    
            </View>
        </TouchableNativeFeedback>
      </View>
    

    As you can see once I moved it to here, it was positioned right where I wanted, even if I move the screeen. What would be good practice, is to take it to another component class and then just call an instance of it.

    Thanks to John Ruddell for the help while coming up with the solution