Stacking Order: How to render component so it appears on top of parents' sibling who renders afterwards - react-native

I'm having some problems with zIndex and position whilst styling a drop down list (react-native-menu). I want to make the drop down list appear on top of all other components on this scene when it's clicked. I'm trying to use zIndex and position but maybe not doing it correctly?
In my code (below), I'm rendering a hierarchy where Card > CardSection > various subcomponents of each. The drop down list consists of the components MenuContext (config) and TopNavigation (main drop down list).
return (
<Card>
<CardSection style={{zIndex: 2}}>
<View style={thumbnailContainerStyle}>
<Image style={thumbnailStyle}
source={{ uri: "" }}
/>
</View>
<View style={headerContentStyle}>
<Text style={headerTextStyle}>Tam</Text>
<Text>tam#tam</Text>
</View>
<MenuContext style={{ flex:1, zIndex:6, position:'absolute', flexDirection: 'column', alignItems: 'flex-end' }} >
<TopNavigation/> //this is
</MenuContext>
</CardSection>
<CardSection style={{zIndex: 1}}>
<Text style={{zIndex: 2}}>{props.post.body}</Text>
</CardSection>
</Card>
)
So the drop down is a child of the first CardSection. I've got it to appear over it's own parent CardSection but I can't get it to appear on top of the second CardSection that renders after. So I can't get it to show on top of it's parent's sibling.
I'm reluctant to use some plugin or workaround.
Any ideas? Thanks!!

So what was making it so hard to render the popup menu above things on the z-axis was the sibling of it's parent. So what helped me get the results I needed was looking more macro and moving <ContextMenu/> higher in the component hierarchy, out of this component altogether and into it's parent.
I should have inferred this since the docs for the original package I used had ContextMenu in the entry point to the app and comments such as:
// You need to place a MenuContext somewhere in your application,usually at the root.
// Menus will open within the context, and only one menu can open at a time per context.
My mistake was getting lost in the micro world of zIndex and position and assuming that what looked like a styling problem should be solved with a styling solution. I forgot about the bigger picture.

Related

ScrollView won't Scroll at all

I have a React page that needs a Scrollview, there's no way around it. The content goes off the bottom of the screen, and it is encapsulated in the ScrollView. I have a red border on the ScrollView element so I can see that it goes past the bottom of the screen where the rest of my content it. However, it just does not want to scroll. I even put an 'onScroll' prop inside with console.log('hit') at one point to see if the ScrollView was even registering my attempts, it was not. This is happening in a couple of similar components, their structure is very similar. The smallest of them looks like this...
<ScrollView style={{borderColor: 'red', borderWidth: 3}}>
<View style={QualityStyles.container}>
<View style={{width: '100%'}}>
<Text style={QualityStyles.leadersTitle}>Top Three Leaders</Text>
</View>
<View style={QualityStyles.topThree}>
{renderTopThree(topThree)}
</View>
<View style={{width: '100%'}}>
<Text style={QualityStyles.leadersTitle}>Employees</Text>
</View>
<View style={QualityStyles.remainders}>
{renderOthers(others)}
</View>
</View>
</ScrollView>
The code's pretty straightforward, with renderTopThree returning 3 components that will take up about 90% of the screen, and renderOthers will fit maybe one component on the screen, and the rest (while rendered and existent) can't be seen since I can't scroll. Anyone see what could be wrong?
I resolved the issue, I had a TouchableWithoutFeedback wrappping the entire Application, and it was blocking out any ability to scroll

Scrollview goes under status bar when using KeyboardAvoidingView

If you take a look on the left of the time on the status bar, you can see part of the scrollview showing. When scrolling up i can see the scrollview with all the elements ( pickers ,textinputs etc) scrolling underneath the statusbar.
My hierarchy looks like this
<React.Fragment>
<SafeAreaView forceInset={true} style={{ flex: 1, backgroundColor: colors.black, zIndex: 10000 }}>
<View style={{flex:1}}>
<Header/> //has certain height. had to add zIndex=10000 to avoid same issue
<KeyboardAvoidingView behavior='position'>
<ScrollViewWithContent/>
</KeyboardAvoidingView>
</View>
</SafeAreaView>
</React.Fragment>
Are you seeing anything obviously off?
Adding overflow:hidden; will do the trick. However i feel like this shouldnt be happening in the first place. The original bug is a weird state where part of the scrollview shows ( the text ) and part of it doesnt ( the background )

