FlatList Horizontal Scrolling - javascript

I'm creating onBoarding screens and I have created each of the screen item as a component and trying to render them with Flatlist so far everything is working smoothly but when I swipe the flatlist to see the other screens it's not working it swipes 40% and and forcefully shows the current screen it seems like there is some flex styling issues and I could able to figure it out please suggest.
Here is the video for explaination: https://youtube.com/shorts/pHbTs7ifMww
OnBoardingScreen.js
import React, { useState } from 'react';
import { Dimensions, FlatList, SafeAreaView, View, StyleSheet, Text, Image } from 'react-native';
const { width, height } = Dimensions.get('window');
const COLORS = {primary : '#ff006c', white: '#ffffff', black: '#000000'};
const slides = [
{
id: '1',
image: require('../../images/OnBoardingImages/1.png'),
title: 'You can mark time',
description: 'Lorem ipsum is a placeholder text commonly used to demonstrate the visual',
},
{
id: '2',
image: require('../../images/OnBoardingImages/2.png'),
title: 'You can mark time',
description: 'Lorem ipsum is a placeholder text commonly used to demonstrate the visual',
},
{
id: '3',
image: require('../../images/OnBoardingImages/3.png'),
title: 'You can mark time',
description: 'Lorem ipsum is a placeholder text commonly used to demonstrate the visual',
},
]
const Slide = ({item}) => {
return (
<View style={styles.slideView}>
<Image source={item.image} style={styles.slideImage} />
<Text style={styles.slideTitle}>{item.title}</Text>
<Text style={styles.slideDescription}>{item.description}</Text>
</View>
);
}
const OnBoardingScreen = ({ navigation }) => {
const [currentSlideIndex, setCurrentSlideIndex] = useState(0);
const Footer = () => {
return (
<View style={styles.footer}>
<View style={styles.pagination}>
{slides.map((_, index) => (<View key={index} style={[styles.paginationItem, currentSlideIndex == index && {backgroundColor: 'grey'} ]} /> ))}
</View>
</View>
);
};
return (
<SafeAreaView style={styles.root}>
<FlatList
data={slides}
contentContainerStyle={{flex: 1}}
showsHorizontalScrollIndicator={false}
horizontal
pagingEnabled
renderItem={({item}) => <Slide item={item} />} />
<Footer />
</SafeAreaView>
);
};
export default OnBoardingScreen;
const styles = StyleSheet.create({
root: {
flex: 1,
backgroundColor: COLORS.white,
},
slideView: {
alignItems: 'center',
},
slideImage: {
height: '75%',
width: width,
resizeMode: 'contain',
},
slideTitle: {
color: COLORS.primary,
fontSize: '22',
fontWeight: 'bold',
marginVertical: 10,
paddingHorizontal: 10,
textAlign: 'center',
},
slideDescription: {
fontSize: 18,
paddingHorizontal: 20,
color: 'grey',
textAlign: 'center',
},
footer: {
height: height * 0.25,
paddingHorizontal: 20,
justifyContent: 'space-between',
},
pagination: {
flexDirection: 'row',
justifyContent: 'center',
marginTop: 20,
},
paginationItem: {
height: 10,
width: 10,
backgroundColor: COLORS.primary,
marginHorizontal: 3,
borderRadius: 50,
},
});
App.js
import { StatusBar } from 'expo-status-bar';
import { StyleSheet, Text, View } from 'react-native';
import Navigation from './src/navigation';
export default function App() {
return (
<View style={styles.container}>
<Navigation />
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
},
});

Update this style
slideView: {
alignItems: 'center',
width: width
},

Related

How we can give auto height to FlatList based on its list items content in React Native

