Text Component exists as below.
const Text = ({
color,
fontSize,
fontWeight,
children,
}: Props) => {
return (
<Root // styled-component
color={color}
fontSize={fontSize}
fontWeight={fontWeight}
>
{children}
</Root>
);
};
const Root = styled.div`
${props => `color: ${props.color};`}
${props => `font-size: ${props.fontSize};`}
${props => `font-weight: ${props.fontWeight};`}
`;
export default Text;
Color, fontSize, and fontWeight are externally managed in the form of objects.
export const color = {
purple: "#683CED",
light_purple: "#925CE9",
orange: "#F58229",
light_gray1: "#DDDDDD",
light_gray2: "#EEEEEE",
light_gray3: "#F9F9F9",
light_gray4: "#D9D9D9",
gray: "#666666",
dark_gray: "#999999",
black: "#000000",
white: "#FFFFFF",
};
export const font = {
size: {
menubar: "10px",
xs: "11px",
s: "12px",
m: "13px",
content: "14px",
title: "16px",
header: "18px",
},
weight: {
regular: "400",
bold: "700",
},
};
When using that component:
import { color, font } from "example-path"
<Text color={color.black} fontSize{font.size.s} fontWeight={font.weight.regular}>Example Text</Text>
This use seems to significantly increase the length of the code where the Text component is used. So, I would like to create in advance all cases of fontSize and fontWeight values that Text components can have and use them as follows.
<Text.T1 color={color.black}>T1</Text> // fontSize = xs and fontWeight = regular
<Text.T2 color={color.black}>T2</Text> // fontSize = s and fontWeight = regular
<Text.T3 color={color.black}>T3</Text> // fontSize = m and fontWeight = regular
....
When a Text component and a font object are given, is there a way to create all possible combinations of font values in advance and group them with the Text component as in the example above?
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'
}
I try to build a news app that shows on the MainPage an overview of news items.
The first 3 items need to be rendered different as the rest, using a FlatList.
First item is a 100% background image with some text on it (did this with: if index === 0))
The second and third item needs to be background images with titles in a row (so next to each other)
The rests is a list with image, title, and date (underneath each other)
I tried everything but item 2 and 3 is not working.
Tried with this little basic test:
import React, { Component } from "react";
import { View, StyleSheet, Text, FlatList } from "react-native";
export default class Screen1 extends Component {
state = {
data: [
{
text: "one"
},
{
item1: {
text: "two"
},
item2: {
text: "three"
}
},
{
item1: {
text: "four"
},
item2: {
text: "five"
}
},
{
item1: {
text: "six"
}
}
]
};
renderItem = ({ item, index }) => {
if (index === 0) {
return (
<View style={styles.bigSquare}>
<Text> {item.text} </Text>{" "}
</View>
);
} else if (index > 0 || index <= 3) {
return (
<View
style={{
flexDirection: "row"
}}
>
{" "}
{item.item2 && (
<View
style={[
styles.smallSquare,
{
backgroundColor: "red"
}
]}
>
<Text> {item.item2.text} </Text> <Text> {item.item2.text} </Text>{" "}
</View>
)}{" "}
</View>
);
}
};
keyExtractor = (item, index) => `${index}`;
render() {
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem}
keyExtractor={this.keyExtractor}
/>{" "}
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1
},
bigSquare: {
flexDirection: "column",
height: 220,
width: "100%",
margin: 10,
backgroundColor: "yellow",
justifyContent: "center",
alignItems: "center"
},
smallSquare: {
height: 100,
width: 100,
margin: 10,
backgroundColor: "green",
justifyContent: "center",
alignItems: "center"
}
});
Can someone point me in the right direction?
Example:
This approach is a little bit different. Separate your list into 3 parts which include,
First item
Second & third items
Rest of items (use FlatList to render this part)
Finally, you can display those 3 parts in different ways. But make sure to display part 1 & 2 as a ListHeaderComponent of FlatList.
import React, { Component } from "react";
import { SafeAreaView, View, FlatList, StyleSheet, Text, Dimensions } from "react-native";
const ScreenWidth = Dimensions.get('window').width;
const DATA = [
{
id: "1",
title: "First Item"
},
{
id: "2",
title: "Second Item"
},
{
id: "3",
title: "Third Item"
},
{
id: "4",
title: "Forth Item"
},
{
id: "5",
title: "Fifth Item"
},
{
id: "6",
title: "Sixth Item"
},
{
id: "7",
title: "Seventh Item"
}
];
export default class Example extends Component {
renderHeader = () => (
<View>
{/* Display index === 0 item */}
<View style={styles.bigSquare}>
<Text>{DATA[0].title}</Text>
</View>
{/* Display index > 0 && index < 3 items */}
<View style={{ flexDirection: 'row' }}>
<View style={styles.middleSqure}>
<Text>{DATA[1].title}</Text>
</View>
<View style={styles.middleSqure}>
<Text>{DATA[2].title}</Text>
</View>
</View>
</View>
)
renderItems = ({ item }) => (
<View style={styles.smallSquare}>
<Text>{item.title}</Text>
</View>
);
render() {
return (
<SafeAreaView style={{flex: 1, marginTop: 20}}>
{/* Display rest of item in a FlatList */}
<FlatList
data={DATA.slice(2)}
renderItem={this.renderItems}
ListHeaderComponent={this.renderHeader}
keyExtractor={item => item.id}
/>
</SafeAreaView>
);
}
}
const styles = StyleSheet.create({
bigSquare: {
height: 220,
width: ScreenWidth - 20,
margin: 10,
backgroundColor: "yellow",
justifyContent: "center",
alignItems: "center"
},
middleSqure: {
height: (ScreenWidth - 40) / 2,
width: (ScreenWidth - 40) / 2,
margin: 10,
backgroundColor: "red",
justifyContent: "center",
alignItems: "center"
},
smallSquare: {
height: 100,
width: 100,
margin: 10,
backgroundColor: "green",
justifyContent: "center",
alignItems: "center"
},
});
Hope this helps you. Feel free for doubts.
In React Native iOS, I would like to slide in and out of a like in the following picture.
In the following example, when a button is pressed, the Payment Information view pops up from the bottom, and when the collapse button is pressed, it goes back down and disappears.
What would be the correct and proper way to go about doing so?
Thank you in advance!
EDIT
Basically, you need to absolute-position your view to the bottom of the screen. Then you translate its y value to equal its height. (The sub view must have a specific height in order to know how much to move it)
Code:
'use strict';
import React, {Component} from 'react';
import ReactNative from 'react-native';
const {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight,
Animated
} = ReactNative;
var isHidden = true;
class AppContainer extends Component {
constructor(props) {
super(props);
this.state = {
bounceValue: new Animated.Value(100), //This is the initial position of the subview
buttonText: "Show Subview"
};
}
_toggleSubview() {
this.setState({
buttonText: !isHidden ? "Show Subview" : "Hide Subview"
});
var toValue = 100;
if(isHidden) {
toValue = 0;
}
//This will animate the transalteY of the subview between 0 & 100 depending on its current state
//100 comes from the style below, which is the height of the subview.
Animated.spring(
this.state.bounceValue,
{
toValue: toValue,
velocity: 3,
tension: 2,
friction: 8,
}
).start();
isHidden = !isHidden;
}
render() {
return (
<View style={styles.container}>
<TouchableHighlight style={styles.button} onPress={()=> {this._toggleSubview()}}>
<Text style={styles.buttonText}>{this.state.buttonText}</Text>
</TouchableHighlight>
<Animated.View
style={[styles.subView,
{transform: [{translateY: this.state.bounceValue}]}]}
>
<Text>This is a sub view</Text>
</Animated.View>
</View>
);
}
}
var styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
marginTop: 66
},
button: {
padding: 8,
},
buttonText: {
fontSize: 17,
color: "#007AFF"
},
subView: {
position: "absolute",
bottom: 0,
left: 0,
right: 0,
backgroundColor: "#FFFFFF",
height: 100,
}
});
AppRegistry.registerComponent('AppContainer', () => AppContainer);
I know it is a little bit late, but thought it might be useful for someone. You should try out a component called rn-sliding-out-panel. It works awesomely. https://github.com/octopitus/rn-sliding-up-panel
<SlidingUpPanel
draggableRange={top: 1000, bottom: 0}
showBackdrop={true|false /*For making it modal-like*/}
ref={c => this._panel = c}
visible={ture|false /*If you want it to be visible on load*/}
></SlidingUpPanel>
And you can even open it from an external button:
<Button onPress={()=>{this._panel.transitionTo(1000)}} title='Expand'></Button>
You can install it via npm: sudo npm install rn-sliding-out-panel --save on your react-native root directory.
I hope it helps someone :D
I've created a reusable BottomSheet component that accepts any content.
This is how it looks like:
Here's the code (in TypeScript) of the BottomSheet component:
import * as React from 'react'
import {
Animated,
Easing,
Pressable,
StyleSheet,
useWindowDimensions,
View,
} from 'react-native'
const DEFAULT_HEIGHT = 300
function useAnimatedBottom(show: boolean, height: number = DEFAULT_HEIGHT) {
const animatedValue = React.useRef(new Animated.Value(0))
const bottom = animatedValue.current.interpolate({
inputRange: [0, 1],
outputRange: [-height, 0],
})
React.useEffect(() => {
if (show) {
Animated.timing(animatedValue.current, {
toValue: 1,
duration: 350,
// Accelerate then decelerate - https://cubic-bezier.com/#.28,0,.63,1
easing: Easing.bezier(0.28, 0, 0.63, 1),
useNativeDriver: false, // 'bottom' is not supported by native animated module
}).start()
} else {
Animated.timing(animatedValue.current, {
toValue: 0,
duration: 250,
// Accelerate - https://easings.net/#easeInCubic
easing: Easing.cubic,
useNativeDriver: false,
}).start()
}
}, [show])
return bottom
}
interface Props {
children: React.ReactNode
show: boolean
height?: number
onOuterClick?: () => void
}
export function BottomSheet({
children,
show,
height = DEFAULT_HEIGHT,
onOuterClick,
}: Props) {
const { height: screenHeight } = useWindowDimensions()
const bottom = useAnimatedBottom(show, height)
return (
<>
{/* Outer semitransparent overlay - remove it if you don't want it */}
{show && (
<Pressable
onPress={onOuterClick}
style={[styles.outerOverlay, { height: screenHeight }]}
>
<View />
</Pressable>
)}
<Animated.View style={[styles.bottomSheet, { height, bottom }]}>
{children}
</Animated.View>
</>
)
}
const styles = StyleSheet.create({
outerOverlay: {
position: 'absolute',
width: '100%',
zIndex: 1,
backgroundColor: 'black',
opacity: 0.3,
},
bottomSheet: {
position: 'absolute',
width: '100%',
zIndex: 1,
// Here you can set a common style for all bottom sheets, or nothing if you
// want different designs
backgroundColor: 'dodgerblue',
borderRadius: 16,
},
})
I put this code in a file named BottomSheet.tsx.
This is how you use the BottomSheet:
import * as React from 'react'
import {
Pressable,
SafeAreaView,
StatusBar,
StyleSheet,
Text,
View,
} from 'react-native'
import { BottomSheet } from './src/BottomSheet'
const App = () => {
const [showBottomSheet, setShowBottomSheet] = React.useState(false)
const hide = () => {
setShowBottomSheet(false)
}
return (
<SafeAreaView style={styles.safeAreaView}>
<StatusBar barStyle={'dark-content'} />
<View style={styles.container}>
<Pressable
onPress={() => {
setShowBottomSheet(true)
}}
style={styles.showButton}
>
<Text style={styles.buttonText}>Show bottom sheet</Text>
</Pressable>
</View>
<BottomSheet show={showBottomSheet} height={290} onOuterClick={hide}>
<View style={styles.bottomSheetContent}>
<Text style={styles.bottomSheetText}>Hey boys, hey girls!</Text>
<Pressable onPress={hide} style={styles.bottomSheetCloseButton}>
<Text style={styles.buttonText}>X Close</Text>
</Pressable>
</View>
</BottomSheet>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
safeAreaView: {
flex: 1,
},
container: {
flex: 1,
},
showButton: {
marginTop: 48,
padding: 16,
backgroundColor: 'mediumspringgreen',
alignSelf: 'center',
borderRadius: 8,
},
buttonText: {
fontSize: 20,
},
bottomSheetContent: {
padding: 40,
alignItems: 'center',
},
bottomSheetText: {
fontSize: 24,
marginBottom: 80,
},
bottomSheetCloseButton: {
padding: 16,
backgroundColor: 'deeppink',
borderRadius: 8,
},
})
export default App
Notes:
I've put an outer semitransparent overlay, but you can get rid of it by deleting it.
I've chosen to close the modal when you click on the outer semitransparent overlay. This is done with the onOuterClick callback, which is optional - don't pass it if you don't want to do anything.
I've put some styling (blue background + border radius) that applies to all bottom sheets, but you can remove it if you want to have different styles.
After a quite long search I found very good library called react-native-swipe-down with MIT licence.
It will help you make a slider <View /> with no effort.
I Hope this library help you out.
import SwipeUpDown from 'react-native-swipe-up-down';
<SwipeUpDown
itemMini={<ItemMini />} // Pass props component when collapsed
itemFull={<ItemFull />} // Pass props component when show full
onShowMini={() => console.log('mini')}
onShowFull={() => console.log('full')}
onMoveDown={() => console.log('down')}
onMoveUp={() => console.log('up')}
disablePressToShow={false} // Press item mini to show full
style={{ backgroundColor: 'green' }} // style for swipe
/>
To achive above type of requirnment we can take help of some greate libraries
1 #gorhom/bottom-sheet
2 react-native-raw-bottom-sheet
But if we want to do with nativelly please find a code below, I'll try to justify the answer:)
For some animation effects I'll take reference from blow site
how-to-create-moving-animations-in-react-native
import React, { useState } from 'react'
import { SafeAreaView, View, ScrollView, Text, Dimensions, TouchableOpacity, Animated } from 'react-native'
const App = () => {
const { height, width } = Dimensions.get('window')
const SCREEN_HEIGHT = Math.round(height)
const SCREEN_WIDTH = Math.round(width)
// Animation
const startValue = new Animated.Value(Math.round(height + height * 0.3))
const endValue = Math.round(height - height * 0.3)
const duration = 1000
const _showBottomView = (key) => {
const toValue = key === 'HIDE' ? height : endValue
Animated.timing(startValue, {
toValue,
duration: duration,
useNativeDriver: true,
}).start()
}
return (
<SafeAreaView style={{ flex: 1, backgroundColor: 'rgba(0,0,0,0.1)' }}>
{/* Header */}
<View style={{ flex: 1, alignItems: 'center', justifyContent: 'center', borderWidth: 1, borderColor: 'black', margin: 5 }}>
<Text>
Header
</Text>
</View>
<View style={{ flex: 9, borderWidth: 1, borderColor: 'black', margin: 5 }}>
<ScrollView
style={{ flex: 1 }}>
{/* Title View */}
<View style={{ height: SCREEN_HEIGHT * 0.1, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
<Text>
Content ONE
</Text>
</View>
<View style={{ height: SCREEN_HEIGHT * 0.5, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
<Text>
Content TWO
</Text>
</View>
<View style={{ height: SCREEN_HEIGHT * 0.2, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', }}>
<TouchableOpacity
activeOpacity={0.85}
onPress={() => _showBottomView()}
style={{ height: SCREEN_HEIGHT * 0.065, width: '75%', borderRadius: 5, borderWidth: 1, borderColor: 'green', alignItems: 'center', justifyContent: 'center', }}>
<Text>
SHOW BOTTOM VIEW
</Text>
</TouchableOpacity>
</View>
<View style={{ height: SCREEN_HEIGHT * 0.3, width: '95%', borderColor: 'black', borderWidth: 1, marginLeft: '2.5%', marginTop: SCREEN_HEIGHT * 0.01, alignItems: 'center', justifyContent: 'center', marginBottom: SCREEN_HEIGHT * 0.01 }}>
<Text>
...REST_CONTENT...
</Text>
</View>
</ScrollView>
</View>
{/* Bottom view */}
<Animated.View
style={[
{
position: 'absolute',
height: height * 0.3,
width: width,
backgroundColor: 'white',
alignItems: 'center', justifyContent: 'center',
borderTopRightRadius: 23, borderTopLeftRadius: 23,
transform: [
{
translateY: startValue
},
],
},
]} >
<TouchableOpacity
activeOpacity={0.85}
onPress={() => _showBottomView('HIDE')}
style={{ height: SCREEN_HEIGHT * 0.065, width: '75%', borderRadius: 5, borderWidth: 1, borderColor: 'green', alignItems: 'center', justifyContent: 'center', }}>
<Text>
HIDE BOTTOM VIEW
</Text>
</TouchableOpacity>
</Animated.View>
</SafeAreaView>
)
}
export default App
Demo