View is shaking by no reason on React Native iOS - react-native

I have detected a weird behaviour in the RN app I'm developing. By no reason apparently, one of the components of the screen starts to shake when refresh the app. This happens both on iOS simulator and iPhone device. It does not happen every time I refresh, but most of the time, and when it happens the simulator becomes unresponsive.
Here is the GIF of what happens: https://gph.is/g/EvAqBgg
Here is the code of the screen and the shaking component:
Screen
<Container>
<SafeAreaView />
<Header>
<TouchableOpacity onPress={() => navigation.openDrawer()}>
<MaterialIcons name="menu" size={24} color="black" />
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Filter')}>
<MaterialIcons name="search" size={24} color="black" />
</TouchableOpacity>
</Header>
<FlatList
data={products}
renderItem={({ item }) => (
<ProductItem
product={item}
onPress={() => navigation.navigate('Product', { product: item })}
/>
)}
keyExtractor={(item) => item.id}
numColumns={2}
ListEmptyComponent={() => <Text>No hay elementos</Text>}
ListHeaderComponent={<HomeHeader />}
></FlatList>
<ShoppingCartButton
items={itemsInCart}
onPress={() => navigation.navigate('ShoppingCart')}
price={price}
></ShoppingCartButton>
</Container>
);
}
const Container = styled.View`
flex: 1;
align-items: center;
justify-content: center;
background-color: white;
`;
const Header = styled.View`
width: 100%;
height: 40px;
flex-direction: row;
align-items: center;
justify-content: space-between;
padding-left: 16px;
padding-right: 16px;
`;
Shaking component
export default function ShoppingCartButton({ onPress, price, items }) {
return (
<ButtonArea>
<Container onPress={onPress}>
<CartIndicator>
<CartQuantity>{items}</CartQuantity>
</CartIndicator>
<ButtonTitle>Ver carrito</ButtonTitle>
<Price>{price} €</Price>
</Container>
<SafeAreaView />
</ButtonArea>
);
}
const ButtonArea = styled.View`
width: 100%;
padding: 16px;
border-top-width: 1px;
border-top-color: ${colors.separatorGrey};
background-color: ${colors.white};
box-shadow: 0px -4px 4px rgba(222, 222, 222, 0.2);
`;
const Container = styled.TouchableOpacity`
height: 48px;
width: 100%;
flex-direction: row;
justify-content: space-between;
align-items: center;
background-color: ${colors.mainBlue};
border-radius: 5px;
padding-left: 16px;
padding-right: 16px;
`;
const CartIndicator = styled.View`
background-color: #2c81ab;
padding: 4px;
padding-left: 8px;
padding-right: 8px;
border-radius: 3px;
`;
const CartQuantity = styled.Text`
font-family: 'Medium';
color: ${colors.white};
`;
const ButtonTitle = styled.Text`
font-family: 'Medium';
color: ${colors.white};
`;
const Price = styled.Text`
font-family: 'Book';
color: ${colors.white};
`;

Try using https://www.npmjs.com/package/react-native-safe-area-context instead of SafeAreaView from React Native.
Another thing you can try is to set fixed height to ButtonArea component.
Can't guarantee that these will work, but it fixed the shaking issue for me.

Related

Is there a way to level the text in a view component for react native with styled components?

