Daniel
Daniel

Reputation: 133

Nested Touchable with absolute position

I need to implement an interface where an object is clickable, but an area of this object does another action, like this:

|-----------|
|        |  | -> clicking on this small area does an action
|        ---|
|           |
|           |
|           | -> clicking on this area does another action
|           |
|-----------|

I did an implementation similar this structure:

<View> // Container
  <Touchable onPress={do X}> // Large area
  <Touchable onPress={do Y} style={{position: absolute, top: 0, right: 0}}> // Small area
</View>

The problem is that the small area never activate the onPress props. The event is always triggered on the large area.

Can someone help me with this?

Thanks!

Upvotes: 13

Views: 6200

Answers (2)

Nader Dabit
Nader Dabit

Reputation: 53691

I'm not sure if you have any styling to show for the small container, but if there is no width or height, it will not trigger, so check to make sure you have set up a width and height:

smallContainer: {
    width: 120, // set this
    height:100, // set this
    position:'absolute',
    top:0,
    right:0
}

I've gotten your setup working here. Code is also below.

https://rnplay.org/apps/StpOXg

'use strict';

var React = require('react-native');
var {
  AppRegistry,
  StyleSheet,
  Text,
  View,
  TouchableHighlight
} = React;

var SampleApp = React.createClass({
  render() {
    return (
      <View style={styles.container}>
        <View style={{flexDirection:'row'}}> 
          <TouchableHighlight onPress={ () => alert('largeContainer') } style={styles.container1}>
                    <View><Text>Hello1</Text></View>
            </TouchableHighlight>
          <TouchableHighlight onPress={ () => alert('smallContainer') }  style={styles.container2}>
                <View><Text>Hello2</Text></View>
            </TouchableHighlight>
        </View>
      </View>
    );
  }
});

var styles = StyleSheet.create({
  container: {
    flex: 1
  },
  container1: {
    width:320,
    height:300,
    backgroundColor: 'red'
  },
  container2: {
    width: 120,
    height:100,
    position:'absolute',
    backgroundColor: 'green',
    top:0,
    right:0
  }
});

AppRegistry.registerComponent('SampleApp', () => SampleApp);

Upvotes: 4

darrylivan
darrylivan

Reputation: 354

There are a few possible issues that I can imagine might be going wrong.

  1. just to make sure it is not the obvious: does the second div have a height/width? If it is zero size, you won't be able to touch it. I will assume this is not the case, so more likely,
  2. Are you certain both handlers are not triggering? The event can be propagated up the chain if you don't call event.stopPropagation() in the event handler of the smaller/inner div. In this case, it could be executing the first handler and then propagating to the second handler.
  3. Depending on all your css, there could be a z-index or hidden element issue that either layers the first div on top of the second div, or hides the second div altogether (display:none).

Aside:

One tricky thing that can sometimes affect you is that React implements its own events above and beyond the native browser events. That means if you call stopPropagation() on the event you get in the React handler, it will stop the propagation of the React event, but not of the underlying browser event. So, if for some reason you had some handler for the event outside of React (using JS or jQuery to add event handlers instead of react), those non-React handlers will still trigger after you have done a stopPropagation(). I don't think that is your problem here.

Upvotes: 0

Related Questions