React Native multi-line vertically centered text on IOS trouble - ios

I'm using a multi line TextInput in my react-native application and been stuck on this for a while. I can not get the text to be vertically aligned on IOS devices.
using textAlign='center' puts the text on IOS vertically centered... but it becomes an unwrapped never ending line.
adding multiline={true} negates the vertically aligned text in IOS and puts it at the top of the input.
<TextInput
style={{
width: wp('80%'),
height: hp('25%'),
borderWidth: 1,
borderRadius: 10,
fontSize: RF(3),
}}
textAlign={'center'}
multiline={true}
onChangeText={entry => this.setState({entry})}
value={this.state.entry}
/>
I would like the behavior to be like android in that it shows the placeholder text vertically and horizontally centered and when user inputs more text it starts creating multi lines if needed but always vertically and horizontally centered.
Please see image with android version on left and IOS on right.
Android on left, IOS on right

try adding textAlignVertical={"center"} to textInput's props

Have you tried wrapping the TextInput in a View?
<View style={{ alignItems: 'center', justifyContent: 'center' }}>
<TextInput
style={{
width: wp('80%'),
height: hp('25%'),
borderWidth: 1,
borderRadius: 10,
fontSize: RF(3),
}}
textAlign={'center'}
multiline={true}
onChangeText={entry => this.setState({entry})}
value={this.state.entry}
/>
</View>

Add the attribute paddingTop to your TextInput in your XML file.

Related

#capacitor-community/barcode-scanner wrongly calculate height on different iphones

