Tutorial: Extending Widgets with a Navigation Bar

In the Widget 1.0 library, developers could use widget.newTabBar() to create a top-level navigation bar, but only in the sense that it would draw a graphical gradient bar. It had no other features that were useful. In the Widget 2.0 library, a “no-buttons” tab bar is no longer possible, because a tab bar, by basic definition, needs some tabs to interact with.

Of course, it’s easy enough to create our own top navigation bar — just draw the background, add some title text, and place the buttons as necessary. But if we want to adhere to “DRY” programming theory (Don’t Repeat Yourself), including an entire set of navigation bar code in every scene of an app is more work than it should be.

About the Navigation Bar

In the iOS vernacular, the top navigation bar is known as the UI Navigation Bar and it has fairly consistent behavior:

a background

an optional left button

an optional right button

an optional title

With iOS6 and earlier, the nav bar for most apps was a gradient image. In iOS7, it’s either a solid color or a translucent white rectangle. This tutorial illustrates how to create a standard iOS-style “UI Navigation Bar” widget in which we provide the definitions for two buttons, the functions to handle button interaction, and some basic information to draw the bar.

When creating a top nav bar, there are a few things to consider, and we’ve done so in this code. For example, does the app have a device-specific status bar? If so, the nav bar should be positioned below it, but the area the status bar occupies is still space that we’re responsible for. With iOS6, this area is hidden, but with iOS7, we have to consider the area behind it. Because we cannot programmatically detect if the status bar is showing or not, we must pass in a flag that states if we decided to show or hide the status bar. The function will then calculate the status bar height and adjust placement of the nav bar accordingly.

Next, let’s construct the bar itself:

1

2

3

4

5

6

7

8

9

10

11

12

13

local barContainer=display.newGroup()

local background=display.newRect(barContainer,opt.x,opt.y,opt.width,opt.height+statusBarPad)

if(opt.background)then

background.fill=type="image",filename=opt.background

elseif(opt.backgroundColor)then

background.fill=opt.backgroundColor

else

if(widget.isSeven())then

background.fill=1,1,1

else

background.fill=type="gradient",color1=0.5,0.5,0.5,color2=0,0,0}

end

end

In this code block, we start by creating a container group to hold all of the visual objects. Then, a rectangle is created for the “background” and it’s added to the container group. Next, the passed-in parameters determine how to fill the rectangle — either with a specified image, a solid color, or (if nothing is provided) a solid white fill (iOS7) or a gray-to-black gradient fill (iOS6).

Now, let’s add the “title” of the page to the nav bar, if provided (note that some iOS apps don’t use titles):

1

2

3

4

5

if(opt.title)then

local title=display.newText(opt.title,background.x,background.y+statusBarPad *0.5,opt.font,opt.fontSize)

title:setFillColor(unpack(opt.titleColor))

barContainer:insert(title)

end

Now, let’s set up the buttons. There will be two buttons in this example: a “left” button and a “right” button. To keep things simple, we’ll use the existing widget.newButton() widget — essentially, we’ll pass the parameters to the button constructor:

If images are provided via the defaultFile attribute, the code looks for the parameters associated with image-based widget buttons (see the documentation). If simple text buttons are preferred, we can specify a label, font, fontSize, and labelColor array. Once both buttons are set up, we just return the container to the caller as a reference to the object.

Using the Navigation Bar Widget

To use this new widget, we simply include the above code in main.lua. It will be added to the widget library, so in other modules where you require("widget"), it will be available to you. Then, when we need to display a new navigation bar, we follow three basic steps:

1. Write the Button Listeners

The buttons on the nav bar will not be very useful unless there are callback listeners associated with tap action upon them. As such, let’s include some basic listener functions in the module where we want to use the nav bar:

1

2

3

4

5

6

7

8

9

10

11

12

13

local functionhandleLeftButton(event)

if(event.phase=="ended")then

--dostuff

end

returntrue

end

local functionhandleRightButton(event)

if(event.phase=="ended")then

--dostuff

end

returntrue

end

2. Declare the Navigation Bar Buttons

Now, let’s configure the buttons specific to this nav bar. In this example, the left button will be a two-image button and the right button will be a simple text button. Notice that we are also including a reference to the callback listeners we just wrote so that our buttons respond to touch.

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

local leftButton=

onEvent=handleLeftButton,

width=60,

height=34,

defaultFile="images/backbutton.png",

overFile="images/backbutton_over.png"

local rightButton=

onEvent=handleRightButton,

label="Add",

labelColor=default=1,1,1,over=0.5,0.5,0.5},

font="HelveticaNeue-Light",

isBackButton=false

}

3. Declare the Navigation Bar

Finally, we declare the actual navigation bar as follows:

1

2

3

4

5

6

7

8

9

10

local navBar=widget.newNavigationBar(

title="SuperDuper App",

backgroundColor=0.96,0.62,0.34,

--background="images/topBarBgTest.png",

titleColor=1,1,1,

font="HelveticaNeue",

leftButton=leftButton,

rightButton=rightButton,

includeStatusBar=true

})

Where From Here?

There’s plenty of room for you to expand on this concept. First, this is very iOS-friendly, but it doesn’t build Android-style navigation bars. The Android-style top bar is more like the iOS Toolbar, with a series of buttons on the right side and a “hamburger” icon and graphic title on the left. Secondly, this example could be expanded to support more button styles than 2-image or basic text buttons — for example, support for image sheets or 9-slice buttons (see documentation). Finally, this example doesn’t support the navigation chevrons (less-than and greater-than symbols), but it could be configured easily enough.

Disclaimer: SDKNews.com only syndicates the blog entries from various SDK blogs.
We are not the creator/author of these entries (posts). Product names, brand names
and company names mentioned on this site may be trademarks of their respective owners.