I am using FlatList in my component which is working fine. All is wanted is that my entire screen should have an automatic height to it and FlatList contents never does out of the screen height.
Also, the height of FlatList should be changed based on content/items in it rather than giving any fixed height.
How I can be acheived both cases like automatic screen height and auto height of FlatList content?
Code:
import React, { useState, useEffect } from 'react';
import {
View,
StyleSheet,
useWindowDimensions,
Text,
FlatList,
SafeAreaView,
TouchableOpacity,
} from 'react-native';
import { LinearGradient as LinearGradientView } from 'expo-linear-gradient';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
import { ActivityIndicator, ThemeProvider } from 'react-native-paper';
import { ScrollView } from 'react-native-gesture-handler';
import { useIsFocused, useNavigation } from '#react-navigation/native';
import Svg, { Path } from 'react-native-svg';
import { BASE_GRADIENT_HEAVY } from '../rooms/Background';
import { useResolution } from '../browse/useResolution';
import { OnboardingNavigationProp } from '../navigation/LinkingConfiguration';
import { LIGHT_THEME } from '../Theme';
import { OnboardingBack } from './OnboardingBack';
import {
useOnboardingYearsOfExperiencePage,
useOnboardingYearsOfExperienceSubmit,
} from './useOnboardingYearsOfExperiencePage';
export function OnboardingYearsOfExperience({ route }: { route?: any }) {
const { height } = useWindowDimensions();
const { top: safeAreaTop } = useSafeAreaInsets();
const [selectedId, setSelectedId] = useState<{ id: string }>();
const [role_id, setRoleId] = useState<number>();
const { navigate } =
useNavigation<OnboardingNavigationProp<'OnboardingConfirmAllDetails'>>();
const parentUrl = route?.params.result.onboarding._links;
const initialUrl = parentUrl.onboarding_years_of_experience.href;
const onboardingUrl = parentUrl.self.href;
useEffect(() => {
setRoleId(route?.params.role_id);
}, []);
const isFocused = useIsFocused();
const { contentType } = useResolution();
const {
data: result,
isLoading,
error,
} = useOnboardingYearsOfExperiencePage(initialUrl, contentType, role_id, {
enabled: isFocused,
notifyOnChangeProps: ['data', 'isLoading', 'error'],
});
const {
mutateAsync: updateYearsOfExperience,
isLoading: isUpdatingYearsOfExperience,
error: yearsOfExperienceUpdateError,
} = useOnboardingYearsOfExperienceSubmit(onboardingUrl);
const Arrow = ({ style }: { style: object }) => {
return (
<Svg width="7" height="11" viewBox="0 0 7 11" fill="none" style={style}>
<Path
d="M6.28711 5.53931C6.28711 5.31649 6.19783 5.12476 6.02452 4.95376L1.9911 1.07251C1.85455 0.937781 1.68649 0.865234 1.48692 0.865234C1.07728 0.865234 0.751664 1.18651 0.751664 1.58552C0.751664 1.78243 0.830441 1.96898 0.977493 2.11407L4.54875 5.53413L0.977492 8.95937C0.835692 9.10446 0.751663 9.28583 0.751662 9.48792C0.751662 9.88693 1.07728 10.2082 1.48692 10.2082C1.68649 10.2082 1.85455 10.1357 1.99635 10.0009L6.02452 6.11968C6.20308 5.93832 6.28711 5.75695 6.28711 5.53931Z"
fill="#4D4D4D"
/>
</Svg>
);
};
const Item = ({
item,
onPress,
}: {
item?: { id: string; title: string };
onPress: () => void;
}) => (
<TouchableOpacity onPress={onPress}>
<Text
style={{
color: '#4D4D4D',
fontFamily: 'Inter_400Regular',
fontStyle: 'normal',
fontWeight: '400',
fontSize: 16,
lineHeight: 32,
padding: 3,
margin: 2,
}}
>
{item?.title}
</Text>
</TouchableOpacity>
);
const renderItem = ({ item }: { item: { id: string; title: string } }) => {
return (
<React.Fragment>
<View
style={{
flexDirection: 'row',
justifyContent: 'space-between',
borderRadius: 5,
backgroundColor:
selectedId?.id === item?.id ? '#F2F2F2' : 'transparent',
}}
>
<View style={{ width: '90%' }}>
<Item
item={item}
onPress={() => {
setSelectedId({ id: item.id });
updateYearsOfExperience({ id: item.id, role_id })
.then((result) => {
navigate('Onboarding', {
screen: 'OnboardingConfirmAllDetails',
params: { result },
});
})
.catch(() => {});
}}
/>
</View>
<View style={{ width: '10%' }}>
<Arrow style={{ position: 'absolute', top: 16, right: 10 }} />
</View>
</View>
</React.Fragment>
);
};
return (
<ThemeProvider theme={LIGHT_THEME}>
<View style={{ height: safeAreaTop }} />
<View style={styles.topHeader}>
<LinearGradientView
{...BASE_GRADIENT_HEAVY}
style={[styles.gradiantStyle]}
/>
</View>
<View style={styles.innerContainer}>
<ScrollView
contentContainerStyle={{
marginHorizontal: 'auto',
alignSelf: 'center',
width: '100%',
backgroundColor: '#ffffff',
height: '100%',
}}
>
<OnboardingBack
style={{
left: -10,
}}
/>
<Text style={styles.topHeadline}>
How many years of experience do you have?
</Text>
<Text style={styles.middleHeadline}>
Jump-start the conversation by sharing your years of experience
within healthcare.
</Text>
{isLoading || isUpdatingYearsOfExperience ? (
<ActivityIndicator size="large" />
) : (
<SafeAreaView>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
data={Object.values(
result!['years_of_experiences']['years_of_experiences_list']
)}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
style={{
borderWidth: 1,
borderStyle: 'solid',
borderColor: '#D7D7D7',
borderRadius: 5,
padding: 12,
height: '27%',
}}
ListEmptyComponent={
<View>
<Text>No data found</Text>
</View>
}
/>
</SafeAreaView>
)}
</ScrollView>
</View>
</ThemeProvider>
);
}
const styles = StyleSheet.create({
innerContainer: {
display: 'flex',
position: 'relative',
backgroundColor: 'white',
padding: 18,
},
topHeader: {
backgroundColor: '#e5dede',
padding: 0,
width: '100%',
},
topHeadline: {
fontSize: 24,
fontFamily: 'CircularStd_Medium',
fontStyle: 'normal',
fontWeight: '500',
color: '#222222',
marginTop: 40.6,
marginBottom: 14.6,
display: 'flex',
alignItems: 'center',
lineHeight: 32,
},
middleHeadline: {
fontSize: 16,
fontFamily: 'Inter_400Regular',
fontStyle: 'normal',
fontWeight: '400',
lineHeight: 24,
color: '#4D4D4D',
marginBottom: 30,
},
gradiantStyle: {
width: 248.4,
height: 4.71,
},
});
add the following style to your flatList =>
style={{maxHeight:'what ever you want',flexGrow:0}}