I want to build BarCode scanner with #capacitor-community/barcode-scanner, On Android it looks totally fine, it calculate proper height of the screen and put overlay button on the bottom of the page. With Iphones it doesn't work like that, each iphone shows button in other place, I tested it on iphone 8,11 and 13. On Iphone 8 button is visible on the bottom but you can see that it is cut and it is possible to scroll down, on iphone11 it is barely visible and on iphone13 it is not visible at all. Anybody knows how to set overlay button to be totally on the bottom of the page without need to scroll down?
{isScanningInProgress ? (
<>
<StyledStopScanBox>
<Button color="primary" variant="contained" size="large" onClick={stopScan}>
Stop Scan
</Button>
</StyledStopScanBox>
</>
) : (
...
)
const StyledStopScanBox = styled(Box)(({ theme }) => ({
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'center',
position: 'absolute',
width: '100%',
top: 'calc(100vh - 75px)',
zIndex: 3,
height: 75,
backgroundColor: theme.palette.background.default
}));

Scroll displacement on React Native with Expo

I got this screenshot from a user that says its scroll is displaced in the center as you can see in the image bellow.
I tried using simulator with iPhone XS Max and even my olds iPhone 7 but couldn't reproduce this in anyway. Maybe this is a known bug or something and I was wandering if someone could point me in the right direction.
About the code, I'm using a ScrollView component with the following props:
<View style={{flex: 1}}>
<ScrollView
style={{flexGrow: 1}}
contentContainerStyle={{flexGrow: 1}}
>
// content here
</ScrollView>
</View>
Hello Please try to set absolute position for your scrollview
`<View style={{flex: 1}}>
<ScrollView
style={{flexGrow: 1, position: 'absolute', right: 0, bottom: 0}}
contentContainerStyle={{flexGrow: 1}}
>
// content here
</ScrollView>
</View>`

Underline placeholder in React Native

How can I underline placeholder in iOS in React Native? I can underline whole TextInput (not placeholder) by:
borderBottomWidth: 1,
borderBottomColor: '#B8B8B8',
I would like to underline only placeholder of TextInput, not TextInput
I have a little workaround for you. As soon as you start typing, the underline gets removed.
Demo
Explanation
I applied the borderBottomWidth and borderBottomColor to the parent view, because you probably don't want to use multiline. If you want to use a mulitine TextInput you could apply those styles directly to the Textinput, as mentioned in the docs.
Note that some props are only available with multiline={true/false}.
Additionally, border styles that apply to only one side of the element
(e.g., borderBottomColor, borderLeftWidth, etc.) will not be applied
if multiline=false. To achieve the same effect, you can wrap your
TextInput in a View
As soon as the user has typed (the text length is greater than 0) something, this.setState({ active: true }) gets fired. After that the conditional rendering takes place here:
borderBottomColor: this.state.active === false ? 'red' : 'transparent' // hide color, when text is present
width: this.state.active === false ? scaledWidth : 100 // increase width to 100. Value is just a placeholder, use whatever you like
Complete Code
// helper function to scale font size and placeholder width.
scale = (fontSize) => {
const screenWidth = Dimensions.get('window').width;
const ratio = fontSize / 375; // get ratio based on your standard scale, here: width of iphone 7
const newSize = Math.round(ratio * screenWidth);
return newSize;
}
render() {
// you probably have to play around with those standard values
const scaledFontSize = this.scale(22);
const scaledWidth = this.scale(25);
return (
<View style={{ marginTop: 50, flex: 1, alignItems: 'flex-end' }}>
<View style={{ borderBottomWidth: 2, borderBottomColor: this.state.active === false ? 'red' : 'transparent', width: this.state.active === false ? scaledWidth : 100 }}>
<TextInput
style={{ height: 30, textAlign: 'right', fontSize: scaledFontSize }}
onChangeText={(text) => text.length > 0 ? this.setState({ active: true }) : this.setState({ active: false })}
placeholder={'10'}
//multiline
/>
</View>
</View>
)
}

Picker placement is wrong on react-native view

I'm following this Udemy react-native course and in one of the examples he uses a picker to select data in the screen. Back when he tried it it seems like it was working but now I get a weird result when I try to render it.
If I follow his code exactly the picker shows after all the other items, after making some changes I get it to show kind of at the right place but it is now squished, which is still not correct:
I am definitely doing something wrong here in terms of how to render it, here's the code (full example on github):
import React from 'react';
import {Picker, Text, StyleSheet, View} from 'react-native';
import {connect} from 'react-redux';
import {Card, CardSection, Input, Button} from "./common";
import {employeeUpdate} from "../actions";
class EmployeeCreate extends React.Component {
updateEmployee(name, value) {
this.props.employeeUpdate({prop: name, value: value})
}
renderPickerItems() {
return ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday']
.map((item) => <Picker.Item key={item} label={item} value={item}/>);
}
render() {
return (
<Card>
<CardSection>
<Input
label="Name"
placeholder="Your Name"
value={this.props.name}
onChangeText={this.updateEmployee.bind(this, 'name')}
/>
</CardSection>
<CardSection>
<Input
label="Phone"
placeholder="555-555-5555"
keyboardType="phone-pad"
value={this.props.phone}
onChangeText={this.updateEmployee.bind(this, 'phone')}
/>
</CardSection>
<CardSection style={{flex: 1}}>
<View style={styles.shiftContainerStyle}>
<Text style={styles.pickerTextStyle}>Shift</Text>
<Picker
style={styles.pickerStyle}
selectedValue={this.props.shift}
onValueChange={this.updateEmployee.bind(this, 'shift')}
>
{this.renderPickerItems()}
</Picker>
</View>
</CardSection>
<CardSection>
<Button>
Create
</Button>
</CardSection>
</Card>
);
}
}
const styles = StyleSheet.create({
pickerTextStyle: {
fontSize: 18,
lineHeight: 23,
flex: 1,
},
pickerStyle: {
flex: 2,
},
shiftContainerStyle: {
flex: 1,
flexDirection: 'row',
alignItems: 'center',
}
});
const mapStateToProps = state => {
const {name, phone, shift} = state.employeeForm;
return {
name,
phone,
shift,
};
};
export default connect(mapStateToProps, {employeeUpdate})(EmployeeCreate);
Any idea what I could do to render this correctly?
You need to remove style={{flex: 1}} from this line in your code:
<CardSection style={{flex: 1}}>
The reason being that your parent container, Card, doesn't have any flex or width/height values defined. If flex is left undefined, the default is flex: 0. If you look at the docs for flex, you'll see that:
When flex is 0, the component is sized according to width and height and it is inflexible.
Combine that with having no width/height defined and you get this behavior on rendering your CardSections:
The three CardSections (input, input, button) will take up the default width and height based on their children. That is the default styling for the Inputs and Button.
The CardSection with style={{flex: 1}} will calculate its width and height based on the remaining space taken up by the parent container(s) per the definition of flex: 1:
When flex is a positive number, it makes the component flexible and it will be sized proportional to its flex value. So a component with flex set to 2 will take twice the space as a component with flex set to 1.
The parent container, Card, in this case has no extra space left. So what happens is that this CardSection ends up with 0 height. Hence the strange overflow rendering you're seeing.
Once you remove style={{flex: 1}}, the width and height of the CardSection will be defined by it's child components which, like Input and Button, do have a styles and default styles.
Whether or not this is correct behavior per the Yoga spec (Yoga is what React Native uses for layout) is up for debate and has tripped up others before. Definitely look over that first StackOverflow answer I linked to as it has far more detail and explanation on gotchas than any of the documentation on React Native wrt flex.

Why would touches not be registering on the bottom of the screen in React-Native?

I'm attempting to put a floating button over a ListView in my React-Native application on iOS. The appearance is great, but the functionality of my TouchableHighlight is not so great...
<TouchableHighlight
onPress={() => {
this.myAction()
}}>
<View style={styles.floatingCameraButton}>
<Image source={camera_icon} style={styles.cameraIcon}/>
</View>
</TouchableHighlight>
That's my code for the button, and here are my stylings:
floatingCameraButton: {
height: 80,
width: 80,
borderRadius: 40,
backgroundColor: '#aa2222',
position: 'absolute',
bottom: 20,
right: 20,
shadowColor: '#000000',
shadowOpacity: 0.8,
shadowRadius: 2,
shadowOffset: {
height: 5,
width: 5
},
},
For some reason, when the button is touched on the lower portion of the screen, the touch fails to register on the button.
I've tested making the button taller and also moving in up, and both of those are solutions, but not ones I am interested in.
My assumption is that somehow React-Native is masking my touches that occur where the iOS native Tab Bar would be (meaning the bottom 50px). However, I do not have a Tab Bar on the screen, nor have I implemented one. I do have a Navigator that is wrapping the view which my button is in, not sure if that could be the culprit.
Any ideas or help to get my TouchableHighlight to be touchable on the bottom 50px of the screen would be very helpful.
Try applying your styles to the TouchableHighlight itself.
<TouchableHighlight
style={styles.floatingCameraButton}
onPress={() => this.myAction()}>
<Image source={camera_icon} style={styles.cameraIcon}/>
</TouchableHighlight>

Resources