Include ListHeaderComponent in numColumns - React-Native

Does anyone know how I can include the header of a flatlist in the columns?
For example, in the image below I would like "Design" to follow "New +" in the same row.
Example Screenshot
Here is my code in render:
<FlatList
data={goalItems}
extraData={this.props}
renderItem={this._renderGoal}
ListHeaderComponent={this._renderGoalHeader}
keyExtractor={item => item.goal_id}
showsVerticalScrollIndicator={false}
numColumns={2}
/>
and in _renderGoal:
_renderGoal = ({ item }) => (
<TouchableOpacity
onPress={() => this.openOptions(item)}
style={{ padding: 10 }}>
<Bubble>
<Text style={[styles.normalText]}>{item.name}</Text>
<View style={{ alignItems: 'center' }}>
<Text>{formatSeconds(item.total_time)}</Text>
</View>
</Bubble>
</TouchableOpacity>
);
and in _renderGoalHeader:
_renderGoalHeader = () => (
<TouchableOpacity
onPress={() => this.openAddGoal()}
style={{ padding: 10 }}>
<Bubble style={[styles.newGoal]}>
<Text style={[styles.touchableText]}>New +</Text>
</Bubble>
</TouchableOpacity>
)
Thanks in advance.
As a temporary fix, I removed numColums from the flatList and added the following:
contentContainerStyle={{ flexWrap: 'wrap', flexDirection: 'row', width: 345 }}
I would love to be proven wrong here, but as far as I can tell, this cannot be done using numColumns. There is a workaround which I'll list at the end, but first the reasoning:
Explanation
I ran into this same issue but with the footer and did a code dive into the React Native source to see what was happening. First thing I did was use the inspector and I noticed that the header and footer of a FlatList are wrapped in a View while each row of columns is wrapped in CellRenderer > View. This is the first clue that FlatList does not account for headers and footers in numColumns. This is problematic because FlatList does not support masonry type layouts. This hints at the fact that there are many assumptions being made about how they are handling rendering the rows - that is, items are separated into rows to be rendered.
With these clues, I went into the source and found that FlatList passes its own custom renderItem down to VirtualizedList. Meanwhile, ListHeaderComponent and ListFooterComponent are passed down as is. They are never used in FlatList. Not a good sign as you'll see that the aforementioned _renderItem is what handles grouping the items together into columns to render using flexDirection: 'row' and whatever is passed down with columnWrapperStyle.
But perhaps VirtualizedList is smart enough to combine the header and footer into data that gets passed into renderItem?
Sadly, this is not the case. If you follow the code in VirtualizedList, you'll eventually see all the logic get played out in render() where:
a cells array is created
that first has the header pushed into it
followed by all of the data pushed into it via its _pushCells helper method
This is where CellRenderer appears;
hence why headers and footers are not wrapped by this whereas the rows are.
This is also where FlatLists _renderItem is used explaining why you get numColumns number of items wrapped in a CellRenderer.
and then finished with the footer being pushed in the same manner as the header.
This cells array of React components is then eventually cloned which helps with things such as keeping scroll position.
And finally rendered.
Do to this implementation, you will always get a fixed CellRenderer component which prevents headers and footers from being included as part of numColumns.
Workaround (not recommended)
If you've used React Native prior to FlatList being released, you'll know that one old workaround was to be very careful with your dimensions and use flexWrap: 'wrap'. It's actually documented within the source code as it will spit out a warning if you use this method of handling columns. Do note that it is NOT recommended to do this (I believe performance and perhaps scroll position may be some of the reasons against using this method).
If you are willing to do this though, add these styles to your contentContainerStyle:
flexDirection: 'row',
flexWrap: 'wrap',
// You'll probably also want this for handling empty cells at the end:
justifyContent: 'flex-start',
and remove the numColumns prop. Then make sure to manually size your component dimensions to get the correct looking column style layout you desire. This should allow your header and footer to render as part of the columns.
If you want to do it with numOfColumns, than use flexDirection:'row' within your header component
_renderGoalHeader = () => (
return(
<View style={{flexDirection:'row'}}>
<TouchableOpacity
onPress={() => this.openAddGoal()}
style={{ flex:1, padding: 10, }}>
<Bubble style={[styles.newGoal]}>
<Text style={[styles.touchableText]}>New +</Text>
</Bubble>
</TouchableOpacity>
<View>
<View style={{flex:1}}/> //this view is just to cover half width
);
)

