Fixed View at bottom (variable height) and fill remaining height with other View - react-native

I want to build a chat. In the view for the messages are the messages and the input field for the message. The Inputbox should be at the bottom and should use the height it needs. The height of the Inputbox can change if the user enters multi-line text. The msgs-View should fill the rest of the height (above). I don't want to position the Input absolute because the message's FlatList should be always in the "visible" area.
<View style={styles.wrapper}>
<View style={styles.msgs}>Messages (FlatList)</View>
<View style={styles.input}>Inputbox</View>
</View>

Don't give flex style to your input.
Give your wrapper and list a flex: 1 style. Wrapper will take up all the space in its parent (which I assume is the screen). And list will take all the space in wrapper. And input will sit in the bottom.

Related

Plotting points on an image and rendering on a different screen size in React Native

So I have an image of a field in which the user is able to plot points by touching their screen. These points are then stored within a database by obtaining the e.nativeEvent.locationX, e.nativeEvent.locationY on the user's press.
So when I plot the point on my Tablet and review where I placed the plot on the field image using my PC, It is displayed incorrectly. I assume this is due to different screen sizes and the image is a different size depending on the device screen size.
How do I resolve this issue so that the plots are consistent no matter what device you are using?
Any other possible solutions are much appreciated.
Below is how I display the image / obtain the user's x-axis and y-axis values and on press these values are retrieved by the function ObtainPosition
<TouchableOpacity onPress={this.ObtainPosition}>
<Image style = {{
width:wp('60%'),
height:hp('100%'),
resizeMode: 'contain'}} source={require('./pitch.png')}/>
</TouchableOpacity>
note - you may see wp and hp this is an import
import {widthPercentageToDP as wp, heightPercentageToDP as hp} from 'react-native-responsive-screen';
Below is how I display user's plots (Note this is usually on a different screen/component). These plots are retrieved from the database and displayed in an array of objects. As you can see below the .map function loops through the array called PlotsArray and retrieves the x and y values and returns a View which is our plots.
<View>
<Image style = {{
width:wp('60%'),
height:hp('100%'),
resizeMode: 'contain'}} source={require('./pitch.png')}/>
{this.state.PlotsArray.map((data) => {
return (
<View
style={{
position: 'absolute',
left: data.x,
top: data.y,
backgroundColor:'#242424',
width: 10,
height: 10,
borderRadius: 50
}}>
</View>
)
})}
</View>
I think your obtainPosition function will need to take into account the Image element's left and right values (from the window / page) at the same time as you getting the actual x y coordinates of the click (if its padded, or the user is scrolled etc.)
You will also need to get the size of the image when you log the coordinates. So for example have a function similar to:
(event) => {
var {height, url, width} = event.nativeEvent.source;
}
called within the onLoad prop of the image. That way when you store the x, y co-ordinates you can also record the size of the image at the time (say 200px x 200px). Later on, when you render the clicks overlaid on the image, you can asses the size of the image on the 'viewing' device and adjust x y coordinates accordingly or store them as percentages rather than fixed pixels.
Rough example here of how using % on top and left values can adjust to the image varying in size https://jsfiddle.net/skfroxyt/ (have a play with editing the image height and width)

How to create horizontal FlatList with multiple rows and items with dynamic width?

I want to achieve something simillar to this:
The effect is similar to UICollectionView from Swift with self sizing cells.
How should I go implementing this in React Native?
Setting numColumns will not achieve the desired effect as I need a dynamic number of cells per row. That would limit me to the value of numColumns. There should be as many items per row as there can fit. If no more can fit on that row, then add to the next row.
Thanks!
you can try to use the flexWrap style. and set the text view a fixed height. the width is auto.
<View style={[{flexDirection: 'row', flexWrap: ' wrap'}]}>
data.map(element => {
return <Text style={{height:100}}>element.content</Text>
})
</View>

Can I apply styles to a subset of the text in a user input with React Native?

