React navigation- Wrap button in TabBar - react-native

I'm new in React Native and i'm trying to do the TabBar in the image. My problem is to put a button in the tabbar. If someone can help me or have an idea to create this tabbar it could be really nice.
THX

you can check
this link. One of the props to pass TabNavigator is tabBarComponent. If you do not want the default styling or have to make custom tabBar you can specify the how the component should look.
In your case this should work.
import React from 'react';
import {View, Text, TouchableOpacity, Dimensions} from 'react-native';
import {TabNavigator} from 'react-navigation';
import Tab1Screen from '../components/tab1Screen';
import Tab2Screen from '../components/tab2Screen';
var {height, width} = Dimensions.get('window');
const mainRoutes = TabNavigator({
Tab1: {screen: Tab1Screen},
Tab2: {screen: Tab2Screen}
},
{
tabBarComponent:({navigation}) => (
<View style={{flex: 0.1, borderColor: 'green', borderWidth: 1}}>
<View style={{flexDirection:'row', justifyContent: 'space-around', alignItems: 'center', paddingTop: 15}}>
<View style={{width: 40, height: 40, borderRadius: 20, borderColor: 'red', borderWidth: 1, position: 'absolute', left: width/2.5, bottom:13 }}></View>
<TouchableOpacity onPress={() => navigation.navigate('Tab1')}>
<Text>Tab1</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => navigation.navigate('Tab2')}>
<Text>Tab2</Text>
</TouchableOpacity>
</View>
</View>
)});
export default mainRoutes;

I had to do something similar. I'm using React Navigation v5 and in my case, the button had to execute a custom action instead of navigating to a tab. So this is what I did:
import styles from './styles';
// Other needed imports...
// ...
<Tab.Screen
name="Add Recipe"
component={() => null}
options={{
tabBarButton: () => (
<TouchableOpacity
style={styles.addIconWrapper}
onPress={() => {
// Your custom action here
}}
>
<View style={styles.addIconBackground}>
<Image source={assets.add} style={styles.addIconImage} />
</View>
</TouchableOpacity>
),
}}
/>;
And inside styles.js:
// ...
addIconWrapper: {
width: '20%',
justifyContent: 'center',
alignItems: 'center',
},
addIconBackground: {
marginTop: -30,
backgroundColor: '#85c349',
borderColor: 'white',
shadowOffset: { width: 2, height: 2 },
shadowColor: '#999',
shadowOpacity: 0.5,
borderRadius: 1000,
width: 42,
height: 42,
justifyContent: 'center',
alignItems: 'center',
},
addIconImage: {
tintColor: 'white',
},
Final result

Related

React Native How to show an element above bottom tab navigator

