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

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
}));

Related

Weview doesn't shirnk when keyboard is appeared on IOS

Problem: The height of webview doesn't reduce when I open up the keyborad on IOS
I used a KeyboardAvoidingView wrap my Webview like this
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={isKeyboardOpen ? {
backgroundColor: 'rgba(0,0,0,0.3)',
position: 'absolute',
left: webViewConfig.x,
top: webViewConfig.show ? y : deviceHeight,
width: deviceWidth - webViewConfig.x,
height: deviceHeight - y - keyboardHeight,
} : {
backgroundColor: 'rgba(0,0,0,0.3)',
position: 'absolute',
left: webViewConfig.x,
top: webViewConfig.show ? y : deviceHeight,
width: deviceWidth - webViewConfig.x,
height:
deviceHeight - y
}}
>
// webivew here
</KeyboardAvoidingView>
I even make the height of KeyboardAvoidingView is dynamically change when the keyboard is hidden/appeared.
Please check the image below. I'd like to make the red section is dissapeared. Or at least make the content of webview fit into the container's space (which is KeyboardAvoidingView component) and make it unable to scroll down.
Screenshots/Videos:
I add style={{ backgroundColor: 'red' }} into Weview. As you can see that the webview's content is shirnked as exepected but the red bacground still appear.
Environment:
OS: IOS
OS version: 15.4.1
react-native version: 0.64.2
react-native-webview version: 11.2.3
In my case. I need to prevent the webview from scrolling. There is a property called scrollEnabled of the WebView component that does that. The codes will look like this
<KeyboardAvoidingView
behavior={Platform.OS === 'ios' ? 'padding' : 'height'}
style={{
backgroundColor: 'rgba(0,0,0,0.3)',
position: 'absolute',
left: webViewConfig.x,
top: webViewConfig.show ? y : deviceHeight,
width: deviceWidth - webViewConfig.x,
height: deviceHeight - y
}}
>
<Webview
// other properties
scrollEnabled={false} // -> set this to false
/>
</KeyboardAvoidingView>

Full screen background image on loginscreen in React Native app

I'm currently trying to set a full background image on my login view.
I've used the following code to do so but noticed that Iphone 11 have like a white bar at the bottom and top of the phone. Is this something that can't be overlapped since it's like the navigation?
const Background = styled.ImageBackground`
padding:20px;
justify-content:center;
width:100%;
height:100%;
`
const styles = StyleSheet.create({
container: {
flex: 1,
},
});
enter image description here
return <SafeAreaView style={styles.container}><Background source={require('../../assets/images/background-cover.jpg')}>
<CoverLogo width={100} height={100} color={Colors.White} />
<Introduction loop={false}>
<TextHeading text={`#test`} />
<TextPage text={`Btest2`} />
<TextPage text={`Ttest3`} />
<TextPage text={`test4 Sign up !`} />
</Background>
</SafeAreaView>
I'm not sure if this will help with the bottom of the screen, but for the top you can try and set your header style in navigationOptions like so if using react navigation
headerStyle: {
backgroundColor: 'transparent',
position: 'absolute',
top: 0,
left: 0,
right: 0,
borderBottomWidth: 0 // removes the border on the bottom
}
If you follow the SafeArea advice also given in the other answer, then this may be of help too https://reactnavigation.org/docs/handling-safe-area/
Try using :
SafeArea as a parent view, with flex:1
Or maybe have a function to check for iPhone 11/ iPhoneX like that:
isIphoneX: () => {
const dimen = Dimensions.get('window');
const deviceModel = DeviceInfo.getModel();
return (
deviceModel === 'iPhone X' ||
(Platform.OS === 'ios' &&
!Platform.isPad &&
!Platform.isTVOS &&
(dimen.height === 812 ||
dimen.width === 812 ||
dimen.height === 896 ||
dimen.width === 896))
);
},
iPhones Specs
your issue lies in your use of
<SafeAreaView> tag which limits the use of the screen space in ios devices below the notch and just above the lower edge of the screen. The use of SafeAreaView is only visible in the effects only on ios devices.
To resolve your issue I would suggest using the tag <View> instead of <SafeAreaView>

React Native multi-line vertically centered text on IOS trouble

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.

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