I’ve written a few blog posts in the past about NativeControls, a plugin for Cordova/PhoneGap that let’s you use the Navigation Bar (the infamous app header) and the TabBar (the infamous app footer) in your web-based Apps. PhoneGap works as a layer between the native xCode and your javascript, giving you the responsiveness of a native app in your web app. On top of that, it feels really native, because it is native. In fact, it is one of my favorite ways to implement a simple UI in an app.
I’ve finally gotten around to updating the code on GitHub. The hide/show functions aren’t 100% right, but I got both portrait and landscape working. If someone wants to fork my code and fix some of the bugs, please feel free.
Setup is pretty simple. Grab the following files and add them to the plugin section of your project:
- CDVNavigationBar.xib
- CDVNavigationBarController.h
- CDVNavigationBarController.m
- NativeControls.h
- NativeControls.m
Include the javascript files at the top of your index file. I’ve included them all to show that order matters:
1 2 3 |
<script type="text/javascript" charset="utf-8" src="js/controls.js"></script> <script type="text/javascript" charset="utf-8" src="js/cordova-1.7.0.js"></script> <script type="text/javascript" charset="utf-8" src="js/NativeControls.js"></script> |
<script type="text/javascript" charset="utf-8" src="js/controls.js"></script> <script type="text/javascript" charset="utf-8" src="js/cordova-1.7.0.js"></script> <script type="text/javascript" charset="utf-8" src="js/NativeControls.js"></script>
You will need to edit the controls.js file for your own button settings. Use my example to guide you. You need to setup a few javascript listeners in your document.ready function.
1 2 3 4 |
$(document).ready( function() { document.addEventListener("deviceready", onDeviceReady, false); window.addEventListener("resize", orientationChange, false); }); |
$(document).ready( function() { document.addEventListener("deviceready", onDeviceReady, false); window.addEventListener("resize", orientationChange, false); });
Then in your deviceready function, you need to setup your NavigationBar (header) and TabBar (footer).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 |
function onDeviceReady() { newLoc = location.href.substring(0, location.href.lastIndexOf("/")+1); // Initializating TabBar nativeControls = window.plugins.nativeControls; nativeControls.createTabBar(); // Back Button nativeControls.createTabBarItem( "page1", "Page 1", "www/images/pound.png", {"onSelect": function() { $.mobile.changePage( "#page1", { transition: 'reverse slide' } ); nativeControls.setNavBarTitle("Page 1"); nativeControls.selectTabBarItem("page1"); selectedTabBarItem = "page1"; }} ); // Home tab nativeControls.createTabBarItem( "page2", "Page 2", "www/images/pound.png", {"onSelect": function() { if ( selectedTabBarItem == "page1" ) { $.mobile.changePage( "#page2", { transition: 'slide' } ); } else { $.mobile.changePage( "#page2", { transition: 'reverse slide' } ); } nativeControls.setNavBarTitle("Page 2"); nativeControls.selectTabBarItem("page2"); selectedTabBarItem = "page2"; }} ); // About tab nativeControls.createTabBarItem( "page3", "Page 3", "www/images/question.png", {"onSelect": function() { $.mobile.changePage( "#page3", { transition: 'slide' } ); nativeControls.setNavBarTitle("Page 3"); nativeControls.selectTabBarItem("page3"); selectedTabBarItem = "page3"; }} ); // Compile the TabBar nativeControls.showTabBar(); nativeControls.showTabBarItems("page1", "page2", "page3"); selectedTabBarItem = "page1"; nativeControls.selectTabBarItem("page1"); // Setup NavBar nativeControls.createNavBar(); nativeControls.setNavBarTitle("Page 1"); nativeControls.setupLeftNavButton( "?", "", "onLeftNavButton" ); //nativeControls.hideLeftNavButton(); nativeControls.setupRightNavButton( "About", "", "onRightNavButton" ); nativeControls.showNavBar(); } |
function onDeviceReady() { newLoc = location.href.substring(0, location.href.lastIndexOf("/")+1); // Initializating TabBar nativeControls = window.plugins.nativeControls; nativeControls.createTabBar(); // Back Button nativeControls.createTabBarItem( "page1", "Page 1", "www/images/pound.png", {"onSelect": function() { $.mobile.changePage( "#page1", { transition: 'reverse slide' } ); nativeControls.setNavBarTitle("Page 1"); nativeControls.selectTabBarItem("page1"); selectedTabBarItem = "page1"; }} ); // Home tab nativeControls.createTabBarItem( "page2", "Page 2", "www/images/pound.png", {"onSelect": function() { if ( selectedTabBarItem == "page1" ) { $.mobile.changePage( "#page2", { transition: 'slide' } ); } else { $.mobile.changePage( "#page2", { transition: 'reverse slide' } ); } nativeControls.setNavBarTitle("Page 2"); nativeControls.selectTabBarItem("page2"); selectedTabBarItem = "page2"; }} ); // About tab nativeControls.createTabBarItem( "page3", "Page 3", "www/images/question.png", {"onSelect": function() { $.mobile.changePage( "#page3", { transition: 'slide' } ); nativeControls.setNavBarTitle("Page 3"); nativeControls.selectTabBarItem("page3"); selectedTabBarItem = "page3"; }} ); // Compile the TabBar nativeControls.showTabBar(); nativeControls.showTabBarItems("page1", "page2", "page3"); selectedTabBarItem = "page1"; nativeControls.selectTabBarItem("page1"); // Setup NavBar nativeControls.createNavBar(); nativeControls.setNavBarTitle("Page 1"); nativeControls.setupLeftNavButton( "?", "", "onLeftNavButton" ); //nativeControls.hideLeftNavButton(); nativeControls.setupRightNavButton( "About", "", "onRightNavButton" ); nativeControls.showNavBar(); }
Take the time to walk through the code and learn what is happening. First, we are setting up the TabBar (footer), and buttons. Then we are setting up the NavigationBar (header) and its two buttons. We will also need to create two functions for these buttons called “onLeftNavButton” and “onRightNavButton”.
1 2 3 4 5 6 7 |
function onLeftNavButton() { alert('Left Button Pressed'); } function onRightNavButton() { alert('Right Button Pressed'); } |
function onLeftNavButton() { alert('Left Button Pressed'); } function onRightNavButton() { alert('Right Button Pressed'); }
Also, don’t forget to setup the function for orientation changes:
1 2 3 4 |
function orientationChange() { nativeControls = window.plugins.nativeControls; nativeControls.resizeTabBar(); } |
function orientationChange() { nativeControls = window.plugins.nativeControls; nativeControls.resizeTabBar(); }
Last but not least, don’t forget to add “NativeControls” to your Cordova.plist file to initialize the plugin, and start up xCode. If you are lucky, you will see the top and bottom bars as shown in the screenshot. Download the demo and code over at GitHub.
Let me know how it works out for you!
I’m not sure if I’m doing something wrong here, but I have an issue since upgrading. Today I recreated my app in Xcode after installing Cordova 1.7.0 (previously running 1.5.0) and I removed the old NativeControls .h & .m files then replaced them with your latest release (plus all the other new files). I’m also referencing Cordova-1.7.0.js. When the app first launches, the bottom tab bar is in place as expected. As soon as I tap any of the tabs, it changes page but the tab bar vanishes and the whole page moves down leaving whitespace at the top of the app – the same size as the bottom tab bar was! I’m not calling a top nav bar, so do I even need this update?
I have reverted to the previous version of NativeControls (still using Cordova 1.7.0) and it’s working fine again. Am I missing something?
You do not need the update if you aren’t using the top bar. In the meantime, I need to work on the resizing functions a bit. Thanks for the feedback.
Hi, im using the native controls plugin and everything works fine, but when i rotate the app (from portrait to landscape) the bar (i use top bar) doesnt resize
if you have a fix i will appreciate your help
thanks
hi! congrats for the tutorial! i have a question for you..
I’ve downloaded your code and i’m trying to do a very easy app.. the problem is that i can’t scroll down the page.
please help;)
Thanks!
Does the page not even move? You may need to remove the function in the utility.js to preventDefault the “pagemove” event, if you included mine.
It works!! thank you so much!
Great to hear!
is there anyway of changing navbar color and add background image?
Great work btw
Sure! In xCode, edit the XIB file. Just click on the navbar, then on the right-side of the screen should be some properties that you can play with.
Awsome should have checked there first. Thanks
hi Again.I have changed the tabbar color! sweet.
i cant get get the navbar color changed there are no settings in xcode that i can see and i have tried self.navigationController.navigationBar.tintColor = [UIColor orangeColor]; and all of the variants with no luck.
any ideas please!!
You changed the footer but not the header? I think you got that backwards. The Tabbar is always black, as far as I know.
Thanks for the reply. Nope i changed the bottom tabbar color with the following:
> UIColor *myNewColor = UIColorFromRGB(0xCD2626);
> tabBar = [UITabBar new];
> [tabBar sizeToFit];
> tabBar.delegate = self;
> tabBar.multipleTouchEnabled = NO;
> tabBar.autoresizesSubviews = YES;
> tabBar.hidden = YES;
> tabBar.userInteractionEnabled = YES;
> tabBar.opaque = YES;
> tabBar.tintColor = myNewColor;
but cant seem to change the top navbar. grrrrr thanks again i have learnt heaps with your code.
Look in the XIB file, then click the actual object, then set settings on the right side panel. This screenshot best explains it.
Well dont i feel like a goose! Thanks worked a treat.
Hi, does this work on Android? Can we customize colors and background outside XCode?
Thanks!
Sorry! This is very much iOS specific.
Hello
Im beginning with dev iOS with the great Phonegap
Thanks a lot for this great tutorial ,helps a lot.
I m trying to get the label under the controls tabBar icon on two line for a specific request where 2 menus labels need to be set like this(there is 5 menus in the TabBar)
I found how to increase the the height of the tabBar in NativeControls.m
if(height == 0)
{
height = 65.0f;
atBottom = YES;
}
-How i could customize the text box label for the TabBar this way ? (need to get the words corrects)
-There is a way to set up the size of the icon box for TabBar?
Thank in advance if someone can provide me
Have you tried slipping a “\n” or < br > into the label?
Unfortunally doesn’t work
\n make some dot after the label
tag doesn’t seems work
How do you think implement this tag ?
“long label menu for native controls” ?
thanks
I wish I knew… I would try both \n and br. Let me know if you figure it out. Has me baffled!
great article.
one thing that i did in my app was to set the AutoHideSplashScreen to NO in Cordova.plist.
then in deviceready, at the end of the function, i manually hide the spashscreen, like this:
setTimeout(function() { cordova.exec(null, null, “SplashScreen”, “hide”, []); }, 0);
This has the nice effect that when the main view is shown it already has the nav- and tab-bar.
Otherwise you might see a flicker while the webview is initialized and the 2 bars are created.
Very cool tip, thank you!
There seems to be some bugs when hiding and showing the tabbar is this the case or its just me?
Yeah that part is very buggy at the moment.
Hi everyone-
I seem to be having a slight issue with the navigation bar. When a new page is loaded, the page loads from the top of the screen, so that the navbar is covering the upper portion of the page. Is there any way to resolve this?
Thanks!
Very odd… the viewport should only be the displayed window. However, my show/hide functions are very buggy right now, so perhaps that is the problem. I’m moving irl right now, but hope to jump back on this project soon.
Hi Pat, I am having your same problem, did you manage to fix that ?
If I dont want title for my item,
i put “null” and it is not working
 nativeControls.createTabBarItem (
                                                    “back”,
                                                    “Back”,
                                                    “www / images / Back_tablet.png”,
                                                    {“onSelect”: function () {
                                                    $. mobile.changePage (“# page1”, {transition: ‘reverse slide’});
                                                    nativeControls.setNavBarTitle (“Page 1”);
                                                    nativeControls.selectTabBarItem (“page1”);
                                                    selectedTabBarItem = “page1”;
                                                    }}
                                                    );
Try an empty string with two double quotes.
This work with the latest Cordova. I’ve tried every tutorial on native controls with not luck. New to Cordova and can’t get any plugin to work.. Did something break in 1.8+ with plugins?
thanks, I’m new to cordova.
Scott
Hey great plugin! got it to work. I guess the files in the plugin dir weren’t assoc. right. Anyway. Is there anyway to show a back button on the top bar?
Thanks,
Scott
Or even hide the topbar?
Seems if you comment out the navbar it’s fine on the first page, but shows an empty spot for it when sliding to another page. Any ideas?
thanks!!
Yeah sadly my show/hide functions suck. I need to spend some time on them.
Is possible to add a badge on tab button?
I was trying to use the plugin. I downloaded the demo project and tried to run it. Its giving me compile error of “property ‘invokeString’ not found on object of type ‘MainViewcontroller'”
I am using cordova 1.5.0 and jQuery 1.1.0
Update Cordova and try.
is there anyway to put a searchbox in the navbar ?
Thanks.
While anything is possible, I did not code any way to do this.
Thanks for your answer. I’m new to IOS so I do not have much experience. Just one more question: I try to add image to navbar button but it didn’t show up. This is my code:
…
nativeControls.setupLeftNavButton(‘Back’, ‘www/images/back.png’, ‘onBack’)
…
Button’s event works but the image didn’t show. Did I do something wrong ? Thanks.
I have this question too, how to put images to Navbar buttons?
Just link them as shown above. It should be pretty straight forward, honestly. My example does this exactly.
Perhaps you need the lead slash? “/www/images/back.png”?
If that doesn’t work, compile it in xCode, then open up the file and get the exact path to the image. It should work. Your path must be wrong.
I did try “/www/images/back.png” and it didn’t work too. In your example, you only change image for tabbar item, with navbar, you leave the field image blank. I try to change the tabbar image with the path ‘www/images/imagename.png’ and it works well, but it does not work for navbar. Can you pls try your code with custom image for navbar to check again. Thanks alot.
Is there any option to customize the left button to be a back button in xcode? I tried many ways available in various forums, but still cant able to find a solution.
if I want to change the color of the nav bar ??
tint and style .
tnx.
You do this in xCode on the right side. It is simple point/click using drop downs. No extra code required!
This is all done in xCode, no actual code needed. Just change the color on the right side panel in xCode. It’s a drop down list.
Hi Sprawl
I use the original plugin nativecontrols perfectly working with Jquery and a multipage.
Hide and show tabbar works great.
On my application at the index the navigation tabbar is hide and after clicking on a Jquery list menu item, the tabbar is show and the correct tabbar menu item is select.
When i return to the home page the native controls bars is hide again.
I m happy of that except its only working inside a multiple page with jquery.
But when try using it with some single page links , the navigation of the native doesnt work anymore.
It just appear one but navigation of the tabbar doesnt work anymore and when return home page doesnt hide.
Its something with Dom i imagine.But i m lost how use this
(i use the function init to load the nativecontrols at the home page)
Could help me a bit how use nativecontrols with single pages and jquery
many thanks
Do you have the code uploaded somewhere that I can look at? Hard to understand what you are asking.
Report problem: when I call function nativeControls.hideTabBar(), my page is slided up a little bit and being covered by the navbar and the page can not be scrolled anymore. Is this a bug or because of my bad code ?
Do you have a copy that will work pre-cordova ?
I’m using 1.4.1 phonegap atm..
Sorry, I do not.
Realy nice tutorial and well explained but i simply cant get it work.
I’m using Cordova 1.9 and the last git:.. ios/nativecontrols plugin.
I mean ChildBrowser works perfectly but native controls nothing. I cant fint anything on the web, do you know if they’ve changed anything in the last version of cordova/phonegap?
Thanks man!
I haven’t loaded 1.9 yet, so I don’t know. Please keep us updated!
We are running NativeControls in Cordova 1.9. It works perfectly
Do you have any app examples?
You should be able to download the code above and run it with filler text. The px2em app that I have on the App Store uses this layout as well.
I tested your code and it works just fine, nice layout!
But there is a problem with a scrolling in this app.
When you put something in CONTENT div like listview, there is no scroll function at least not in simulator.
Did you think about this?
Hmm mine scrolls…
By default or?
In simulator wont work at all
Hi Sprawl,
thanks a lot for the plugin. NativeControls is really valuable to us and saved us a lot of time.
We found one issue: Hiding the NavBar does work on the first screen but after resizing the first time, a blank rectangle apears at the top of the app and pushes the webview towards the end. The Tabbar slides out of sight, only the top 5 Pixel are still visible.
The cause is variable topBar in NativeControls.m:resizeTabBar which is statically set to “44.0” but should have a value of 0 when NavBar is hidden. We were fixing topBar to “0.0” in our app and everything is working as expected from then on. Maybe you can add a switch in the next release that checks whether NavBar is hidden and set the value of topBar accordingly.
How to add ” Back ” button to topbar?
I open .xib file and try to remove ” ? ” button and add Back button but i cant …
Can u help with this?
Thanks
I have got this all working – I have also allowed scrolling (up and down) for longer content pages – the only problem is that when you scroll to the end of the page you can then go further which leaves a white space the same height as the bottom tab bar. Is there a reason for this?
is there a minimum height for the content to be to stop this?
See pic here:
Hi Sprawl,
Thanks for the example. I am starting with Cordova.
When i upload your www folder to phonegab it doesn’t show any toolbar.
Do I need to upload a congif file for phonegab version or something?
Thanks for your help!
If I don’t use an image icon on the footer navbar, it still has an empty space for that icon. How can I make it so it is just the text in the vertical middle of the tabbar without an icon?
Love this article, but I can’t get it working with the latest 2.1 release of Cordova. Any plans on updating your code – thx for the writeup.
It works for me after the normal header update mentioned in the Cordova plugin update guide.
https://github.com/apache/incubator-cordova-ios/blob/master/guides/Cordova%20Plugin%20Upgrade%20Guide.md
Could you please elaborate on what you did to get it working properly with 2.1?
Thanks
Thanks for the plugin and coding.
One question:
How can I do a link index.html? E.g. I found the function onLeftButton():
function onLeftNavButton() {
window.location(“./index.html”);
}
window.location(“index.html”);, window.location(“(/)www/index.html”); window.location(“file://www/index.html”); and all window.location.href(…) don’t work either? Is there a trick?
Thanks!
PS: It is the first NavBar-Plugin that is working! Very cool!
Oh, this was pretty easy!
window.location.href = “index.html” is the solution.
Sorry!
Hey Sprawl, nice plugin!
Is it possible to change the navbar for each side?
E.g. the navbar looks like:
index.html:
title of navbar //nothinig else just title
subpage.html:
leftButton & title of navbar & rightButton
Greetings,
Ben
This works if I import it into xCode and with the updating of the build architecture and builds to the iPhone device. However, no orientation change. Is there supposed to be?
Also, could not get it to work with Phonegap 2.1, don’t know why. I tried creating a new project in Phonegap and then just importing your www folder, updating script tags and installing your plugins. I’m not getting errors, but nothing is happening i.e. the controls don’t show up.
Any tips how to upgrade? If not, I’ll just build with 1.8.1. Personally, I think the new updates are such a mess!
Thanks for this plugin BTW!
I am also having issues getting NativeControls working with Phonegap 2.1 Has anyone had any luck getting the plugin working?
I have tried this code but running through issues, tab items are not getting called and display appropriate content. I am using Cordova 2.2.0 on OS x . I added alert to onSelect function for each tab this function is not getting called
nativeControls.createTabBarItem(
“page3”,
“Page 3”,
“www/images/question.png”,
{“onSelect”: function() {
alert(“page 3”);
https://docs.google.com/open?id=0B-dtT5RyOEjcTXJtTFZ5bTRlZXM
Hello Sprawl,the navbar not show with Cordova 2.3 but the footer tabbar,could you mind to help me for this?
I downloaded your demo, took the WWW folder and renamed it and tried it with a browser in my localhost. As expected, it only showed the screen, but nothing else (I’m using WAMP).
Then I zipped the whole folder (and sub-folders) and uploaded it to PhoneGap build and let it build and then downloaded it to both an iPad and an iPod Touch. Both showed exactly what the localhost did: the striped background and the “Thank You” note, but no controls of any kind. Is this what it’s supposed to show? Am I missing some action I am supposed to be doing (been years since I was an Apple guy).
Thanks in advance for the reply.
Again, I took your exact folder with no changes.