underline the clicked text element

I have a list of text elements that I want to underline when clicked. If I add the text decoration to the tabText then obviously it is applied to all items. How can I make sure that the when I click on another tab, the underline from the previous tab gets removed?
Is there any way I can add or remove items from the style element upon clicking on an item?
//onPress={() => {}}>
const tabs = [
{
id: 1,
text: 'Alle List',
},
{
id: 2,
text: 'Second',
},
];
export const Tab: React.FunctionComponent = () => {
return (
<View style={styles.tabView}>
{tabs.map((item: any) => (
<View>
<Text style={styles.tabText}>{item.text}</Text>
</View>
))}
</View>
);
};
const styles = StyleSheet.create({
tabView: {
paddingTop: moderateScale(15),
paddingLeft: moderateScale(20),
paddingRight: moderateScale(20),
flexDirection: 'row',
justifyContent: 'space-between',
},
tabText: {
color: 'white',
paddingBottom: moderateScale(10),
//textDecorationLine: 'underline'
},
});
Codesandbox (with tabText items as an array too):
https://snack.expo.io/#nhammad/shallow-watermelon
You can use useState to save the selected index and then apply another style based on the selected index. Here is a quick modification to your script and the snack link is at the end.
import * as React from 'react';
import { Text, View, StyleSheet, TouchableOpacity } from 'react-native';
const tabs = [
{
id: 1,
text: 'All Friends',
},
{
id: 2,
text: 'Second',
},
{
id: 3,
text: 'Third',
},
];
export default function App() {
const [selected, setSelected] = React.useState(null)
return (
<View style={styles.container}>
<View style={styles.tabView}>
{tabs.map((item: any, index) => (
<TouchableOpacity onPress={()=>setSelected(index)}>
<View>
<Text style={[styles.tabText,selected===index?styles.selected:null]}>{item.text}</Text>
</View>
</TouchableOpacity>
))}
</View>
</View>
);
}
const styles = StyleSheet.create({
tabView: {
paddingTop: 15,
paddingLeft: 20,
paddingRight: 20,
flexDirection: 'row',
justifyContent: 'space-between',
},
tabText: {
color: 'black',
paddingBottom: 10,
},
selected: {
textDecorationLine: 'underline'
},
});
https://snack.expo.io/#saachitech/da6280
You can add different styles for your tab depending on active route
<Text style={[(this.props.activeRouteName == route.routeName) ? styles.tabActiveText: styles.tabText]}>{item.text}</Text>
And then in the styles
tabActiveText: {
color: 'white',
paddingBottom: moderateScale(10),
textDecorationLine: 'underline'
}

