Sliding Tabbar Highlight React Native - react-native

Attempting to replicate the following but for a bottom tabbar (moving an underlying blue line that follows the user selection underneath the tabbar):
https://raw.githubusercontent.com/brentvatne/react-native-scrollable-tab-view/master/demo.gif
Here is what I have so far (but the red underline doesn't slide and is static based on the user's selection):
So far here is my code:
return <Tabbar
selected={this.state.selected}
tabHeight={window.height/16}
style={styles.menu}
onTabItemPress={name => this.setState({ selected: name })}
renderTabComponent
renderTabComponent={(name, isActive) => (
<View
style={[
{ borderBottomWidth: 2, justifyContent: 'center', alignItems: 'center' },
isActive ? { borderColor: '#DB202A'} : { borderColor: 'transparent' }
]}>
<Text style={styles.menuText}>{ name }</Text>
</View>
)}>
<Tabbar.Item name="Causes" >
<Text>This is the Causes tab</Text>
</Tabbar.Item>
<Tabbar.Item name="Trending" >
<Text>This is the Trending tab</Text>
</Tabbar.Item>
<Tabbar.Item
name="Home" >
<View style={styles.containerSuper}>
<View style={styles.container}>
{this.renderListView()}
</View>
</View>
</Tabbar.Item>
<Tabbar.Item name="Profile" >
<Text>This is the Profile tab</Text>
</Tabbar.Item>
<Tabbar.Item name="Settings" >
<Text>This is the Settings tab</Text>
</Tabbar.Item>
</Tabbar>

Related

How can I have a custom navigation component in react-native-navigation Stack?

I'm trying:
export default function Navigator() {
return (<>
<Stack.Navigator screenOptions={{
headerShown: false
}} initialRouteName="Home" >
<Stack.Screen name="Home" component={HomeScreen} />
<Stack.Screen name="Feed" component={FeedScreen} />
</Stack.Navigator >
<CustomTabBar />
</>
);
}
And:
export const CustomTabBar = () => {
const onHomePress = () => { }
return (
<SafeAreaView style={styles.safeAreaView}>
<View style={styles.navContainer}>
<View style={{ flex: 1 }}>
<Avatar rounded source={{ uri: 'https://source.unsplash.com/random/100x100?profile picture,smile' }} containerStyle={styles.avatar} />
</View>
<View style={{ flex: 1 }}>
<Chip
title={<View style={styles.pillContainer}>
<Ionicons name='search' color='white' />
<TouchableOpacity onPress={onHomePress}>
<Ionicons name='ios-home' color='white' />
</TouchableOpacity>
<Ionicons name='planet' color='white' />
</View>}
type="outline"
containerStyle={styles.chipContainer}
/>
</View>
<View style={{ flex: 1 }}>
<Animated.View style={styles.btnCircle}>
<TouchableOpacity
style={{
flex: 1,
justifyContent: 'center'
}}
onPress={() => Alert.alert('Click Action')}>
<Ionicons name={'paper-plane-outline'} color={'white'} size={25} />
</TouchableOpacity>
</Animated.View>
</View>
</View>
</SafeAreaView>
);
}
If I move the CustomTabBar inside the Stack.Navigator, we get an error.
but this creates the white area at the bottom:
How can I have my custom navigation element?
StackScreen at custom bottom tab bar is not bad idea.
If you want custom bottom tab bar for use custom tabbar, actually still you can use BottomTabBar but if you want use stack screens, try like this.
<>
<NavigationContainer>
<Stack.Navigator screenOptions={{ headerShown: false }}>
<Stack.Screen name={"TestScreen"} component={TestScreen} />
</Stack.Navigator>
</NavigationContainer>
{/* custom tab bar */}
<View
style={{
position: "absolute",
bottom: 0,
width: "100%",
alignItems: "center",
}}>
<Text>TEST</Text>
<Text>TEST</Text>
<Text>TEST</Text>
<Text>TEST</Text>
</View>
</>
In your case, White Space is'nt custom tab bar's background. And stack screen's height is not "100%".
So In case, you can use position: "absolute", bottom: 0 then screen get full area, and cover the deault background(whitespace).

How to switch from camera button to video record button in react native