I am trying out React Native with Expo client and styling it using styled components.
I am having trouble trying to level the text that is within a View component. I tried to search online and found some questions like Is there a way to scale a View in react-native? but it didn't help.
When the text is too long, the component will extend along and I can't seem to level them even after placing them within a container. I've tried experimenting around, adding margins into StyledViewItems and StyledItem (The View components where the problem lies), changing the flex, etc. But so far what I've tried, nothing seems to work.
I thought it would make sense to include margins but that only gave extra height to the component, and doesn't fix the issue.
Here is a screenshot for reference. Notice that bluetooth earpiece & portable monitor is not on the same level compared to the other items.
Code here:
import React, { useEffect, useState } from "react";
import {
Text,
TextInput,
View,
Button,
Image,
StyleSheet,
TouchableOpacity,
ScrollView,
} from "react-native";
import styled from "styled-components/native";
import { getCurrentUser, getItems, logOutUser } from "../../firebase";
import colours from "../Config/colours";
const StyledView = styled.View`
flex: 1;
background-color: ${colours.primary};
alignItems: center;
justifyContent: center;
width: 100%;
`;
const StyledSearchView = styled.View`
flex: 1;
background-color: ${colours.primary};
alignItems: center;
justifyContent: center;
width: 80%;
flexDirection: row;
margin: 8px;
`;
const StyledTextInput = styled.TextInput`
height: 40px;
margin: 2px;
width: 95%;
borderWidth: 1.5px;
borderRadius: 8px;
padding: 8px;
background-color: ${colours.inputbox};
color: ${colours.inputboxtext};
borderColor: ${colours.border};
fontSize: 14px;
`;
const StyledTouchableOpacity = styled.TouchableOpacity`
height: 40px;
margin: 2px;
borderWidth: 0.5px;
borderRadius: 6px;
padding: 6px;
background-color: ${colours.buttonbox};
color: ${colours.buttonboxtext};
borderColor: ${colours.border};
`;
const StyledSearch = styled(StyledTouchableOpacity)`
height: 40px;
`;
const StyledTouchableOpacityText = styled.Text`
color: ${colours.buttonboxtext};
fontSize: 17px;
`;
const StyledImage = styled.Image`
width: 90px;
height: 90px;
borderRadius: 6px;
`;
const StyledText = styled.Text`
margin: 8px;
color: ${colours.inputboxtext};
fontSize: 16px;
align-items: center;
justify-content: center;
`;
const StyledViewItems = styled.View`
flex: 4;
background-color: ${colours.primary};
alignItems: center;
justifyContent: center;
width: 100%;
flexDirection: row;
flexWrap: wrap;
alignSelf: center;
`;
const StyledItem = styled.View`
alignItems: center;
justifyContent: center;
margin: 8px;
width: 100px;
height: 118px;
position: relative;
alignSelf: center;
`;
const BrowseScreen = ({ route, navigation }) => {
// save the params as a variable
const userEmail = route.params.email;
// react states
const [text, setText] = useState("");
const [items, setItems] = useState([]);
const [user, setUser] = useState([]);
// useEffect - upon render, get all the items + user details
useEffect(() => {
getItems(setItems);
getCurrentUser(userEmail, setUser);
}, []);
return (
<>
<ScrollView contentContainerStyle={{ flexGrow: 1 }}>
<StyledView>
<StyledText>
What are you looking for today, {user.username}?
</StyledText>
<StyledSearchView>
<StyledTextInput
placeholder="Search items / category"
onChangeText={(text) => setText(text)}
/>
<StyledSearch
onPress={() =>
navigation.push("Search", {
email: user.email,
search: text,
})
}
>
<StyledTouchableOpacityText>🔍</StyledTouchableOpacityText>
</StyledSearch>
</StyledSearchView>
<StyledViewItems>
{items.map((element, index) => {
return (
<StyledItem key={index}>
<TouchableOpacity
onPress={() =>
navigation.push("Item", {
name: element.name,
email: user.email,
})
}
>
<StyledImage
source={{
uri: element.image,
}}
/>
<Text>{element.name}</Text>
</TouchableOpacity>
</StyledItem>
);
})}
</StyledViewItems>
<StyledSearchView>
<StyledTouchableOpacity
onPress={() => navigation.push("Cart", { email: user.email })}
>
<StyledTouchableOpacityText>Cart 🛒</StyledTouchableOpacityText>
</StyledTouchableOpacity>
<StyledTouchableOpacity
onPress={() => navigation.push("Account", { email: user.email })}
>
<StyledTouchableOpacityText>Account</StyledTouchableOpacityText>
</StyledTouchableOpacity>
<StyledTouchableOpacity onPress={() => logOutUser(navigation)}>
<StyledTouchableOpacityText>Logout</StyledTouchableOpacityText>
</StyledTouchableOpacity>
</StyledSearchView>
</StyledView>
</ScrollView>
</>
);
};
export default BrowseScreen;

Horizontal ScrollView Not Scrolling in React Native