React Native Component Exception <Text strings must be rendered within a Text component>

I am trying to build a react native application with the expo, First I try to build this application with my chrome web browser, it was worked without any issue after that I try to test the application with my android device and I'm getting an exception - "Text strings must be rendered within a <Text> component" HomeScreen.js files. I have no idea why this happened. My code as follows,
/*This is an Example of Grid View in React Native*/
// import * as React from "react";
import React from 'react';
import { Image, FlatList, StyleSheet, View, Text, TouchableOpacity, TextInput } from 'react-native';
import { COLORS } from '../../asserts/Colors/Colors';
import { CATEGORIES } from '../../asserts/mocks/itemListData';
import CategoryGridTitle from '../components/HomeGridTile';
import { HeaderButtons, Item } from 'react-navigation-header-buttons';
import { HeaderButton } from '../components/HeaderButton';
import HomeScreenButton from '../components/HomeScreenButton';
//import all the components we will need
const renderTopBarItems = (topBarItems) => {
return (
<TouchableOpacity
style={styles.topBar}>
<Text style={styles.textStyle}> {topBarItems.item.category} </Text>
</TouchableOpacity>
)
}
const HomeScreen = props => {
const renderGridItem = (itemData) => {
return <CategoryGridTitle
title={itemData.item.title}
image={itemData.item.image}
onSelect={() => {
props.navigation.navigate({
routeName: 'PaymentHandlerScreen',
params: {
categoryId: itemData.item.id
}
});
}} />;
}
// const [images, setImages] = React.useState(picsumImages);
return (
<View style={styles.mainBody}>
<View style={styles.searchContainer}>
<TextInput
placeholder='Search'
style={styles.formField}
placeholderTextColor={'#888888'}
/>
<TouchableOpacity onPress={() => props.navigation.navigate('BarCodeScannerScreen')}
style={styles.saveFormField}>
<Image
source={require('../../../images/barcode.png')}
style={{
width: '100%',
height: '30%',
resizeMode: 'contain',
alignContent: 'center',
}}
/> </TouchableOpacity>
</View>
<View style={styles.tabBar}>
<FlatList
horizontal
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderTopBarItems} />
</View>
<FlatList
keyExtractor={(item, index) => item.id}
data={CATEGORIES}
renderItem={renderGridItem}
numColumns={3} />
<HomeScreenButton style={styles.buttonView} />
</View>
);
};
HomeScreen.navigationOptions = navigationData => {
return {
headerTitle: 'Tickets',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title='profile'
iconName='ios-star'
onPress={() => {
console.log('profile clicked');
}} />
<Item
title='more'
iconName='md-more'
onPress={() => {
console.log('more clicked');
}} />
</HeaderButtons>
)
};
};
export default HomeScreen;
const styles = StyleSheet.create({
mainBody: {
flex: 1,
justifyContent: 'center',
backgroundColor: COLORS.background,
paddingTop: '3%',
},
searchContainer: {
flex: 1,
flexDirection: 'row',
},
tabBar: {
paddingBottom: '3%',
},
topBar: {
width: 150,
borderWidth: 1,
borderRadius: 20,
borderColor: COLORS.primary_blue,
padding: '5%',
marginLeft: '5%',
},
textStyle: {
color: COLORS.primary_blue,
textAlign: 'center',
fontWeight: 'bold',
fontSize: 14,
},
formField: {
flex: 4,
borderWidth: 1,
padding: '4%',
marginLeft: '2%',
borderRadius: 10,
borderColor: COLORS.gray,
backgroundColor: COLORS.gray,
fontSize: 15,
height: '35%',
},
saveFormField: {
flex: 0.5,
justifyContent: 'space-between',
alignItems: 'center',
margin: 10,
},
buttonView: {
position: 'absolute',
bottom: 0,
left: 0,
},
});
Thank you.
I ran into this error a couple of times. RN doesn't like extra spaces in tags. try removing the spaces before and after {topBarItems.item.category}
<Text style={styles.textStyle}>{topBarItems.item.category}</Text>

How can I make a touchable opacity when another touchableopacity is clicked and set the text in it to the value entered in a text input