I have camera capture button and video recording button on the same container, I want to be able to have camera button when app is launched, then when I a tap Text "Video", the it will switch to video button to record. I have a screenshot of beautyplus app as sample of what I mean
Camera button navigation
return (
<View style={styles.action}>
<View style={{ flexDirection: 'row', justifyContent: 'space-between', paddingHorizontal: 20, marginBottom: 15, alignItems: 'flex-end' }}>
<TouchableOpacity onPress={this.toggleTorch.bind(this)}>
{ this.state.flashon == RNCamera.Constants.FlashMode.off? (
<Icon
name="md-flash-off"
color="black"
size={30}
/>
) : (
<Icon
name="md-flash"
color="black"
size={30}
/>
)
}
</TouchableOpacity>
<View style={{ alignItems: 'center' }}>
<TouchableOpacity onPress={this.takePicture} style={styles.captureBtn} />
</View>
<View style={{ alignItems: 'center' }}>
<TouchableOpacity onPress={this.recordVideo} style={styles.captureVideoBtn}>
{
this.state.recording ?
(<Text>{this.secondsToMMSS(this.state.seconds)}</Text>) :
(null)
}
</TouchableOpacity>
</View>
<TouchableOpacity
onPress={this.reverseCamera}
>
<Icon
name="md-reverse-camera"
color="black"
size={30}
/>
</TouchableOpacity>
</View>
</View>
)
}
}
</RNCamera>
</View>
);
};
}
What is the problem with condition checking?
constructor() {
...
this.state = {capture:'photo'}; // default to photo
}
captureVideo=()=> {...}
capturePhoto=()=> {...}
captureAudio=()=>{...}
capture() {
swicth (this.state.capture)
case 'audio' : captureAudio()
...
}
render () {
...
<TouchableOpacity onPress={()=>this.setState({capture:'video'})}>
<Text>Video</Text></TouchableOpacity>
<TouchableOpacity onPress={()=>this.startCapture()}><Text>Start</Text>
</TouchableOpacity>
<TouchableOpacity onPress={()=>this.setState({capture:'photo'})}>
<Text>Video</Text></TouchableOpacity>
...
}

React Native Drawer Item I want to set icon right side via

Please check screenshot
1 - Screenshot of Code
2 - Screenshot of Sidemenu
<View
style={{
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'space-between',
padding: 12,
color: 'white',
borderBottomWidth: 1,
borderBottomColor: '#aaaaaa',
backgroundColor:
global.currentScreenIndex === item.screenToNavigate
? '#c1c0c0'
: '#fff',
}}
key={key}
onStartShouldSetResponder={() =>
handleClick(key, item.screenToNavigate)
}>
{/* <View style={{ marginRight: 5, marginLeft: 10 }}>
<Icon name={item.navOptionThumb} size={25} color="#273983" />
</View> */}
<Text style={{ fontSize: 17, color: 'black', marginLeft: 10,}}>
{item.navOptionName}
</Text>
<View style={{ marginRight:5}}>
{/* <Icon name={item.navOptionThumb} size={25} color="#808080" /> */}
<Icon name={item.navOptionThumb} size={20} color="#273983" />
</View>
</View>
try this its worked for me (react navigation v6)
<DrawerNavigator.Screen
name="Home"
options={{
drawerIcon: ({color}) => (
<Icon name="md-home" color={color}
style={{ position: "absolute",right: 10,}}
/>
)
}}
/>
Use drawerLabel property
const SyncIconFunc = {
drawerLabel: config=>
<View style={{flexDirection:'row'}}>
<Text style={{color:Colors.bg}}>
Sync Data
</Text>
<Feather
onPress={() => alert("bell pressed")}
style={{ position:'absolute',right: 10}}
size={24}
color={Colors.bg}
name="bell"
/>
</View>
};
<Drawer.Navigator>
<Drawer.Screen name="Catalogues" component={FolderList}/>
<Drawer.Screen name="Sync Data" component={SyncData} options={SyncIconFunc}/>
<Drawer.Screen name="Notifications" component={FolderList}/>
</Drawer.Navigator>

Unable to display content inside a SwipeRow