How to "stack" touch events in React Native

I have a feed of items that looks something like this:
What I am trying to Achieve:
When the user presses an item in the feed (represented by the black box), they will be brought to a separate page for that item. When the user clicks on the star icon, they can "favorite" the item.
How I am trying to do it:
I am currently trying to implement this by nesting two TouchableOpacity's (represented by the black boxes), where the inner/child TouchableOpacity has a zIndex: 2 style applied to it.
The zIndex style does not seem to give a priority to the child container for touch events, so I was wondering if anyone knows how I can implement this pattern. I think I might need to use the PanResponder, but it seems like a very verbose way to add this functionality.
Any comments or examples would be greatly appreciated ! Thanks.
Can you not simply nest a TouchableOpacity in your parent TouchableOpacity ? I've done a mock project and this below seems to work
<View>
<TouchableOpacity
style = {{backgroundColor: 'red', height: 100}}
onPress = {() => {console.log("PARENT METHOD")}}>
//content
<TouchableOpacity
style = {{width: 30, height: 30, backgroundColor: 'yellow',
position: 'absolute', right: 5, bottom: 5}}
onPress = {() => {console.log("CHILD METHOD")}}>
//content
</TouchableOpacity>
</TouchableOpacity>
</View>
I've used logs and when pressing the small nested box, only child method is logged, and similarly for if i press the parent view.
Log output: showing independant touches
Let me know if this helps
Why not something like below:
<View style={{flex-direction: "row"}}>
<View>
<TouchableOpacity onPress={this.goToDetails.bind(this)}>
</TouchableOpacity>
</View>
<View>
<TouchableOpacity onPress={this.goToDetails.bind(this)}>
</TouchableOpacity>
<TouchableOpacity onPress={this.favoriteItem.bind(this)}>
</TouchableOpacity>
</View>
</View>
Where you have two views in a row, first view has one TouchableOpacity, and the second view has two TouchableOpacitys in a a column (where first one is similar to previous TouchableOpacity, and the second is to favorite the item).
Should be structured like this:

React Native Soft Keyboard Issue

I have TextInput at the bottom of the screen. When TextInput is focused then keyboard appears and due to this all the flex view gets shrink to the available screen. I want to achieve that page layout should not change and input should be visible to user.
<View style={MainView}>
<View style={subMain1}>
<View style={{flex:1,backgroundColor:'#add264'}}></View>
<View style={{flex:1,backgroundColor:'#b7d778'}}></View>
<View style={{flex:1,backgroundColor:'#c2dd8b'}}></View>
</View>
<View style={subMain2}>
<View style={{flex:1,backgroundColor:'#cce39f'}}></View>
<View style={{flex:1,backgroundColor:'#d6e9b3'}}></View>
<View style={{flex:1,backgroundColor:'#69ee9a'}}>
<TextInput placeholder="input field"/>
</View>
</View>
</View>
const Styles = {
MainView:{
flex:1,
backgroundColor:'green'
},
subMain1:{
flex:1,
backgroundColor:'blue'
},
subMain2:{
flex:1,
backgroundColor:'orange'
}
}
I just found an answer to this.
I just have to use fixed height for my main container and inside that I can use flex layout. And If keyboard is hiding the content then we can use Scrollview that will allow scrollable interface when user clicks on input.
This helped me hope it can help others. :)
I'm not quite sure I understand what the issue you're running into, but I recently struggled with keyboard avoiding views in my app - for some reason, the native component just wasn't working.
Check this package out - it did the trick for me, and offers some cool customization capabilities:
https://github.com/APSL/react-native-keyboard-aware-scroll-view
Use 'react-native-keyboard-aware-scroll-view' and keep this as parent view and put all view inside that view. This node module creates scrollview and it listens to keyboard show event and automatically scrolls your screen so user can see the input box without getting it hidden behind the soft keyboard.