I am trying to show a media player above the bottom tab navigator just like in spotify app.
It should stay there in same state across all the screens (bottom tabs).
Any suggestions or approaches to implement this in React native ?
You just need to calculate the height of Bottom Navbar and make a View with Position:'absolute' and to keep it above Bottom Navbar assign the height of Navbar to 'bottom' of this View.
<View>
<View
style={{
position: "absolute",
backgroundColor: "#4470AE",
bottom: 75,
flexDirection: "row",
width: "90%",
height: 60,
paddingVertical: "3%",
alignSelf: "center",
borderRadius: 12,
margin: "3%",
}}
></View>
<View
style={{
position: "absolute",
backgroundColor: "orange",
bottom: 0,
height: 75,
flexDirection: "row",
width: "100%",
justifyContent: "space-around",
paddingVertical: "3%",
borderTopLeftRadius: 20,
borderTopRightRadius: 20,
}}
>
</View>
</View>
I would suggest to use an React.Context as you wanna show the same object (music control panel) on each screen with same state and not an replica on each screen.
For positioning I suggest using an absolute position. This works together with "react-navigation" because header and bottom areas are changed.
This means bottom:0 is no longer the screens bottom within a tab navigator it's right above the TabBar.
Here is an example:
import * as React from 'react';
import { Text, View } from 'react-native';
import { NavigationContainer } from '#react-navigation/native';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import { MusicControlPanelContext, MusicControlPanelConsumer } from './components/MusicControlContext';
import {MusicControlPanel} from './components/MusicContorlPanel'
function HomeScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Home!</Text>
<MusicControlPanelConsumer/>
</View>
);
}
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text>Settings!</Text>
<MusicControlPanelConsumer/>
</View>
);
}
const Tab = createBottomTabNavigator();
export default function App() {
return (
<MusicControlPanelContext.Provider value={MusicControlPanel}>
<>
<NavigationContainer>
<Tab.Navigator
tabBarOptions={{
activeTintColor: '#000000',
inactiveTintColor: 'gray',
activeBackgroundColor: '#ff0000',
inactiveBackgroundColor: '#ff0000',
style: {
backgroundColor: '#ffffff',
},
}}>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
</NavigationContainer>
</>
</MusicControlPanelContext.Provider>
);
}
import * as React from 'react';
import { MusicControlPanelContext } from './MusicControlPanelContext';
import { View } from 'react-native';
function MusicControlPanelConsumer() {
return (
<MusicControlPanelContext.Consumer>
{(Component) => <Component/>}
</MusicControlPanelContext.Consumer>
);
}
export { MusicControlPanelConsumer };
import * as React from 'react';
import {MusicControlPanel} from '../MusicContorlPanel'
export const MusicControlPanelContext = React.createContext<React.FC>(MusicControlPanel);
import * as React from 'react';
import { View, Text, Pressable } from 'react-native';
export const MusicControlPanel: React.FC = () => {
const [startStop, setStartStop] = React.useState(false);
return (
<View
style={{
position: 'absolute',
width: '90%',
height: 100,
backgroundColor: '#ff00ff',
bottom: 10,
justifyContent: 'center',
alignItems: 'center'
}}>
<Pressable
onPress={() =>
setStartStop((val) => {
return !val;
})
}>
<Text>{startStop ? 'Start' : 'Stop'}</Text>
</Pressable>
</View>
);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I just solved this problem
import BottomTabBar
call tabBar props in tab navigator
wrap it with empty tag
import and insert your component above the BottomTabBar
import { BottomTabBar} from '#react-navigation/bottom-tabs';
import SmallVideoPlay from 'YOUR_PATH_OF_THE_COMPONENT';
<Tab.Navigator
tabBar={(props) => (
<>
< SmallVideoPlay />
<BottomTabBar {...props} />
</>
)}
>
<Tab.Screen name="HomeStack" component={Home}/>
....
</Tab.Navigator/>

TouchableOpacity outside parent View in absolute positive not works react native

I was making Picker component but what I found is Touchable Opacity in absolute positions outside from it's parent view not works.
const App = () => {
const data = [2, 3, 4, 23]
const [isOpen, setIsOpen] = useState(true);
return (
<View style={{ flex: 1, backgroundColor: 'white', justifyContent: 'center', alignItems: 'center' }}>
<TouchableOpacity style={styles.container} onPress={setIsOpen.bind(null, true)} disabled={isOpen}>
<Text>3</Text>
<Image source={require('./assets/downArrow2.png')} />
{
isOpen && (
<View style={styles.optionsContainer}>
{
data.map((number, index) => (
<View key={index}>
<TouchableOpacity onPress={() => { setIsOpen(false) }}>
<View style={{ padding: 10, paddingRight: 40 }}>
<Text>{number}</Text>
</View>
</TouchableOpacity>
<View style={{ height: 1, width: '100%', backgroundColor: 'white' }} />
</View>
))
}
</View>
)
}
</TouchableOpacity>
</View>
)
}
const styles = StyleSheet.create({
container: {
width: 48,
paddingVertical: 8,
paddingRight: 5,
paddingLeft: 8,
borderWidth: 1,
borderColor: 'grey',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
position: 'relative'
},
optionsContainer:
position: 'absolute',
top: -1,
left: -1,
backgroundColor: 'grey'
}
})
So, There is outer TouchableOpacity Component & inside we are mapping many TouchableOpacity Component where children are in Absolute View.
TouchableOpacity inside it's parent's view works, but not Works outside Parent View with absolute position. Is their someOne to help me out with it???
It even Not works with TouchableNativeFeedback
Using TouchableOpacity from react-native-gesture-handler solves the issue of absolute position touches. However, it leads to some styling issues such as the overflow "visible" property not working.
So what you can do is that, for the parent TouchableOpacity you can use react-native's TouchableOpacity and for children you can use react-native-gesture-handler's TouchableOpacity to get the touch to work even when positioned absolutely.
This is the updates code. Please note the imports.
import { useState } from 'react';
import {View, StyleSheet, Text, TouchableOpacity as TouchableRN} from 'react-native';
import {TouchableOpacity} from 'react-native-gesture-handler'
const App = () => {
const data = [2, 3, 4, 23]
const [isOpen, setIsOpen] = useState(false);
return (
<View style={{ flex: 1, backgroundColor: 'white', justifyContent: 'center', alignItems: 'center' }}>
<TouchableRN style={styles.container} onPress={setIsOpen.bind(null, true)} disabled={isOpen}>
<Text>3</Text>
<Image source={require('./assets/downArrow2.png')} />
{
isOpen && (
<View style={styles.optionsContainer}>
{
data.map((number, index) => (
<View key={index}>
<TouchableOpacity onPress={() => { setIsOpen(false) }}>
<View style={{ padding: 10, paddingRight: 40 }}>
<Text>{number}</Text>
</View>
</TouchableOpacity>
<View style={{ height: 1, width: '100%', backgroundColor: 'white' }} />
</View>
))
}
</View>
)
}
</TouchableRN>
</View>
)
}
const styles = StyleSheet.create({
container: {
width: 48,
paddingVertical: 8,
paddingRight: 5,
paddingLeft: 8,
borderWidth: 1,
borderColor: 'grey',
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
position: 'relative'
},
optionsContainer: {
position: 'absolute',
top: -1,
left: -1,
backgroundColor: 'grey'
}
})
export default App;

