8

So, I want to create a layout similar to whats below. [Refer the Image]

So the background has a full screen MapView (React Native Maps) with Markers over it, which needs to be clickable.

And there is a Scrollview with full screen height over the MapView which initially has some top-margin associated with its contents.

But the issue if I arrange my Views this way, the Markers on the map are not clickable in the initial state.

<View>
  <MapView>
    <Marker clickEventHere></Marker>
    <Marker clickEventHere></Marker>
  </MapView>
  <ScrollView fullscreen>
     <View marginTop></View>
  </ScrollView>
<View>

I am unsure if its really possible to solve this out.

Initial State Initial State

After Scrolling After Scrolling

Solution Tried

yScrolled = event.nativeEvent.contentOffset.y;
yValue = this.state.yValue - yScrolled;

upwardScroll = yScrolled > 0;

if(upwardScroll && (yValue > 0)){
  this.setState({
    yValue: yValue
  });
}


if(yScrolled === 0){
  yScrolled = -10;
}
if(!upwardScroll && (yValue <= scrollViewMarginTop)){
  yValue = this.state.yValue - yScrolled;
  console.debug("UPDATE DOWNWARD");
  this.setState({
    yValue: yValue
  });
}
Gregoire Ducharme
  • 1,095
  • 12
  • 24
red-devil
  • 1,064
  • 1
  • 20
  • 34
  • 1
    Have you tried passing `pointerEvents: 'box-none'` to ScrollView's style? More info in the docs: https://facebook.github.io/react-native/docs/view.html#pointerevents – Mateo Hrastnik Oct 08 '17 at 10:30
  • Thanks! I didn't try this. But this would also make the visible or sub views inside the ScrollView to be un-clickable, I don't want that. – red-devil Oct 08 '17 at 11:19
  • 1
    From the link I provided in my previous comment: `'box-none': The View is never the target of touch events but it's subviews can be.` – Mateo Hrastnik Oct 08 '17 at 16:07
  • Well! in that case that would work, thanks much. :) Unfortunately I had to move to an alternate design to skip this problem, but we would revert back again. I will try it out. – red-devil Oct 09 '17 at 01:05
  • 1
    I get the following error "pointerEvents is not a valid style property". Since I am applying this to Scrollview while the link you shared has it for a View. – red-devil Oct 09 '17 at 06:26

2 Answers2

2

I'd start with adding absolute positioning to your ScrollView, (position: absolute) starting at whatever y coordinate you would like. I would make this y value a state, eg

yValue: new Animated.Value(start_value) or simply yValue: start_value

I would then use ScrollView's prop onScroll event to handle the change in this y coordinate, for example for the first 100 pixels of a scroll it would simply change the yValue instead of scrolling the view.

This should enable you to press the markers you have in your parent view, and use the same component structure that you have provided.

Note: You would need to do this for collapsing the scrollview also.

Note2: if this doesn't give you the result you were looking for, i'd suggest looking into using some sort of collapsable component for this task, eg https://github.com/oblador/react-native-collapsible

Hope this helps

EDIT: To collapse the scrollview you could first identify if the scroll direction is downwards ( which i think youve done via upwardScroll ) and then..

1) Either simply add the content offset to your yValue

2) If you used Animated.Value for yValue, you can have an animate function that animates the scrollview downwards to your desired position. I think this would look nicer as the user would only need a simple downwards flick to collapse the view, which seems like the industry standard.

Ryan Turnbull
  • 3,766
  • 1
  • 25
  • 35
  • Tried first solution for now, It works well in the case of upward scroll. What to do to make the downward scroll collapse the scrollview? Have updated the solution tried above. – red-devil Oct 02 '17 at 12:39
  • Also, Accordions wont solve this. As the background map needs to be visible. – red-devil Oct 02 '17 at 13:22
  • Do you not just do the same sort of thing in reverse? It's a hard question to answer without seeing it running, but i'd handle a downward scroll event one of two ways, ive edited my answer – Ryan Turnbull Oct 02 '17 at 20:35
  • I wrote for even reverse above in the similar way, but it hangs as the scroll would obstruct scrolling downward if the top is reached. I am trying the above two approaches now. – red-devil Oct 03 '17 at 00:34
  • 2
    Can you please show the solution with some code? Because when it comes to actual implementation most things don't work. Like here even finding the right scroll direction when the yValue is changing is breaking. Also contentOffset as a param is for iOS. A simple code snippet for the entire solution would make things more clear.. – red-devil Oct 03 '17 at 01:01
  • Hey @red-devil have you found any solution for your issue? m facing the same. can you share some code for it? – Himanshu G Aug 29 '19 at 15:11
0

There is also a library that is called react-native-touch-through-view that can do this for you. This it how it works basically:

<View style={{ flex: 1 }}>
    // Your map goes here
</View>
<TouchThroughWrapper style={{
    position: 'absolute'',
    top:      0,
    left:     0,
    width:    '100%',
    height:   '100%',
}}>
    <ScrollView
        style={{
            backgroundColor: 'transparent',
            position:        'absolute',
            top:             0,
            left:            0,
            width:           '100%',
            height:          '100%',
            // Maybe in your case is flex: 1 enough
        }}
        bounces={false}
        showsVerticalScrollIndicator={false}
    >
        <TouchThroughView 
            style={{
                height: 400, // This is the "initial space" to the top
            }} 
        />
        // The "slide up stuff" goes here
    </ScrollView>
</TouchThroughWrapper>

For example, this then can look like this:

ios screenshot

So the map is overlayed by the TouchThroughView that passes all the events right to the view behind. In my case this worked better than using pointer-events box-none.

Thomas Kekeisen
  • 4,355
  • 4
  • 35
  • 54