Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible Solve For System Navigation #28

Open
keeleycarrigan opened this issue May 15, 2017 · 15 comments
Open

Possible Solve For System Navigation #28

keeleycarrigan opened this issue May 15, 2017 · 15 comments

Comments

@keeleycarrigan
Copy link
Contributor

I'm not well versed in Android phone usage, much less Android development but it seems like I might have found something to allow the OS to apply the proper bottom padding to the view. Would be great if this works out because I'd much rather use your tabs than a drawer for navigation.

https://medium.com/google-developers/why-would-i-want-to-fitssystemwindows-4e26d9ce1eec

TLDR - seems like android:fitsSystemWindows=“true” might work.

@timomeh
Copy link
Owner

timomeh commented May 15, 2017

Hmmm. android:fitsSystemWindows="true" could work if there were an Android Layout for the Bottom Navigation. Since it's an only-JS Component, there really is no Android Layout here.

I could write a Bridge for this, but then I would much rather write a standalone module which applies fitsSystemWindows on a child view (some kind of Higher Order Component).

Then again, fitsSystemWindows could simply be a prop (or a style) for View in React Native itself.

I think the solution with a Bridge in a separate module would be nice. Right now I don't have time for this. Maybe someone wants to grab this and make it?

@keeleycarrigan
Copy link
Contributor Author

Yea I was looking at the attribute wrong. When I first saw it I was just thinking it was an attribute you could put in AndroidManifest.xml

@keeleycarrigan
Copy link
Contributor Author

Actually, would this module work? https://www.npmjs.com/package/react-native-detect-navbar-android

@timomeh
Copy link
Owner

timomeh commented May 15, 2017

This looks very promising! If you have time for this, would you mind testing it and maybe sharing some code, if it works? Thank you!

@keeleycarrigan
Copy link
Contributor Author

Yes! I will check it out. I'm super excited because I've been searching for a way to use your module for a couple days now, haha.

@timomeh
Copy link
Owner

timomeh commented May 15, 2017

Of course you could use it without the behind-the-nav-bar-thingy, but of course it looks waaay better this way!

@keeleycarrigan
Copy link
Contributor Author

That package is working in my simulator but I need to make a pull request to the author to update the documentation because it's off a little and I had to investigate a bunch to see why it wasn't working initially. But I think this is a real solve!

@keeleycarrigan
Copy link
Contributor Author

keeleycarrigan commented May 16, 2017

Only issue I'm seeing with the attributes to make the bar transparent is the header for a Stack Navigator goes behind the status bar.

This can be fixed by added padding and height to a header. Styles could be perfected though.

navigationOptions: ({navigation}) => ({
        headerStyle: {
          paddingTop: 30,
          height: 60 + 30,
        }
    })

image

@timomeh
Copy link
Owner

timomeh commented May 16, 2017

Looks very promising! Thank you very much. So I think that could be the solution. Can you maybe share some code for the innerStyles of the BottomNavigation working together with this detection module? This way anybody who's interested in doing this has a solution right away.

@keeleycarrigan
Copy link
Contributor Author

Still working on an example implementation. I have a couple ideas now but because the soft keyboard check is a promise it is returning after I need it in the simple example project I've got. I'm also still wrapping my head around React Navigation so I'm trying to figure out the best place to put this logic to apply the bottom padding.

@keeleycarrigan
Copy link
Contributor Author

keeleycarrigan commented May 25, 2017

Here's a basic example. I had to wrap the main tab navigator in a component because DetectNavbar returns a promise and most times the promise doesn't return until the component is rendered. If you don't use React Navigation it would be pretty similar to this, but this was the only way I could get the TabNavigator to re-render when the promise returns. You also need to add padding to the top of any StackNavigator headers when setting the Android bars to transparent. I'm open to any suggestions on how to make this better.

class StacksInTabs extends Component {
    constructor (props) {
        super(props);
        
        this.state = { softKeys: false }
    }
    
    componentDidMount () {
        if (Platform.OS === 'android') {
            DetectNavbar.hasSoftKeys().then((softKeys) => {
              this.setState({ softKeys });
            });
        }
    }
    