I'm a 13-year-old beginner to react native, and I need help with the problem in the title.
I need to do that all on a touchable opacity click. I have tried searching for other solutions on google but found nothing.
It's actually a tutorial on Youtube.
Here is the link: Tutorial
Please help me.
Thank you.
import React, { useState } from 'react';
import { StyleSheet, Text, View, FlatList, TextInput, TouchableOpacity } from 'react-native';
import Header from './components/header';
import TodoItem from './components/todoItem';
export default function App() {
const [todos, setTodos] = useState([
{ text: 'turn on laptop', key: '1'},
{ text: 'create an app', key: '2'},
{ text: 'play on the switch', key: '3'}
]);
const addToDo = () => {
}
const PressHandler = (key) => {
setTodos((prevTodos) => {
return prevTodos.filter(todo => todo.key != key);
});
}
return (
<View style={styles.container}>
<Header />
<View style={styles.content}>
{/* todo form */}
<View style={styles.list}>
<FlatList
data={todos}
renderItem={({ item }) => (
<TodoItem item={item} PressHandler={PressHandler}/>
)}
/>
</View>
</View>
<TextInput style={styles.todoInput} maxLength={20} onChange={() => this.setState} />
<TouchableOpacity style={styles.submitTodo} onPress={addToDo}>
<Text style={styles.submitTodoText}>Done</Text>
</TouchableOpacity>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
},
content: {
padding: 40,
},
todoInput: {
position: "absolute",
bottom: 1,
},
todoInput: {
height: 31,
borderColor: "coral",
borderStyle: "dashed",
borderWidth: 1,
borderRadius: 10,
position: "absolute",
bottom: 26,
width: "73%",
textAlign: "center",
marginLeft: 25,
},
submitTodo: {
padding: 10,
width: "15%",
position: "absolute",
right: 15,
bottom: 26,
backgroundColor: "coral",
borderRadius: 10,
alignItems: "center",
},
submitTodoText: {
color: "#fff",
fontSize: 10,
}
});
Again Thank you, for spending time on this.

How do I center the text within the lightblue flexbox?

import React, { Component } from 'react';
import { View, Text, FlatList, TouchableOpacity, Dimensions, StyleSheet } from 'react-native';
const data = [
{id: 'Music', value: 'Music'},
{id: 'Events', value: 'Events'},
{id: 'About Us', value: 'About Us'},
{id: 'Benefits', value: 'Benefits'},
{id: 'Account', value: 'Account'},
{id: 'Social Media', value: 'Social Media'},
{id: 'FAQ', value: 'FAQ'},
{id: 'Settings', value: 'Settings'}
];
const numColumns = 2;
const size = Dimensions.get('window').width/numColumns;
export const Grid = () => {
return (
<FlatList
style={{ marginTop: 20 }}
data={data}
renderItem={({item}) => (
<TouchableOpacity style={styles.itemContainer}>
<Text style={styles.item}>{item.value}</Text>
</TouchableOpacity>
)}
keyExtractor={item => item.id}
numColumns={numColumns} />
);
}
const styles = StyleSheet.create({
itemContainer: {
width: size,
height: size
},
item: {
flex: 1,
margin: 15,
fontSize: 25,
fontWeight: 'bold',
color: 'white',
backgroundColor: 'lightblue'
}
});
I want to be able to center text in both axes
I tried using justifyContent: "center" in the child and parent views but it doesn't work.
textAlign: "center" is able to align the text horizontally.
try like this.
export const Grid = () => {
return (
<FlatList
style={{ marginTop: 20 }}
data={data}
renderItem={({item}) => (
<TouchableOpacity style={styles.itemContainer}>
<View style={styles.item}>
<Text style={styles.itemText}>{item.value}</Text>
</View>
</TouchableOpacity>
)}
keyExtractor={item => item.id}
numColumns={numColumns} />
);
}
const styles = StyleSheet.create({
itemContainer: {
width: size,
height: size
},
item: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
margin: 15,
backgroundColor: 'lightblue'
},
itemText: {
fontSize: 25,
textAlign: 'center',
fontWeight: 'bold',
color: 'white',
}
});
Please attach a screenshot, asking questions about designing in react native. Coming to the answer you can try this.
item:{
alignSelf: 'center',
flex: 1,
margin: 15,
fontSize: 25,
fontWeight: 'bold',
color: 'white',
backgroundColor: 'lightblue'
},
itemContainer: {
width: size,
height: size,
justifyContent: 'center',
alignItems: 'center'
},
Your itemContainer class is missing the display: flex property. This is needed to use flexbox properties on the flex items.

Categories