Pressing a button only dismisses the keyboard

I have a Modal which contains a TextInput and a Button. When the modal is opened, the keyboard appears which enables to enter text in the TextInput.
My problem is that when I press the button for the first time, the keyboard is dismissed but the button onPress method is not triggered.
import React from 'react';
import {
StyleSheet,
View,
Modal,
Text,
TextInput,
InteractionManager,
ScrollView,
TouchableWithoutFeedback,
TouchableOpacity,
Keyboard,
} from 'react-native';
import theme from '../../styles/theme.style';
import { MaterialCommunityIcons } from '#expo/vector-icons';
import I18n from '../../utils/i18n';
class RenameDrillModal extends React.Component {
// Enables to open the keyboard when the component is rendered
inputRef = React.createRef();
componentDidMount() {
this.focusInputWithKeyboard();
}
focusInputWithKeyboard() {
InteractionManager.runAfterInteractions(() => {
this.inputRef.current.focus();
});
}
render() {
return (
<View>
<Modal
animationType="fade"
transparent
visible
onRequestClose={() => {
this.props.close();
}}
>
{/* The sole purpose of the three following tags (TouchableOpacity, ScrollView, TouchableWithoutFeedback) is to close the modal when clicking outside of it */}
<TouchableOpacity
activeOpacity={1}
style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}
onPressOut={() => {
this.props.close();
}}
>
<ScrollView directionalLockEnabled>
<TouchableWithoutFeedback onPress={Keyboard.dismiss}>
<View style={styles.modalTitleView}>
<Text style={styles.modalTitleText}>{`${this.props.drillTitle}`}</Text>
<View style={{ minWidth: '50%', flexDirection: 'row' }}>
<TextInput
style={{ minWidth: '90%', margin: 5, marginBottom: 0, flex: 1 }}
placeholder={I18n.t('drillEditor.drillManager.clickHereToRename')}
onChangeText={text => this.props.textModified(text)}
ref={this.inputRef}
/>
<MaterialCommunityIcons
name="check"
color={theme.COLOR_PRIMARY}
size={26}
onPress={() => {
console.log('Rename, onPress called');
this.props.close();
this.props.confirmNewName();
}}
/>
</View>
</View>
</TouchableWithoutFeedback>
</ScrollView>
</TouchableOpacity>
</Modal>
</View>
);
}
}
const styles = StyleSheet.create({
modalTitleView: {
margin: 20,
backgroundColor: 'white',
borderRadius: 20,
padding: 20,
alignItems: 'center',
shadowColor: '#000',
shadowOffset: {
width: 0,
height: 2,
},
shadowOpacity: 0.25,
shadowRadius: 3.84,
elevation: 5,
},
modalTitleText: {
fontWeight: 'bold',
fontSize: 20,
marginBottom: 15,
textAlign: 'center',
},
item: {
backgroundColor: theme.BACKGROUND_COLOR_LIGHT,
padding: 8,
borderRadius: 10,
marginVertical: 8,
marginHorizontal: 8,
flexDirection: 'row',
justifyContent: 'space-between',
alignItems: 'center',
},
});
export default RenameDrillModal;
The second press on the button works but do you know how I could both dismiss the keyboard and push the button by only pressing once?