I'm trying to render a horizontal scroll view of clickable photos.
The vertical scroll works fine, but once I set horizontal={true}, I'm limited to how far I can scroll horizontally. It prevents me from scrolling more than what is shown in this image.
<Container>
<ScrollView
horizontal={true}
contentContainerStyle={{
flex: 1,
paddingTop: "5%"
}}
>
{posts.map(post => {
return (
<TouchableOpacity
key={post.id}
style={{
width: width,
flex: 1,
height: height / 3,
borderRadius: "8px",
overflow: "hidden",
marginRight: "2%"
}}
>
<Thumbnail
source={{
uri: uri`
}}
/>
<PostTitle>{post.name}</PostTitle>
</TouchableOpacity>
);
})}
</ScrollView>
</Container>
const Container = styled.View`
flex: 1;
padding-top: 18%;
background: #fff;
`;
const Title = styled.Text`
color: #333;
text-transform: uppercase;
font-weight: 600;
padding-left: 8%;
padding-bottom: 5%;
`;
const Thumbnail = styled.Image`
flex: 1;
justify-content: center;
align-items: center;
resize-mode: cover;
`;
const PostTitle = styled.Text`
color: #fdfdfd;
font-size: 16px;
font-weight: bold;
position: absolute;
top: 10%;
left: 8%;
`;
Fixed. Removed "marginRight" and it worked. Horizontal ScrollView doesn't like styling its children's margins.
The problem certainly is from the margin. However, I've found that specifically, setting the margin in percentage values or adding flex: 1 to contentContainerStyle is what causes this problem.

React Native: Text gets cut when using numberOfLines & align-items

I'm trying to style a Splash Screen, I'm using styled-components.
I want the Text & Image to be swipeable on the screen so I created a card.
now the text in the card gets broken only on android, it just gets cuts off when I use align-items with numberOfLines
Here is the Splash Screen
import React from "react";
import { StyleSheet, Text, Dimensions, Button } from "react-native";
import styled from "styled-components/native";
import SplashCard from "../components/SplashCard";
const windowWidth = Dimensions.get("window").width;
const windowHeight = Dimensions.get("window").height;
export default class SplashScreen extends React.Component {
render() {
return (
<Container>
<LogoView>
<Text style={logo.text}>
{" "}
Jennya's <Text style={logo.studio}>Studio </Text>
</Text>
</LogoView>
<CardView>
<SplashCard />
</CardView>
<DotsView></DotsView>
<ButtonView></ButtonView>
<LoginView></LoginView>
</Container>
);
}
}
//Container And Background
const Container = styled.View`
flex: 1;
margin-top: 30px;
margin-bottom: 20px;
margin-left: 18px;
margin-right: 18px;
flex-direction: column;
background-color: #ffffff;
`;
const LogoView = styled.View`
width: 100%;
height: 10%;
background-color: #ff0;
justify-content: center;
align-items: center;
`;
//Logo Styling
const logo = StyleSheet.create({
text: {
fontFamily: "Carrington",
fontSize: 42,
fontWeight: "normal",
fontStyle: "normal",
letterSpacing: -1.01,
textAlign: "center",
color: "#7356bf",
},
studio: {
color: "#ffc043",
},
});
const CardView = styled.View`
height: 55%;
background-color: #7532a8;
`;
const DotsView = styled.View`
height: 3%;
background-color: #eb0e28;
`;
const ButtonView = styled.View`
height: 27%;
background-color: #2929;
`;
const LoginView = styled.View`
height: 5%;
background-color: #f929;
`;
Here is the Splash Screen Card
import React from "react";
import styled from "styled-components/native";
import { Dimensions } from "react-native";
const window = Dimensions.get("window");
//Image Ratio
const ratio = window.width / 240;
const SplashCard = (props) => (
<Container>
<ImageView>
<IllustrationImage
resizeMode="contain"
source={require("../../assets/Illustartions/Illustration1.png")}
/>
</ImageView>
<TitleView>
<Title>Welcome</Title>
</TitleView>
<TextView>
<Text numberOfLines={4} style={{ flex: 1, flexWrap: "wrap" }}>
This can either be a string or a function. Strings are with the rules
as-is. Functions will receive the styled component's props as the first
and only argument.
</Text>
</TextView>
</Container>
);
export default SplashCard;
//Main Card Container
const Container = styled.View`
flex: 1;
background-color: #ffffff;
`;
//Image Position & Size
const ImageView = styled.View`
height: 70%;
justify-content: center;
align-items: center;
background-color: #0f48a3;
`;
const IllustrationImage = styled.Image`
flex: 1;
height: ${ratio * 240}px;
width: ${window.width}px;
max-width: 240px;
max-height: 240px;
`;
//Title Position & Size
const TitleView = styled.View`
height: 10%;
justify-content: center;
align-items: center;
background-color: #8d14de;
`;
const Title = styled.Text`
flex: 1;
font-family: Metropolis-SemiBold;
font-size: 30px;
font-weight: 600;
font-style: normal;
letter-spacing: -0.72px;
text-align: center;
color: #000000;
`;
//Text View
const TextView = styled.View`
flex: 1;
background-color: #db07bf;
`;
//Text Style
const Text = styled.Text`
font-family: Metropolis-Medium;
font-size: 18px;
font-weight: 500;
font-style: normal;
letter-spacing: 1.1px;
text-align: center;
color: #171415;
`;
Here is What it looks like on both android and ios
Image of the cut text in android
Setting a margin around the Text might do the trick. For example, set marginHorizontal style to Text in SplashCard
<Text numberOfLines={4} style={{ flex: 1, flexWrap: "wrap", marginHorizontal:10 }}>
This can either be a string or a function. Strings are with the rules
as-is. Functions will receive the styled component's props as the first
and only argument.
</Text>

Adding a solid stroke to Text

I am trying to add a thick solid stroke to some Text in React Native. I've added a snippet with the desired CSS.
I've tried directly applying the CSS via styled-components but I get an error stating that my value is unable to be parsed.
const Title = styled.Text`
text-shadow: 2px 2px 0px #000, -2px -2px 0px #000, 2px -2px 0px #000, -2px 2px 0px #000;
`;
I have tried using textShadow but this does not apply a solid stroke. This prop relies on a width and height prop for an offset.
Here's a snack for example - https://snack.expo.io/#hannigan/ba7574
h1 {
text-shadow: 2px 2px 0px #000, -2px -2px 0px #000, 2px -2px 0px #000, -2px 2px 0px #000;
color: white;
font-family: 'Arial';
}
<h1>Hello World</h1>
So this works for me, are you sure that it won't work for you in dynamic height?
Edit: I might have now found what you were talking about. I am checking if I can update the snack to work for dynamic views.
Edit2: Alright, made it work. You just need to make the first text non-absolute.
https://snack.expo.io/Bk8ifP!4I
Edit3: As mentioned by Vencovsky it might break if you need to use flex around it. You can hack it with a onLayout like in this Snack: https://snack.expo.io/HJ!PRUKNL
basically you save the height of the text and then use it for height and margin on other views. It hacky, but I have used it in other settings and works fine.
export default class App extends React.Component {
render() {
const myText = 'Hello World. This is my very long text, that can be a few lines height'
return (
<View style={styles.container}>
<View>
<Text style={[styles.paragraph]}>{myText}</Text>
<Text style={[styles.paragraph, styles.abs, {textShadowOffset: {width: -2, height: -2}}]}>{myText}</Text>
<Text style={[styles.paragraph, styles.abs, {textShadowOffset: {width: -2, height: 2}}]}>{myText}</Text>
<Text style={[styles.paragraph, styles.abs, {textShadowOffset: {width: 2, height: -2}}]}>{myText}</Text>
</View>
<Text> 'Here another text' </Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
padding: 8
},
paragraph: { fontSize: 50, color: '#FFF', textShadowColor: 'black', textShadowRadius: 1, textShadowOffset: {
width: 2,
height: 2
}},
abs: {
position: 'absolute',
top: 0, left: 0, right: 0, bottom: 0
}
});
I couldn't find a way to do this with react native's css but I found a way to do a stoke in the text with react-native-svg
<Svg height="60" width="200">
<Text
fill="none"
stroke="purple"
fontSize="20"
fontWeight="bold"
x="100"
y="20"
textAnchor="middle"
>
STROKED TEXT
</Text>
</Svg>
Edit
I know this answer isn't the perfect one, but so far is the only answer I found to do this, but unfortunately it isn't good for dynamic text.

Icon to de right side of the view React-native

im trying to keep my icon in the right side of View component. But im failed.
<StyledView>
<StyledListItem {...props}>
{value}
<Icon name="add" size={24} style={{ right: 0 }} />
</StyledListItem>
<StyledLine></StyledLine>
</StyledView>
styles components:
import styled from 'styled-components/native';
import colors from "../../../styles/colors";
import { styledfont } from "../../../styles/fonts";
export const StyledList = styled.TextInput`
height: 40px;
border: 1px solid gray;
width: 100%;
padding: 0 10px;
`;
export const StyledListItem = styled.Text`
${styledfont.h4}
color: ${colors.blue.primary};
width: 72%;
margin-bottom: 15px;
margin-top: 13px;
margin-left:28px;
flex-direction: row;
`;
export const StyledView = styled.View`
width: 100%;
height: 68px;
`;
export const StyledLine = styled.View`
width: 100%;
height: 1px;
background-color: ${colors.blue.primaryopc20};
`;
export const StyledContainer = styled.View`
width: 100%;
top: 0;
flex: 1;
`;
I try a lot of things, someone can help me? I think that I should use something like flex row, but I do not know how to apply that.
You can add positioning to your components. In this case, I'd try:
<StyledView>
<StyledListItem style={{position: 'relative'}} {...props}>
{value}
<Icon name="add" size={24} style={{ position: 'absolute', right: 0 }} />
</StyledListItem>
<StyledLine></StyledLine>
</StyledView>
You can even leave out the relative positioning on the parent since in react native everything is positioned relative by default
you can wrap icon in view and use marginLeft:'auto' property as:-
```
<StyledView>
<StyledListItem {...props}>
{value}
<View style={{marginLeft:'auto'}}>
<Icon name="add" size={24} style={{ right: 0 }} />
</View>
</StyledListItem>
<StyledLine></StyledLine>
</StyledView>
```