I am trying to wrap the data present in a list and make the list swipeable using SwipeRow. But after I add the SwipeRow on top of my ListItem tag, the content is not displayed.
I have tried using renderItem but that seems unrelatable and doesn't work.
return(
// <SwipeRow style={{backgroundColor:'red'}}>
//body={
<View style={{backgroundColor: 'red'}}>
<ListItem style={{ width: '100%' }} onPress={() => this.navigationTo(this.props.data.h)}>
<View style={{ marginHorizontal: 15, alignSelf: 'flex-start' }}>
{this.props.data.iconType === 'Material' ? (
<MaterialIcon style={{}} size={24} name={this.props.data.i} color="#87898B" />
) : (
<MaterialCommunityIcons style={{}} size={24} name={this.props.data.i} color="#87898B" />
)}
</View>
<View>
<Text style={styles.heading}>{this.props.data.h}</Text>
<Text style={styles.description}>
{this.props.data.dp}{' '}
<B>
{count} {this.props.data.db}
</B>{' '}
{this.props.data.da}.
</Text>
<Text style={styles.metadata}>{this.props.data.m}</Text>
</View>
</ListItem>
</View>
// }
// </SwipeRow>
);
Probably try giving some styles to SwipeRow assuming you have imported the swipeRow
You can use renderRow in ListView
<ListView
style={{flex: 1, backgroundColor:'red'}}
dataSource={this.props.data}
renderRow={ data => (
<SwipeRow
leftOpenValue={75}
rightOpenValue={-75}
>
<View style={{ marginHorizontal: 15, alignSelf: 'flex-start' }}>
{this.props.data.iconType === 'Material' ? (
<MaterialIcon style={{}} size={24} name={data.i} color="#87898B" />
) : (
<MaterialCommunityIcons style={{}} size={24} name={data.i} color="#87898B" />
)}
</View>
<View>
<Text style={styles.heading}>{data.h}</Text>
<Text style={styles.description}>
{data.dp}{' '}
<B>
{count} {data.db}
</B>{' '}
{data.da}.
</Text>
<Text style={styles.metadata}>{data.m}</Text>
</View>
</SwipeRow>
)}
/>

How to add extra item at the bottom of the drawer navigation manually (like logout button)?