Let's say in a TextInput element, I want to make a word green if it's formatted as #someonesusername the moment they finish writing the word (as opposed to after the text is submitted, in which case it's trivial to send the text to a normal Text component with subset styling. I thought of underlaying a Text component with absolute positioning and making the actual TextInput component invisible, but that seems it might be a headache to keep in sync, and cause usability challenges in the sense that the editing cursor wouldn't be there unless you wired together a custom cursor element to render and that'd be quite the headache for such a small thing I want to do.
So this the hack I came up with (Amazing question).
React native TextInput can take children as input. So why not split the value and add Text as children in the TextInput and add style the way you want to.
May be wondering how do get the text back? Well these children become string when comes to onChangeText callback and get a string back in your state.
For example:
// split the text like
const [firstPart, secondPart] = this.state.text.split("#");
const [higlighted , restText] = secondPart ? secondPart.split(' ') : [];
Then use them
<TextInput
style={{height: 40, borderColor: 'gray', borderWidth: 1}}
onChangeText={this.onChangeText}
>
<Text style={styles.paragraph}>
<Text>{firstPart}</Text>
{higlighted && <Text style={{
color: 'blue'
}}>#{higlighted}</Text>}
{restText !== undefined && <Text> {restText}</Text>}
</Text>
</TextInput>
Umm, I accept this might be worse solution ever but this works :P
Full example:
https://snack.expo.io/#subkundu/react-native-styles-to-a-subset-of-the-text

Nested Text Components Props

In React Native, I am trying to output a small blurb that generally takes up 2-3 lines of text. In this text, I want some parts to be bolded and pressable, and so I have come up with the following approach to separate the normal text and the special text:
<Text>
<Text style = {{fontSize:12}}>
{"Tried "}
</Text>
<Text style = {{fontSize:12}}>Beef and Shrimp Fried Noodle </Text>
<Text style = {{fontSize:12}}>{"for $10.25 at "}</Text>
<Text style = {{fontSize:12}}>JoyYee Restaurant</Text>
<Text style = {{fontSize:12}}>{" which is a 15 min walk from you"}</Text>
</Text>
I'm trying to alter the line-height of the 2-3 lines of text, but passing the lineHeight prop to the parent, or simply all of the children, has no effect. Is there a proper way of solving this? Or should I take a completely different approach to my text blurb?
To make the desired out come more clear: The text blurb should all be together, as such:
"Tried Beef and Shrimp Fried Noodle for $10.25 at JoyYee Restaurant which is a 15 min walk from you"
In order to keep the multiple text components in line, I had to wrap everything in a parent text; but now I am unable to control the line height of this small paragraph.
After much trial: The error lies in the fact that lineHeight is not a prop but is a style of the Text component. Therefore, the proper method was to write:
<Text style = {{lineHeight: 30}}>Hello etc. etc.</Text>
Hopefully this can help others avoid this issue as well!

Scrollview and child with flex: 1

Is it possible to have a layout which is wrapped with ScrollView:
<ScrollView>
<View>dynamic height</View>
<View>flex with minHeight</View>
<View>static height</View>
</ScrollView>
and meets below prerequisites:
Height of the first View is dynamic (depends on text length). Height of the third View is static (always three buttons inside). Rest of the screen should be filled with View with map, but the minimal height is set to 250.
Now the tricky part: if there is a lot of text in first View, so that map doesn't fit, a scroll should appear. I couldn't achieve that. I was trying to give the map View flex: 1 and minHeight: 250, but it's not rendered at all.
Solution
Ok, I've found a way to fix it. In first render, I get screen height (Dimensions) and height of first and third view (onLayout). Then, I calculate the height of second view (screenHeight - view1 - view3 - naviagtionHeight) and forceUpdate() to re-render it.
Add contentContainerStyle={{flexGrow: 1}} prop to ScrollView and its children's flex:1 would work. So you don't need to calculate it manually.