Set state is only working after clicking twice react native - react-native

Im trying to change the opacity of a button when the user clicks it, (between 2 buttons the darker one would be his choice). For some reason whenever i click the button once the opacity doesn't change and it only changes after 2 clicks. Any ideas where im going wrong?
export default function lastName({ navigation }) {
let [opac, setOpacity] = useState(0.3);
return (
<View style={styles.container}>
<View
style={{
flex: 0.5,
justifyContent: "flex-end",
//backgroundColor: "red",
}}
>
<Text style={styles.textStyle}>
Select a button
</Text>
</View>
<View
style={{
flex: 1,
justifyContent: "flex-start",
}}
>
<TouchableOpacity
style={{
marginTop: 70,
alignItems: "center",
justifyContent: "center",
width: 180,
height: 40,
backgroundColor: "#004953",
opacity: opac,/// here
borderRadius: 100,
}}
onPress={() => {
setOpacity(1); // here
}}
>
<Text
style={{
color: "white",
textAlign: "center",
fontSize: 18,
}}
>
Button 1
</Text>
</TouchableOpacity>

Apparently, its a bug with touchable opacity, you have to wrap opacity in a view, refer to this link Dynamic Opacity not changing when component rerenders in react native

Related

Not able to make corners of bottom sheet rounded in react-native-bottom-sheet

I am trying to make the corners of the bottom sheet provided by the react-native-bottom-sheet rounded by passing the style prop to it. But the rounded corners are being overlapped by something which I don't know. How do I make the the corners rounded?
Screenshot:
Code:
<BottomSheet
style={{
flex: 1,
borderWidth: 5,
borderColor: "red",
backgroundColor: "blue",
borderRadius: 50
}}
index={1}
ref={bottomSheetRef}
snapPoints={snapPoints}
onChange={handleSheetChange}
>
<View
style={{
backgroundColor: "lightgreen",
marginTop: 30,
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
<View style={{ backgroundColor: "white" }}>
<Text>
I am back
</Text>
</View>
</View>
</BottomSheet>
This BottomSheet component is wrapped inside a View with flex: 1
Just added overflow: hidden to the BottomSheet's style prop and it worked.
I ran into the same problem but found another solution because I was using a Handler that was outside the BottomSheet so adding overflow: 'hidden' just hid my Handler.
Reading the code I realized that the style prop that is passed to BottomSheet is added to the code as containerStyle here, but the component in charge of defining the rounded corners is actually the BackgroundComponent which has the border radius in its styles.
So, in order to get a BottomSheet with a custom corner radius is better to add a separate backgroundComponent with all the modifications we want.
Like this:
function customBackground({ pointerEvents, style }) {
return (
<View
pointerEvents={pointerEvents}
style={[styles.bgContainer, style]}
/>
);
}
function renderSheet(){
return(
<BottomSheet
index={1}
ref={bottomSheetRef}
snapPoints={snapPoints}
onChange={handleSheetChange}
backgroundComponent={customBackground}
>
<View
style={{
backgroundColor: "lightgreen",
marginTop: 30,
flex: 1,
justifyContent: 'center',
alignItems: 'center'
}}
>
<View style={{ backgroundColor: "white" }}>
<Text>
I am back
</Text>
</View>
</View>
</BottomSheet>
;)
}
const styles = StyleSheet.create({
bgContainer: {
borderTopLeftRadius: 40,
borderTopRightRadius: 40,
backgroundColor: "blue"
},
})

Change font color with TouchableHighlight

How to change the font color of the button, the problem is that the font color doesn't look good so each time the user tap on the button I need to change the font color too.
My approach:
Normal Button
Pressed Button
<TouchableHighlight
underlayColor="#E5E6EA"
onPress={onOpen2}
style={{
fontFamily: "AktivGroteskCorp",
paddingLeft: 15,
paddingRight: 15,
borderRadius: 25.5,
flexDirection: "row",
justifyContent: "center",
marginBottom: 15,
width: vw * 67.2,
height: vw * 13.6,
alignItems: "center",
alignSelf: "center",
borderColor: "#E5E6EA",
borderWidth: 1,
}}
>
<Text
style={{
color: "#ffffff",
fontWeight: "bold",
fontSize: 16,
textAlign: "center",
alignSelf: "center",
}}
>
LOG IN
</Text>
</TouchableHighlight>
Here is a functional way
First, create useState then manipulate it on onPressIn/onPressOut
const TouchableHighlightExample = () => {
const [BtnColor, setBtnColor] = useState("red");
return (
<View>
<TouchableHighlight onPressIn={()=>setBtnColor("blue")} onPressOut={()=>setBtnColor("red")}>
<View>
<Text style={{color: BtnColor}}>Touch Here</Text>
</View>
</TouchableHighlight>
</View>
);
}
using onPressIn and onPressOut
https://reactnative.dev/docs/pressable#onpressin
state = {
fontColor: 'red',
}
<TouchableHighlight
onPressIn={()=>{ this.setState({fontColor:'blue'});}}
onPressOut={()=>{ this.setState({fontColor:'red'});}}
>
<Text
style={{
color: this.state.fontColor,
}}
>
LOG IN
</Text>
</TouchableHighlight>

React-native: Layout a view next to a centered one

I want to achieve the following:
I want to display a label next to a centered value.
As far as I can see that's not possible with flexbox, right?
How could I achieve that?
Additionally I'd like to have the base-aligned, but currently this option is not working on Android. Therefore I'm using hardcoded paddings for the smaller text boxes. Any other Idea for that?
Another suggestion, if you don't want to use empty Views, is to position Value to the center, and then have the unit positioned absolute (so it goes off the flex) and to the bottom so you ensure it's base-aligned to Value.
<View style={styles.container}>
<Text style={styles.value}>
Value
<Text style={styles.unit}>unit</Text>
</Text>
</View>
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: 'lightgrey',
},
value: {
backgroundColor: '#eee',
textAlign: 'center',
fontSize: 20,
position: 'relative',
},
unit: {
fontSize: 12,
position: 'absolute',
bottom: 0,
},
});
You can use use 3 flex boxes placed horizontally to get a similar effect. Leave the left box blank.
(Ive added background colors for reference)
<View style={styles.container}>
<View
style={{
flexDirection: 'row',
}}>
<View style={{ flex: 1}} /> {/* blank view */}
<View
style={{
flex: 1,
justifyContent: 'flex-end',
alignItems: 'center',
}}>
<Text style={{ fontSize: 30 }}>Value</Text>
</View>
<View
style={{
flex: 1,
justifyContent: 'flex-end',
alignItems: 'fllex-start',
}}>
<Text style={{ fontSize: 12 }}>Unit</Text>
</View>
</View>
</View>

How to prevent react native modal from moving up when keyboard opens in android?

I have a very basic modal component(using React-native-modal) which render its given child views. However, I dont want the behaviour similar to KeyBoardAvoiding view, i.e. I don't want the modal to be pushed up when keyboard opens.
<Modal
isVisible={isVisible}
onBackdropPress={onCartDismiss}
style={CartStyles.cartModal}
onSwipeEnd={this.onCartDismiss}
onSwipe={this.onCartDismiss}
swipeDirection="down"
swipeThreshold={200}
propagateSwipe
avoidKeyboard={false}
>
{this.props.children}
....
On ios it is working fine i.e. the keyboard opens over the modal component, but not on android. avoidKeyboard={false} is not working.
This is my style for the modal (position:'absolute' didn't work too)
cartModal: {
position: 'absolute',
justifyContent: 'flex-end',
bottom: 0,
left: 0,
right: 0,
zIndex: 1,
},
I have even tried changing softinputmode in android manifest to :
android:windowSoftInputMode="adjustPan"
<Modal
isVisible={modalVisible}
animationInTiming={500}
animationOutTiming={1000}
backdropTransitionInTiming={500}
backdropTransitionOutTiming={1000}
onBackdropPress={() => setModalVisible(!modalVisible)}
onBackButtonPress={() => setModalVisible(!modalVisible)}
style={{
justifyContent: 'flex-end',
margin: 0,
position:'absolute'
}}
avoidKeyboard={false}
>
try this, it works for me.
Set you model height as integer value without percentage.
<Modal
// style={{backgroundColor:'red'}}
deviceHeight={screenHeight}
deviceWidth={screenWidth}
transparent={true} visible={isVisible} animated={false}>
<View style={{
backgroundColor: 'rgba(0,0,0,.6)',
flex: 1,
alignItems: 'center',
justifyContent: 'center'
}}>
<View style={{
flexDirection: 'row',
height: 200,
width: '80%',
alignSelf: 'center'
}}>
{content}
</View>
</View>
</Modal>
Give the main view inside your modal a "fixed height value" and the containing view should have a "100%" view height. Like this:
<Modal animationType={fade} ...>
<View style={{
height: "100%",
width: "100%",
alignItems: "center",
// justifyContent: "center",
backgroundColor: "rgba(0, 0, 0, 0.4)",
}}>
<View style={{
borderRadius: 10,
marginHorizontal: width * 0.05,
marginTop: height * 0.1,
width: width * 0.9
height: height * 0.8
}}>
...`enter code here`
</View>
</View>
</Modal>
I solved the issue by removing justifyContent: "center"

How to center react native headerTitle *component* (not string)

For the life of me, I can't center the headerTitle component. Ideas?
class GroupSelectionScreen extends React.Component{
static navigationOptions = ({navigation}) => {
return {
headerLeft: <View>
<Image source={logoImg} style={{width:72, height:33, marginLeft:5}}/>
</View>,
headerStyle: {
backgroundColor: theme.colors.darkBlue,
height: 75,
},
headerTitle: <View style={{
alignItems: "center",
flexDirection: 'row',
}}>
<View style={{backgroundColor: statusColor, width: 15, height: 15, borderRadius: 8}}></View>
<Text style={{color: 'white', fontSize: 25}}>{username}</Text>
</View>,
headerRight: <SetStatusButton onPress={navigation.getParam('toggleSetStatus')}/>,
};
};
Because you are using flexDirection:'row' you will probably want to add the property justifyContent:'center' to center the content of the view horizontally
This is due to the fact that justifyContent works on the primary axis and alignItems work on the secondary axis. Setting the flexDirection as row changes the primary axis to be row.
Adding flexDirection to a component's style determines the primary axis of its layout.
Adding justifyContent to a component's style determines the distribution of children along the primary axis.
You can see more in the docs
https://facebook.github.io/react-native/docs/flexbox
Here is a snack https://snack.expo.io/#andypandy/flexdirection
Each of the three views have flexDirection: 'row'
The first view has justifyContent: 'center' and the text is centred horizontally.
The second view has alignItems: 'center' and the text is centred vertically.
The third view has both justifyContent: 'center' and alignItems: 'center' and the text is centred horizontally and vertically
Here is an image of what it looks like
And here is the code
<View>
<View style={{flexDirection: 'row', justifyContent: 'center', backgroundColor: 'yellow', height: 100, width: 100, margin: 10}} >
<Text>Hello</Text>
</View>
<View style={{flexDirection: 'row', alignItems: 'center', backgroundColor: 'cyan', height: 100, width: 100, margin: 10}} >
<Text>Hello</Text>
</View>
<View style={{flexDirection: 'row', justifyContent: 'center', alignItems:'center', backgroundColor: 'forestgreen', height: 100, width: 100, margin: 10}} >
<Text>Hello</Text>
</View>
</View>
Update
In react-navigation there appears to be a difference between how headerTitle given by the question poster is handled in Android and iOS.
In iOS the headerTitle centres vertically and horizontally, however in Android it centres only vertically and is aligned left. Obviously this is not ideal.
There is a way to make it work in both iOS and Android, simply
Wrap the original header in a View with flex:1
Make sure the original header's View has a style with justifyContent: 'center' and alignItems: 'center'
Here is the code for the new headerTitle
<View style={{flex: 1}}>
<View style={{flexDirection: 'row', justifyContent: 'center', alignItems: 'center'}}>
<View style={{backgroundColor: 'green', width: 15, height: 15, borderRadius: 8}}/>
<Text>Spencer</Text>
</View>
</View>
Here is a snack showing it working https://snack.expo.io/#andypandy/navigation-header