I want to add logout button to the bottom of the drawer navigation in my RN app.
I am trying to use contentComponent the following way:
const DrawerWithLogoutButton = (props) => (
<ScrollView>
<SafeAreaView style={styles.container} forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
</SafeAreaView>
<Button
style={styles.logoutButton}
title="Logout"
onPress={() => props.navigation.navigate('Login') }/>
</ScrollView>
);
export default Home = createDrawerNavigator({
// screens
}, {
// other settings
contentComponent: DrawerWithLogoutButton,
});
const styles = StyleSheet.create({
container: {
flex: 1,
flexDirection: 'column',
},
logoutButton: {
backgroundColor: 'red',
position: 'absolute',
bottom: 0
}
});
In the result I have the Logout button at the bottom of the menu. But I want it to be located at the bottom of the drawer panel instead
Also I would want the Logout button to look like other menu items and had an icon
Is there a way to create drawer navigator with a menu item which has no screen but is just an action like Logout as in my case?
I was able to align Logout at the bottom of the drawer menu with adding justifyContent: 'space-between' to the ScrollView container. You can see the result in the picture
The result source code looks the following way:
const DrawerWithLogoutButton = (props) => (
<ScrollView contentContainerStyle={{flex: 1, flexDirection: 'column', justifyContent: 'space-between' }}>
<SafeAreaView forceInset={{ top: 'always', horizontal: 'never' }}>
<DrawerItems {...props} />
</SafeAreaView>
<TouchableOpacity>
<View style={styles.item}>
<View style={styles.iconContainer}>
<Image source={require('./img/logout.png')} style={styles.icon}></Image>
</View>
<Text style={styles.label}>Logout</Text>
</View>
</TouchableOpacity>
</ScrollView>
);
const styles = StyleSheet.create({
item: {
flexDirection: 'row',
alignItems: 'center',
},
label: {
margin: 16,
fontWeight: 'bold',
color: 'rgba(0, 0, 0, .87)',
},
iconContainer: {
marginHorizontal: 16,
width: 24,
alignItems: 'center',
},
icon: {
width: 24,
height: 24,
}
});
React Navigation docs recommend wrapping the drawer navigation with a custom content drawer function. This is what we do did to give our drawer a logout button, but also keep all of the Drawer.Screens in place.
In the code below we create a CustomDrawerContent that contains a DrawerItem as our logout button. This function wraps the Drawer.Navigator through its property drawerContent. Our final drawer then looks like:
Home (Drawer.Screen)
Edit Profile (Drawer.Screen)
Landing (Drawer.Screen)
Logout (DrawerItem)
const Drawer = createDrawerNavigator();
function CustomDrawerContent(props) {
return (
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
<DrawerItem label={() => <Text style={{ color: 'white' }}>Logout</Text>}
style={{backgroundColor: 'red'}}
onPress={() => alert('Logged out')}
/>
</DrawerContentScrollView>
);
}
function App(props) {
return (
<Provider store={store}>
<View style={styles.container}>
<StatusBar translucent={true} />
<NavigationContainer>
<Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name='Home' component={Home} />
<Drawer.Screen name='Edit Profile' component={EditProfile} />
<Drawer.Screen name='Landing' component={Landing} />
</Drawer.Navigator>
</NavigationContainer>
</View>
</Provider>
)
}
Similar to William Griffins answer, except their answer does not end up with the logout button at the bottom of the drawer. To have logout be at the bottom, I put my DrawerContentScrollView inside a SafeAreaView, then beneath the DrawerContentScrollView I put a regular View containing the DrawerItem, which is the logout button.
function CustomDrawerContent(props) {
return (
<SafeAreaView style={{flex: 1}} forceInset={{top: "always", horizontal: "never"}}>
<DrawerContentScrollView {...props}>
<DrawerItemList {...props} />
</DrawerContentScrollView>
<View>
<DrawerItem label={"Logout"}
style={styles.logoutDrawerItem}
onPress={() => console.log('Logout pressed!')}
/>
</View>
</SafeAreaView>
);
}
function App(props) {
return (
<Provider store={store}>
<View style={styles.container}>
<StatusBar translucent={true} />
<NavigationContainer>
<Drawer.Navigator drawerContent={props => <CustomDrawerContent {...props} />}>
<Drawer.Screen name='Home' component={Home} />
<Drawer.Screen name='Edit Profile' component={EditProfile} />
<Drawer.Screen name='Landing' component={Landing} />
</Drawer.Navigator>
</NavigationContainer>
</View>
</Provider>
)
}
const styles = StyleSheet.create({
logoutDrawerItem: {
borderRadius: 5,
},
});
Any items you place beneath the DrawerContentScrollView will be placed at the bottom of the drawer.
Note that I set borderRadius to 5 on the logout DrawerItem, so that it closely matches the border radius of regular drawer items.
You can set position:'absolute' and buttom:0 like this code:
<TouchableOpacity
onPress={() => {this.logout()}}
style={{ bottom: 0, position: 'absolute', width: '100%' }}>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', flexDirection:'row', alignItems: 'center' }}>
<Icon name="md-log-out" style={{marginRight: 10, color: '#444'}} size={20}/>
<Text style={{color: '#444'}}>Logout</Text>
</View>
</TouchableOpacity>
You can change the style to make it like other buttons. I hope this will help you...
The accepted answer did not work out for me directly. I had to do some modifications, but in general the secret is indeed using justifyContent: 'space-between'.
import {View} from 'react-native';
import {
createDrawerNavigator,
DrawerContentScrollView,
DrawerItem,
DrawerItemList,
DrawerContentComponentProps,
} from '#react-navigation/drawer';
const Drawer = createDrawerNavigator();
function CustomDrawerContent(props: DrawerContentComponentProps) {
return (
<DrawerContentScrollView
{...props}
contentContainerStyle={{flex: 1, justifyContent: 'space-between'}}>
<View style={{justifyContent: 'flex-start'}}>
<DrawerItemList {...props} />
</View>
<DrawerItem
label="Logout"
onPress={() => console.log('Logged out')}
/>
</DrawerContentScrollView>
);
}
.
.
.
<Drawer.Navigator
initialRouteName="HomeScreen"
drawerContent={(props) => <CustomDrawerContent {...props} />}
drawerContentOptions={{
activeTintColor: color.primaryDark,
itemStyle: {
backgroundColor: 'transperant',
borderColor: color.primaryDark,
borderBottomWidth: 1,
opacity: 0.8,
},
}}
drawerStyle={styles.drawer}>
<Drawer.Screen name="Home" component={HomeScreen} />
<Drawer.Screen name="Notifications" component={NotificationsScreen} />
</Drawer.Navigator>