I need to use drawer from native base into react native app for both android ios et android.
Here is the link for native base http://nativebase.io/docs/v2.0.0/components#drawer and below you'll find my code :
import { Container, Header, Title, Content, Button, Icon, Left, Body, Text } from 'native-base';
import { Drawer } from 'native-base';
import SideBar from '../components/SideBar';
class App extends Component {
closeDrawer = () => {
this._drawer._root.close();
}
openDrawer = () => {
alert('open');
this._drawer._root.open();
}
render() {
return (
<Container>
<Header style={{ backgroundColor: '#C0C0C0' }}>
<Left>
<Button transparent onPress={this.openDrawer.bind(this)}>
<Icon style={style.icon} name='menu' />
</Button>
</Left>
<Body style={style.body}>
<Title style={{ color: '#FFF'}}> title </Title>
</Body>
</Header>
<Content>
<Drawer
ref={(ref) => { this._drawer = ref; }}
content={<SideBar />} >
</Drawer>
</Content>
</Container>
);
}
the alert in the method open drawer is working fine, so i know it's not a problem in the button.
I believe you want to wrap everything in the drawer, like so
render() {
return (
<Drawer
ref={(ref) => { this._drawer = ref; }}
content={<SideBar />} >
<Container>
<Header style={{ backgroundColor: '#C0C0C0' }}>
<Left>
<Button transparent onPress={this.openDrawer.bind(this)}>
<Icon style={style.icon} name='menu' />
</Button>
</Left>
<Body style={style.body}>
<Title style={{ color: '#FFF'}}> title </Title>
</Body>
</Header>
<Content>
// Your other content here
</Content>
</Container>
</Drawer>
);
}
Also, on your self-made sidebar component - make sure it has a backgroundColor. Set it to something like #F0F0F0 otherwise it ends up looking mighty strange.
I am writing answer for anyone who is new to developing apps using react native, for this answer the important thing which I will be using is react-navigation.
First is the app.js where we declare the drawer and the other screens which includes a login screen without the drawer menu. The authLoading Screen is used to navigate the users to login or home screen based on the fact whether they are authenticated or not.
App.js
const HomeScreenRouter = createDrawerNavigator(
{
Home: { screen: HomeScreen }
},
{
contentComponent: props => <SideBar {...props} />
}
);
const AuthStack = createStackNavigator({ SignIn: SignInScreen });
export default createAppContainer(createSwitchNavigator(
{
AuthLoading: AuthLoadingScreen,
App: HomeScreenRouter,
Auth: AuthStack,
},
{
initialRouteName: 'AuthLoading',
}
));
with the contentComponent we get the sliding menu in our home screen the Sidebar is a simple component which can have things as desired. Now for the homescreen we will have a button which will also allow users to open the menu from anywhere.
class HomeScreen extends React.Component {
render() {
return (
<Container>
<Header>
<Left>
<Button
transparent
onPress={() => this.props.navigation.openDrawer()}>
<Icon name="menu" />
</Button>
</Left>
<Body>
<Title>Be-in</Title>
</Body>
<Right />
</Header>
<Content>
</Content>
</Container>
);
}
}
export default HomeScreen
versions used in this example are
"react": "16.6.1",
"react-native": "0.57.7",
"react-navigation": "^3.0.8",
I hope it will be helpful to anyone who is intending to implement a drawer and also enable navigation.
Related
I have created header component and i want to open drawer from header component from icon click, currently swipe is opening drawer. please help if anyone know what is the issue
this is my app js code where i created drawer navigator
<NavigationContainer>
<Drawers.Navigator drawerContent={props => <Drawer {...props} />} >
<Drawers.Screen
name="Home"
component={Home}
initialParams={({navigation}) => {
return{
headerTitle:() => <HomeHeader navigation={navigation}/>,
}
}}
/>
<Drawers.Screen
name="Orders"
component={Orders}
/>
<Drawers.Screen
name="Account"
component={Account}
/>
</Drawers.Navigator>
</NavigationContainer>
and this is my header component where i was trying to navigation.openDrawer
export default function HomeHeader({navigation}) {
const openMenu = () => {
navigation.openDrawer();
}
return (
<View style={GlobalStyle.hheader} >
<View style={GlobalStyle.mainMenu} >
<Icon type="material" name="menu" size={26} color="black" onPress={openMenu} />
</View>
<View style={GlobalStyle.near} >
<Text style={GlobalStyle.nTitle}>Your Location</Text>
<Text style={GlobalStyle.nLocate}>Mehran Town <Icon iconStyle={{ marginBottom:-1, }} name='chevron-down' size= {16} type='font-awesome' color='#000'
/></Text>
</View>
</View>
)
}
and finally draweritem code
<DrawerItem
label="Profile"
onPress={() => {props.navigation.navigate('Account')}}
labelStyle={{color: '#000', fontSize:15}}
icon={() => (
<Icon
name='account-circle'
type='material'
color='#4285F4'
size={18}
/>
)}
/>
<DrawerItem
label="Orders"
onPress={() => {props.navigation.navigate('Orders')}}
labelStyle={{color: '#000', fontSize:15}}
navigation={props.navigation}
icon={() => (
<Icon
name='receipt'
type='material-icons'
color='#4285F4'
size={18}
/>
)}
/>
</View>
I don't think headerTitle is place for you return custom header menu.
My suggestion you can render customer header in each screen content and using navigation.openDrawer(); or try create wrapper view for Drawer and render header first. Or create BaseScreen with your custom header and inheritance for each your screen. But headerTitle I don't think it work.
I'm currently using the material-bottom-tabs to implement navigation in my mobile app.
For some odd reason, it isn't displayed correctly but cut off at the bottom of my screen.
This happens regardless of whether I activate gesture control (so the Android built-in navigation bar disappears) or not.
If I add padding to the style of my Tabs.Navigator, then the Tab-Navigation-Bar is still cut off, now by a white padding.
I tried to wrap my Tab.Navigator inside a SafeAreaView (from react-native-safe-area-context) but if I do this, I just get a plain white screen back.
This is my code:
import React, { Component } from 'react';
import { createBottomTabNavigator } from '#react-navigation/bottom-tabs';
import DrawerHome from './DrawerHome';
import Bookmarks from './Bookmarks';
const Tab = createMaterialBottomTabNavigator();
const Stack = createStackNavigator();
//const insets = useSafeArea();
class App extends Component {
constructor(props) {
super(props);
this.state = {
userToken: 1, // set to 'null' in production state
};
}
render() {
return this.userToken === null ? (
<Stack.Screen name="LogIn" component={LoginScreen} />
) : (
<SafeAreaProvider>
<NavigationContainer>
<SafeAreaView>
<Tab.Navigator style={{ paddingBottom: '10%' }}>
<Tab.Screen
name="Current Schedule"
component={CarouselPage}
options={{
tabBarLabel: 'Current\nSchedule',
tabBarIcon: <Ionicons name="ios-calendar" size={20} />,
}}
/>
<Tab.Screen name="Resources" component={ResourceScreen} />
<Tab.Screen
name="Schedule Selection"
component={ScheduleSelectionScreen}
/>
<Tab.Screen name="About" component={AboutScreen} />
</Tab.Navigator>
</SafeAreaView>
</NavigationContainer>
</SafeAreaProvider>
);
}
}
export default App;
A screenshot of the display issue
Try this:
// ...
<NavigationContainer>
<Tab.Navigator>
<Tab.Screen
name="Current Schedule"
component={CarouselPage}
options={{
tabBarLabel: 'Schedule',
tabBarIcon: ({}) => (
<Ionicons name="ios-calendar" size={20} />
),
}}
/>
// ...
</Tab.Navigator>
</NavigationContainer>
// ...
The bar isn't cut off. The reason the text was cut off was, because you put a newline in the tabBarLabel text. I recommend to choose shorter words for your tab labels.
The documentation does not seem to provide an option to increase the padding for the label to allow for longer text.
I'm using Picker component of Native-Base for my react-native application. On IOS everything is ok, whereas, on Android side I can not trigger function I added on onValueChange.
Is there anyone faced this issue before?
How did you fix it? I stuck here almost a day.
Here is my code.
<Picker style={{ width: 200, height: 40}}
iosHeader="Branch"
Header="Branch"
mode="dropdown"
textStyle={{color: 'white'}}
placeholder="Branch"
headerBackButtonText="Geri"
selectedValue={this.state.selectedBranch}
onValueChange={(value)=>this.onBranchSelected(value)}
>
{this.state.branches.map((branches, i)=>{
return(
<Picker.Item label={branches.address_line} value={branches.id} key={i}/>
);
}
)}
</Picker>
It does not call the function onBranchSelected on Android.
I tried your code and was working fine for me.
Pasting my code
import React, { Component } from "react";
import { Platform } from "react-native";
import { Container, Header, Title, Content, Button, Icon, Text, Right, Body, Left, Picker, Form } from "native-base";
export default class PickerExample extends Component {
constructor(props) {
super(props);
this.state = {
branches: [
{ address_line: 'address 1', id: 1 },
{ address_line: 'address 2', id: 2 },
{ address_line: 'address 3', id: 3 },
{ address_line: 'address 4', id: 4 },
{ address_line: 'address 5', id: 5 }],
selected1: 1
};
}
onBranchSelected(value) {
this.setState({
selectedBranch: value
});
}
render() {
return (
<Container>
<Header>
<Left>
<Button transparent>
<Icon name="arrow-back" />
</Button>
</Left>
<Body>
<Title>Picker</Title>
</Body>
<Right />
</Header>
<Content>
<Form>
<Picker
style={{ width: 200, height: 40 }}
iosHeader="Branch"
Header="Branch"
mode="dropdown"
textStyle={{ color: 'grey' }}
placeholder='Select branch'
headerBackButtonText='Geri'
selectedValue={this.state.selectedBranch}
onValueChange={(value) => this.onBranchSelected(value)}
>
{this.state.branches.map((branches, i) => {
return (
<Picker.Item label={branches.address_line} value={branches.id} key={i} />
);
}
)}
</Picker>
</Form>
</Content>
</Container>
);
}
}
Dependencies
"native-base": "2.3.5",
"react": "16.0.0",
"react-native": "0.50.0",
This is known issue with Picker. The issue is trying to use .map. I myself couldn't ever get map to work with Picker. The only thing I could find was an npm package called react-native-smart-picker which I was able to use a .map with. There are limitations.
And FYI I also tried other bootstrap frameworks and this is an issue with vanilla react-native.
Heres the link..
https://www.npmjs.com/package/react-native-smart-picker
Heres my github repo...
https://github.com/GavinThomas1192/motoMechanicMeeKanic/blob/master/App/Components/vehicleMakePicker.js
Heres my code where I implemented it.
<ScrollView>
<View style={{ flex: 1, marginTop: 20 }}>
{this.state.makes.length > 1 ?
<ScrollView>
<SmartPicker
expanded={this.state.expanded}
selectedValue={this.state.selectedMake}
label='Select Make'
onValueChange={this.handleChange.bind(this)}>
{
this.state.makes.map((ele) => {
return (<Picker.Item label={ele} value={ele}/>);
})
}
<Picker.Item label='Select Make' value='Toyota'/>
</SmartPicker>
<Button block onPress={() => this.props.vehicleMake(this.state.selectedMake)}>
<Text>Done</Text>
</Button>
</ScrollView> : <Spinner/>
}
</View>
</ScrollView>
Update to show how I handled no expandable button
<Content>
<Text>Vehicle Stats:</Text>
<Text>Year: {this.state.vehicleYear}</Text>
<Text>Make: {this.state.vehicleMake}</Text>
<Text>Model: {this.state.vehicleModel}</Text>
{this.state.vehicleYear === "" ? <VehicleYearPicker vehicleYear={this.yearPicked}/> : undefined}
{this.state.vehicleYear !== "" && this.state.vehicleMake === "" ?
<VehicleMakePicker pickedYear={this.state.vehicleYear} vehicleMake={this.makePicked}/> : undefined}
{this.state.vehicleModel === "" && this.state.vehicleMake !== "" ?
<VehicleModelPicker homeState={this.state} vehicleModel={this.modelPicked}/> : undefined}
</Content>
For my react-native application I implement navigations with react-native-router-flux. I have a Drawer menu which is accessible through several different pages. On IOS everything is fine. Whereas, not all but on some android devices redirecting links on the drawer menu does not work. Is there someone faced this problem before? And how did you solve it? I used react-native-router-flux on all pages of my application. So, I do not want to use another navigation component in Drawer menu.
Here is my drawer menu code.
import React, {Component} from 'react';
import {Actions} from 'react-native-router-flux';
import {Text,View,Container} from 'react-native';
import {Button,Icon} from 'native-base';
export default class SideBarContent extends Component{
constructor() {
super();
}
render()
{
const css = {
"Button": {color: '#E5DDCB',fontFamily: 'SourceSansPro-Regular'}
}
return(
<View style={{top: 80}} >
<Button transparent onPress={()=>Actions.ordersMain()}><Icon style={{color: "#FFF",margin: 10}} name="md-card"/><Text style={css.Button}>Order History</Text></Button>
<Button transparent onPress={()=>Actions.account()}><Icon style={{color: "#FFF",margin: 10}} name="md-person-add"/><Text style={css.Button}>Profile</Text></Button>
<Button transparent onPress={()=>Actions.addresses()}><Icon style={{color: "#FFF",margin: 10}} name="md-navigate"/><Text style={css.Button}>Addresses</Text></Button>
<Button transparent><Icon style={{color: "#FFF",margin: 10}} name="md-information-circle"/><Text style={css.Button}>Account</Text></Button>
<Button transparent onPress={()=>Actions.category()}><Icon style={{color: "#FFF",margin: 10}} name="md-archive"/><Text style={css.Button}>Categories</Text></Button>
</View>
);
}
}
Here is how I implement menu on pages.
return (
<Drawer
tapToClose={true}
open={false}
type="displace"
content={<SideBarContent />}
ref = {(ref) => this._drawer = ref}
openDrawerOffset={width/3}
closedDrawerOffset={0}
styles={drawerStyles}
tweenHandler={Drawer.tweenPresets.parallax}
elevation={0}
onClose={()=>this.onClose()}
>
<Container style={{backgroundColor: '#FFF'}}>
//....Page Code...
</Container>
</Drawer>
);
Here is image of my drawer.
I followed the facebook documentation on how to generate signed apk exactly. But still I am getting error: undefined is not an object (evaluating 'e.length'
Here is the screenshot
However, the app works fine in Android Emulator with command react-native run-android.
But, I got the issue which was causing the app to crash. It was native-base.
Here is the following code in my App.js:
import React, { Component } from 'react';
import {Text} from 'react-native';
import { Container, Header, Content, Form,Text, Item, Input, Label, Button }
from 'native-base';
export default class ReactNativeExample extends Component {
constructor(props) {
super(props);
this.state = {
username: '',
password: ''
};
this.doSignIn = this.doSignIn.bind(this);
}
doSignIn() {
let formdata = new FormData();
formdata.append("username", this.state.username)
formdata.append("password", this.state.password)
fetch('http://someweb.com/loginUser',{
method: 'post',
headers: {
'Content-Type': 'multipart/form-data',
},
body: formdata
}).then((response) => response.json())
.then((responseData) => {
console.log("Inside responsejson");
if(responseData.error != true) {
console.log('You have logged in...');
}
}).done();
}
render() {
return (
<Container>
<Header />
<Content>
<Form>
<Item floatingLabel style={{margin: 8}}>
<Label>Username</Label>
<Input ref="username" onChangeText={(username) =>
this.setState({username})}/>
</Item>
<Item floatingLabel last style={{margin: 8}}>
<Label>Password</Label>
<Input ref="username" onChangeText={(password) =>
this.setState({password})}/>
</Item>
<Button block info style={{margin: 8}} onPress={this.doSignIn}>
<Text>Login</Text>
</Button>
</Form>
</Content>
</Container>
<Text> Hello </Text>
);
}
}
I want to know what is wrong with the above native-base code that is making the App crash? Is there any way I can make native-base code work?
Thank You.
ReactNative version: 0.50.1
That's because there is import duplicates of Text component
import { Text } from 'react-native';
import { Container, Header, Content, Form,Text, Item, Input, Label, Button }
from 'native-base';
You can import both Text components via as like this
import { Text as NativeText } from 'react-native';
And then use NativeText. Otherwise, do not duplicate your imports.
tried your code. Was able to generate an apk successfully. Didn't find any issue while running the apk. Posting the code.
import React, { Component } from "react";
import { Container, Header, Content, Form, Text, Item, Input, Label,Button } from "native-base";
export default class ReactNativeExample extends Component {
constructor(props) {
super(props);
this.state = {
username: "",
password: "",
};
this.doSignIn = this.doSignIn.bind(this);
}
doSignIn() {
let formdata = new FormData();
formdata.append("username", this.state.username);
formdata.append("password", this.state.password);
fetch("https://httpbin.org/", {
method: "post",
headers: {
"Content-Type": "multipart/form-data",
},
body: formdata,
})
.then(response => console.log("response", response))
.done();
}
render() {
return (
<Container>
<Header />
<Content>
<Form>
<Item floatingLabel style={{ margin: 8 }}>
<Label>Username</Label>
<Input ref="username" onChangeText={username => this.setState({ username })} />
</Item>
<Item floatingLabel last style={{ margin: 8 }}>
<Label>Password</Label>
<Input ref="username" onChangeText={password => this.setState({ password })} />
</Item>
<Button block info style={{ margin: 8 }} onPress={this.doSignIn}>
<Text>Login</Text>
</Button>
</Form>
</Content>
</Container>
);}
}
When using NativeBase components use <Text/> from 'native-base'