    render () {
        let tabBarConfig = {
          tabBarPosition: 'bottom',
          animationEnabled: false,
          swipeEnabled: false
      };
      
      if (Platform.OS === 'android') {
          tabBarConfig.tabBarComponent = NavigationComponent;
          tabBarConfig.tabBarOptions = {
              bottomNavigationOptions: {
                  style: {
                      height: this.state.softKeys ? 104 : 56
                  },
                  innerStyle: {
                      paddingBottom: this.state.softKeys ? 48 : 0
                  },
                  
              }
          }
      }
        const Tabs = TabNavigator({
          MainTab: {
            screen: MainTab,
            path: '/',
            navigationOptions: {
              tabBarLabel: 'Home',
              tabBarIcon: ({ tintColor, focused }) => (
                <Ionicons
                  name={focused ? 'ios-home' : 'ios-home-outline'}
                  size={26}
                  style={{ color: tintColor }}
                />
              ),
            },
          },
          SettingsTab: {
            screen: SettingsTab,
            path: '/settings',
            navigationOptions: {
              tabBarLabel: 'Settings',
              tabBarIcon: ({ tintColor, focused }) => (
                <Ionicons
                  name={focused ? 'ios-settings' : 'ios-settings-outline'}
                  size={26}
                  style={{ color: tintColor }}
                />
              ),
            },
          },
      }, tabBarConfig);

        return <Tabs />
    }
}

@timomeh
Copy link
Owner

timomeh commented May 26, 2017

@keeleycarrigan Thank you! I will try this out in the next days and if it works I'll update the README.

@keeleycarrigan
Copy link
Contributor Author

keeleycarrigan commented May 26, 2017

Here's the full file. It's adapted from one of Facebook's examples. Styling is good. I think it's something with React Navigation but having inner tabs doesn't work great on Android. Works great on iOS. But if you don't have inner tabs everything is probably good. Let me know if I can improve the example or anything!

Facebook's SampleText component.

import React, { Component } from 'react';
import {
  Button,
  Platform,
  ScrollView,
  StatusBar
} from 'react-native';
import {
  StackNavigator,
  TabNavigator,
} from 'react-navigation';
import { NavigationComponent } from 'react-native-material-bottom-navigation';
import { DetectNavbar } from 'react-native-detect-navbar-android';

import Ionicons from 'react-native-vector-icons/Ionicons';
import SampleText from './sample-txt';

const MyNavScreen = ({ navigation, banner }) => (
  <ScrollView>
    <SampleText>{banner}</SampleText>
    <Button
      onPress={() => navigation.navigate('Profile', { name: 'Jordan' })}
      title="Go to a profile screen"
    />
    <Button
      onPress={() => navigation.navigate('NotifSettings')}
      title="Go to notification settings"
    />
    <Button
      onPress={() => navigation.navigate('SettingsTab')}
      title="Go to settings"
    />
    <Button
      onPress={() => navigation.goBack(null)}
      title="Go back"
    />
  </ScrollView>
);

const MyHomeScreen = ({ navigation }) => (
  <MyNavScreen
    banner="Home Screen"
    navigation={navigation}
  />
);

const MyHomeScreen2 = ({ navigation }) => (
  <MyNavScreen
    banner="Home Screen"
    navigation={navigation}
  />
);

const MyProfileScreen = ({ navigation }) => (
  <MyNavScreen
    banner={`${navigation.state.params.name}s Profile`}
    navigation={navigation}
  />
);
MyProfileScreen.navigationOptions = ({ navigation }) => ({
  title: `${navigation.state.params.name}'s Profile!`,
});

const MyNotificationsSettingsScreen = ({ navigation }) => (
  <MyNavScreen
    banner="Notification Settings"
    navigation={navigation}
  />
);

const MySettingsScreen = ({ navigation }) => (
  <MyNavScreen
    banner="Settings"
    navigation={navigation}
  />
);

const stackConfig = {};

if (Platform.OS === 'android') {
    stackConfig = {
        navigationOptions: {
            headerStyle: {
              paddingTop: StatusBar.currentHeight,
              height: 56 + StatusBar.currentHeight,
              elevation: 0
            }
        }
    };
}

const HomeTabs = {
    HomeTabOne: {
        screen: MyHomeScreen,
    },
    HomeTabTwo: {
        screen: MyHomeScreen2,
    }
};

const mainTabConfig = {
    ...TabNavigator.Presets.AndroidTopTabs,
    animationEnabled: false,
    swipeEnabled: true,
}