React navigation 5 custom header component

I am trying to make custom header in React Navigation v5 which I've been using since v3 but somehow it doesn't work in v5. my header is successfuly shown with its animation on scroll down but i cannot click anything inside the header and also i cannot inspect my header.
const Stack = createStackNavigator();
class HomeStack extends Component {
render() {
return (
<Stack.Navigator initialRouteName="Home">
<Stack.Screen
name="Home"
component={Home}
options={{
header: (props) => <HomeHeader {...props} />,
}}
/>
</Stack.Navigator>
);
}
}
and here is my header component
/* eslint-disable react-native/no-inline-styles */
import React, {Component} from 'react';
import {View, Text, StyleSheet, TouchableOpacity, Animated} from 'react-native';
class HomeHeader extends Component {
handleClickSearch = () => {
this.props.navigation.navigate('Search');
};
render() {
const {
scene: {
route: {params},
},
} = this.props;
if (!(params && params.opacity && params.bgColor)) return null;
// console.log(params.bgColor)
return (
<Animated.View
style={{
...styles.container,
backgroundColor: params.bgColor,
// elevation: params.elevation
}}>
<Animated.View
style={{
...styles.searchContainer,
opacity: params.opacity,
}}>
<View
style={{
flex: 1,
height: '100%',
backgroundColor: '#fff',
width: '100%',
borderRadius: 10,
borderWidth: 1,
borderColor: '#666666',
}}>
<TouchableOpacity
activeOpacity={1}
style={styles.search}
onPress={() => this.handleClickSearch()}>
<Text style={styles.searchText}>
Search batik, sepatu kulit...
</Text>
</TouchableOpacity>
</View>
</Animated.View>
</Animated.View>
);
}
}
const styles = StyleSheet.create({
container: {
width: '100%',
height: 60,
paddingTop: 10,
paddingBottom: 5,
paddingHorizontal: 10,
position: 'absolute',
top: 0,
left: 0,
right: 0,
justifyContent: 'center',
alignItems: 'center',
},
searchContainer: {
width: '90%',
height: 38,
justifyContent: 'center',
},
search: {
paddingHorizontal: 10,
paddingVertical: 5,
height: '100%',
justifyContent: 'center',
},
searchText: {
color: '#666666',
fontSize: 12,
letterSpacing: 0.5,
lineHeight: 14,
},
});
export default HomeHeader;
how can i make fully custom header component in react navigation 5? Thanks!

Icons with gradient colors

Is there any way I can add gradient colors to Icons in react-native / expo?
I want to make icons like those :
Tried this variant using MaskedView and LinearGradient packages https://github.com/react-native-linear-gradient/react-native-linear-gradient/issues/198#issuecomment-590821900. I use this snippet with Icon from native-base and this solution works perfectly for me.
import React from 'react'
import { Text, View, StyleSheet } from 'react-native'
import Icon from 'react-native-vector-icons/MaterialCommunityIcons'
import LinearGradient from 'react-native-linear-gradient'
import MaskedView from '#react-native-community/masked-view'
const size = 40
export function PowerOff({ ...rest }) {
return (
<View style={{ width: size }} {...rest}>
<MaskedView
style={{ flex: 1, flexDirection: 'row', height: size }}
maskElement={
<View
style={{
backgroundColor: 'transparent',
justifyContent: 'center',
alignItems: 'center',
}}>
<Icon
name="power"
size={size}
color="white"
style={styles.shadow}
/>
</View>
}>
<LinearGradient
colors={['#F7C650', 'rgba(247, 198, 80, 0.71)']}
style={{ flex: 1 }}
/>
</MaskedView>
</View>
)
}
const styles = StyleSheet.create({
shadow: {
shadowColor: 'black',
shadowOpacity: 0.5,
shadowRadius: 5,
shadowOffset: {
width: 0,
height: 1,
},
},
})