const MainTab = StackNavigator({
  Home: {
    screen: TabNavigator(HomeTabs, mainTabConfig),
    path: '/',
    navigationOptions: {
      title: 'Welcome',
    //   headerMode: 'none'
    },
  },
  Profile: {
    screen: MyProfileScreen,
    path: '/people/:name',
    navigationOptions: ({ navigation }) => ({
      title: `${navigation.state.params.name}'s Profile!`,
    }),
  },
}, stackConfig);

const SettingsTab = StackNavigator({
  Settings: {
    screen: MySettingsScreen,
    path: '/',
    navigationOptions: () => ({
      title: 'Settings',
    }),
  },
  NotifSettings: {
    screen: MyNotificationsSettingsScreen,
    navigationOptions: {
      title: 'Notification Settings',
    },
  },
}, stackConfig);


class StacksInTabs extends Component {
    constructor (props) {
        super(props);
        
        this.state = { softKeys: false }
    }
    
    componentDidMount () {
        if (Platform.OS === 'android') {
            DetectNavbar.hasSoftKeys().then((softKeys) => {
              this.setState({ softKeys });
            });
        }
    }
    
    render () {
        let tabBarConfig = {
          tabBarPosition: 'bottom',
          animationEnabled: false,
          swipeEnabled: false
      };
      
      if (Platform.OS === 'android') {
          tabBarConfig.tabBarComponent = NavigationComponent;
          tabBarConfig.tabBarOptions = {
              bottomNavigationOptions: {
                  style: {
                      height: this.state.softKeys ? 104 : 56
                  },
                  innerStyle: {
                      paddingBottom: this.state.softKeys ? 48 : 0
                  },
                  
              }
          }
      }
        const Tabs = TabNavigator({
          MainTab: {
            screen: MainTab,
            path: '/',
            navigationOptions: {
              tabBarLabel: 'Home',
              tabBarIcon: ({ tintColor, focused }) => (
                <Ionicons
                  name={focused ? 'ios-home' : 'ios-home-outline'}
                  size={26}
                  style={{ color: tintColor }}
                />
              ),
            },
          },
          SettingsTab: {
            screen: SettingsTab,
            path: '/settings',
            navigationOptions: {
              tabBarLabel: 'Settings',
              tabBarIcon: ({ tintColor, focused }) => (
                <Ionicons
                  name={focused ? 'ios-settings' : 'ios-settings-outline'}
                  size={26}
                  style={{ color: tintColor }}
                />
              ),
            },
          },
      }, tabBarConfig);

        return <Tabs />
    }
}

export default StacksInTabs;

@ZeroCool00
Copy link

ZeroCool00 commented Apr 24, 2018

@timomeh
As you mention in documentation a step-1 and step-2 is bit incomplete,

Step-1:
this step should be added in styles.xml (v21) instead of styles.xml because material design start from api level 21. and below devices is not supported windowTranslucentNavigation

This is how you can add : in android -> app -> src -> main -> res
add new folder rename to values-v21 and add styles.xml file in it.

and there you add this styles for API level 21 and above:

<style name="AppTheme.NoActionBar">
        <item name="android:windowContentTransitions">true</item>
        <item name="android:windowAllowEnterTransitionOverlap">true</item>
        <item name="android:windowAllowReturnTransitionOverlap">true</item>
        <item name="android:windowSharedElementEnterTransition">@android:transition/move</item>
        <item name="android:windowSharedElementExitTransition">@android:transition/move</item>
        <item name="android:windowDrawsSystemBarBackgrounds">true</item>
        <item name="colorControlHighlight">@color/colorPrimary</item>
        <item name="android:navigationBarColor">@android:color/transparent</item>
        <item name="android:windowTranslucentNavigation">true</item>
        <item name="windowActionBar">false</item>
        <item name="windowNoTitle">true</item>
    </style>

and for step-2 maybe there is no need to set height or padding after apply this setting to styles.

i just check today this libarary.. i will implement soon as per my requirement.. but i found this step-1 is bit confusing bcz i m native android developer, and this is how we manage styles for different version of API level otherwise it crash for lower level devices.

@keeleycarrigan
Copy link
Contributor Author

@ZeroCool00 good to know. In React Native it's not common to have to manage styles for multiple API levels, at least I have never seen anyone talk about it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants