Corona Reference: Widgets

The Widgets Library can save you a considerable amount of time when you need to include common objects like buttons, switches, and sliders. Many of these widgets are fully customizable, so they'll match the style of your app. For an even easier widget, you can use one of the default themes.

Widget Library Setup

To use any of the widgets, you first need to include the widget library with the line
local widget = require( "widget" )
This line can be included at the top of the main.lua file, or anywhere before using a widget object.

We'll see how to customize widgets by creating your own images and themes later. For now, you can use the default style, or one of the themes created to blend into the operating system you're building for:
widget.setTheme( "widget_theme_ios" )
for iOS, or
widget.setTheme( "widget_theme_android" )
for Android. These lines can be included after you've included the widget library.

Switches

The “switch” widget comes in three varieties, each of which is used to change a boolean value: the radio button, the checkbox, and the on/off switch. For any of these, we'll use the basic format:
local mySwitch = widget.newSwitch 	-- choose a unique name for the switch
	{		
	x = x_value,			-- x coordinate for switch center
	y = y_value,			-- y coordinate for switch center
	style = "radio",		-- switch type, use either "radio", "checkbox", or "onOff"
	id = "switch1",			-- optional, used to refer to switch later
	initialSwitchState = true,	-- set to true if switch should be on to start, false for off
	onPress = function_name, 	-- optional, function to fire when touch on switch begins
	onRelease = function_name, 	-- optional, function to fire when touch on switch ends
	onEvent = function_name		-- optional, function to fire when touch begins or ends (replaces onPress and onRelease)
	}
Most of the time, we'll just be using the "onEvent" function option.

Checkboxes

A checkbox has two states: on or off. The default on/off appearance of the checkbox using the default, iOS, and Android themes are shown below:
As an example, the following creates a survey and reports the user's selections:
local luaSwitch, luatext, rubySwitch, rubytext, pythonSwitch, pythontext, response, question, showChoices

local bg = display.newRect(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight)

local widget = require( "widget" )			-- include widget library

function showChoices( event )
    local preferencestring = ""				-- create blank string
    
    if luaSwitch.isOn == true then
        preferencestring = preferencestring.."Lua, "	-- add Lua to list of languages
    end
    if rubySwitch.isOn == true then
        preferencestring = preferencestring.."Ruby, "	-- add Ruby to list of languages
    end
    if pythonSwitch.isOn == true then
        preferencestring = preferencestring.."Python, "	-- add Python to list of languages
    end
    
    l = string.len( preferencestring )
    if l > 0 then
        preferencestring = string.sub(preferencestring, -l, -3)	-- remove extra comma from end of string, assuming string is nonempty
    end
    
    response.text = preferencestring			-- change response text to show preferences
    
    return true
end

question = display.newText( "What scripting languages do you enjoy?", display.contentWidth/2, 200, Arial, 30 )
    question:setFillColor( 0, 0, 0.6 )
    
-- create three checkboxes and labels

luaSwitch = widget.newSwitch
	{		
	x = 100,
	y = 300,	
	style = "checkbox",	
	initialSwitchState = false,
	onEvent = showChoices
	}
	
luatext = display.newText( "Lua", 0, 0, Arial, 30 )
    luatext.anchorX, luatext.anchorY = 0, 0.5
    luatext.x, luatext.y = 130, 300
    luatext:setFillColor( 0, 0, 0.6 )
    	
rubySwitch = widget.newSwitch 
	{		
	x = 100,	
	y = 350,			
	style = "checkbox",		
	initialSwitchState = false,	
	onEvent = showChoices
	}

rubytext = display.newText( "Ruby", 0, 0, Arial, 30 )
    rubytext.anchorX, rubytext.anchorY = 0, 0.5
    rubytext.x, rubytext.y = 130, 350
    rubytext:setFillColor( 0, 0, 0.6 )

pythonSwitch = widget.newSwitch 	
	{		
	x = 100,		
	y = 400,			
	style = "checkbox",		
	initialSwitchState = false,
	onEvent = showChoices
	}

pythontext = display.newText( "Python", 170, 400, Arial, 30 )
    pythontext.anchorX, pythontext.anchorY = 0, 0.5
	pythontext.x, pythontext.y = 130, 400
    pythontext:setFillColor( 0, 0, 0.6 )
    
-- empty text object; will display selections:
    
response = display.newText("", display.contentWidth/2, 500, Arial, 30 )
    response:setFillColor( 0, 0.6, 0 )    
The resulting scene:

On/Off Switches

An on-off switch also has two states: on or off. The default on/off appearance of the on-off switch using the default, iOS, and Android themes are shown below:
As an example, the following switch on screen that changes the background color when flipped on and off:
local bg = display.newRect(display.contentWidth/2, display.contentHeight/2, 4000, 4000)
local mySwitch, changeColor

local widget = require( "widget" )

function changeColor( event )
    if event.target.isOn == true then
        bg:setFillColor( 1, 1, 1 )
    else
        bg:setFillColor( 0, 0, 0 )
    end
end

local mySwitch = widget.newSwitch
{
    x = 250,
    y = 200,
    style = "onOff",
    initialSwitchState = true,
    onPress = changeColor
}

Radio Switches

Radio switches also have two states: on or off. The default on/off appearance of the radio button using the default, iOS, and Android themes are shown below:
Unlike checkboxes and on-off switches, though, radio switches are used in sets, where only one switch in the set can be on. To associate radio buttons, add them to the same display group.

In the following example, two survey questions are asked along with a series of options for each answer. Only one choice can be made per question.
local bg = display.newRect(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight)

local widget = require( "widget" )			

-- First Question:

question1choices = display.newGroup()

question1 = display.newText( "Question 1: ... ", display.contentWidth/2, 200, Arial, 30 )
    question1:setFillColor( 0, 0, 0.6 )
    
quest1_ans1 = widget.newSwitch
	{		
	x = 100,
	y = 250,	
	style = "radio",
	initialSwitchState = true,
	}
question1choices:insert(quest1_ans1)
	
quest1_ans1_text = display.newText( "Question 1, Answer 1", 0, 0, Arial, 30 )
    quest1_ans1_text.anchorX, quest1_ans1_text.anchorY = 0, 0.5
    quest1_ans1_text.x, quest1_ans1_text.y = 130, 250
    quest1_ans1_text:setFillColor( 0, 0, 0.6 )
    	
quest1_ans2 = widget.newSwitch 
	{		
	x = 100,	
	y = 300,			
	style = "radio",		
	initialSwitchState = false,	
	}
question1choices:insert(quest1_ans2)

quest1_ans2_text = display.newText( "Question 1, Answer 2", 0, 0, Arial, 30 )
    quest1_ans2_text.anchorX, quest1_ans2_text.anchorY = 0, 0.5
    quest1_ans2_text.x, quest1_ans2_text.y = 130, 300
    quest1_ans2_text:setFillColor( 0, 0, 0.6 )
    
-- Second Questions
    
question2choices = display.newGroup()

question2 = display.newText( "Question 2: ... ", display.contentWidth/2, 400, Arial, 30 )
    question2:setFillColor( 0, 0, 0.6 )
    
quest2_ans1 = widget.newSwitch
	{		
	x = 100,
	y = 450,	
	style = "radio",	
	initialSwitchState = false,
	}
question2choices:insert(quest2_ans1)
	
quest2_ans1_text = display.newText( "Question 2, Answer 1", 0, 0, Arial, 30 )
    quest2_ans1_text.anchorX, quest2_ans1_text.anchorY = 0, 0.5
    quest2_ans1_text.x, quest2_ans1_text.y = 130, 450
    quest2_ans1_text:setFillColor( 0, 0, 0.6 )
    	
quest2_ans2 = widget.newSwitch 
	{		
	x = 100,	
	y = 500,			
	style = "radio",	
	isOn = true,	
	initialSwitchState = true,	
	}
question2choices:insert(quest2_ans2)

quest2_ans2_text = display.newText( "Question 2, Answer 2", 0, 0, Arial, 30 )
    quest2_ans2_text.anchorX, quest2_ans2_text.anchorY = 0, 0.5
    quest2_ans2_text.x, quest2_ans2_text.y = 130, 500
    quest2_ans2_text:setFillColor( 0, 0, 0.6 )

Changing States

We can use the setState method to specify properties of a switch:
mySwitch:setState( { isOn = false, isAnimated = true })
The isOn property can be set to true or false, causing the switch to appear on or off. The isAnimated property can also be either true or false. When set to true, the switch's state will change smoothly. When set to false (the default) the switch's state will simply flip back and forth from on to off.

To retrieve the current state of a switch, use
mySwitch.isOn
which returns true if the switch is on, and false if the switch is off.

Sliders

Sliders can be a convenient method for a user to choose from a range of values. Regardless of how wide the slider is, the position of the slider represents a value between 0 and 100. The default appearance of a slider using the default, iOS, and Android themes are shown below:
The format for creating a slider is a table with several options:
local mySlider = widget.newSlider 	-- choose a unique name for the slider
	{		
	x = x_value,			-- x coordinate for switch center
	y = y_value,			-- y coordinate for switch center
	orientation = "horizontal",	-- either "horizontal" or "vertical"
	width = width_value,		-- width of slider in horizontal orientation
	height = height_value,		-- height of slider in vertical orientation
	value = num_value,		-- number between 0 and 100 indicating position of slider
	id = "slider1",			-- optional, used to refer to switch later
	listener = function_name	-- function to fire when user interacts with slider
	}
The following code creates a horizontal slider, which triggers an event called SliderCall when the user interacts with it. It also sets the initial value of the slider to 40.
local MySlider = widget.newSlider
{
   orientation = "horizontal",
   width = 200,
   x = 250,
   y = 300,
   value = 40
   listener = SliderCall
}
We can use the setValue method to specify the current value of a slider:
mySlider:setValue( 60 )
will position the slider handle at 60% of its width, from the left. To retrieve the value of a slider after a user changes it, use
mySlider.value
which returns a number between 0 and 100.

Buttons

Buttons are a very familiar input device, and are still widely used in mobile apps. Creating a labelled button with Corona widgets is easy. The format for creating a button depends on the level of customization you prefer.

Basic Buttons

The default appearance of a basic button using the default, iOS, and Android themes are shown below:
Creating a basic button requires a table, where you can specify a variety of options:
local myButton = widget.newButton 	-- choose a unique name for the slider
	{		
	x = x_value,			-- x coordinate for button center
	y = y_value,			-- y coordinate for button center
	isEnabled = true,		-- if set to false, button will not respond to touch
	onPress = function_name, 	-- optional, function to fire when touch on button begins
	onRelease = function_name, 	-- optional, function to fire when touch on button ends
	onEvent = function_name,	-- optional, function to fire when touch begins or ends (replaces onPress and onRelease)
	label = "button label",		-- label to appear on button
	labelAlign = "center", 		-- label alignment; use "left", "center", or "right"
	labelColor = 
		{
		default = { r, g, b },	-- color of button label at rest
		over = { r, g, b }	-- color of button label when pressed
		},
	labelXOffset = num_value,	-- optional, shifts label horizontally
	labelYOffset = num_value,	-- optional, shifts label vertically
	font = font_style,		-- font to use for button label
	fontSize = font_size, 		-- size of button label text
	emboss = false,			-- set to true to create embossed label
	textOnly = false		-- set to true to eliminate button background
	}
The following code creates a standard button, that triggers a function called "ButtonPush" when tapped.
local myButton = widget.newButton
	{
	x = 150,
	y = 100,
	width = 200,
	label = "Here’s a button!",
	labelAlign = "center",
	font = native.systemFont,
	fontSize = 20,
	labelColor = { default = { 0, 0, 0 }, over = { 200, 0, 0 } },
	id = button1,
	onEvent = ButtonPush
	}
Of course, we do not need to specify all of these options when creating a button - only the ones we'd like to change from the default. Most of the attributes are optional, used only for placement and sizing. These can easily be changed later in the same way display objects can be manipulated. The label string is the text that appears on the button, and can also be changed using setLabel, as in
myButton:setLabel( "A New Label" )
Notice that we also defined the font, font size, position, and color of the label, and even specified that we would like the label to appear red when pressed (releasing the button changes the label back to black).

Two Image Custom Buttons

The default button image created by Corona will very likely not fit the theme of your app. Fortunately, you can create your own button images to use. The first method of doing so involves creating two separate images. One will be used for the button in its normal state, and another will be used when the button is being pressed. Use the defaultFile and overFile attributes in the button options table to use your images:
local myButton = widget.newButton
	{
	x = 150,
	y = 100,
	defaultFile = "defaultbutton.png",
	overFile = "pressedbutton.png",
	label = "Here’s a button!",
	id = button1,
	onEvent = ButtonPush
	}

Nine Image Flexible Buttons

The two image method is the simplest way to create your own button, though is the least flexible when it comes to resizing. You might not want to use the same button images for buttons with labels of various lengths, but customizing each one means creating separate files for every button width required. To avoid this problem, we can use a more flexible option, involving creating an image sheet. This is the most work in setting up, but pays off when you need to create various buttons with the same appearance.

To start, create a single .png file with two versions of your button: one in its normal state, and one in its pressed state. When saving the image file, you might want to trim any extra space around it. You can place the button images however you like. In the sample below, the normal button is on the left, and the pressed button is on the right:
You can save this image with its current file name if you'd like to try duplicating this example.

We'll now set up an image sheet specifying the "frames" of our buttons. Each frame will represent a section of the button; we'll create nine frames for each version. As a reference for the idea of how these frames will be arranged, the diagram below shows how we'll "split" the normal button into nine frames:
There's a frame for each corner, the top center, bottom center, sides, and center. The idea is that we can use these pieces to make a button as large or small as we need. To make a longer button, we'll just insert more of the center pieces, for instance. Fortunately, once we set up the frame table, Corona will take care of this for us. The table for this example would like like
local buttonSheetOptions = {	-- refers to ButtonImage.png
	frames = 
		{
		-- default button frames:
		{ x = 0, y = 0, width = 20, height = 20 }, 	-- top left
		{ x = 20, y = 0, width = 60, height = 20 }, 	-- top center
		{ x = 80, y = 0, width = 20, height = 20 }, 	-- top right
		{ x = 0, y = 20, width = 20, height = 20 }, 	-- left edge
		{ x = 20, y = 20, width = 60, height = 20 }, 	-- center
		{ x = 80, y = 20, width = 20, height = 20 }, 	-- right edge
		{ x = 0, y = 40, width = 20, height = 20 }, 	-- bottom left
		{ x = 20, y = 40, width = 60, height = 20 }, 	-- bottom center
		{ x = 80, y = 40, width = 20, height = 20 }, 	-- bottom right
		-- pressed button frames:
		{ x = 100, y = 0, width = 20, height = 20 }, 	-- top left
		{ x = 120, y = 0, width = 60, height = 20 }, 	-- top center
		{ x = 180, y = 0, width = 20, height = 20 }, 	-- top right
		{ x = 100, y = 20, width = 20, height = 20 }, 	-- left edge
		{ x = 120, y = 20, width = 60, height = 20 }, 	-- center
		{ x = 180, y = 20, width = 20, height = 20 }, 	-- right edge
		{ x = 100, y = 40, width = 20, height = 20 }, 	-- bottom left
		{ x = 120, y = 40, width = 60, height = 20 }, 	-- bottom center
		{ x = 180, y = 40, width = 20, height = 20 } 	-- bottom right
		},
	sheetContentWidth = 200,
	sheetContentHeight = 60
	}
	
local buttonSheet = graphics.newImageSheet( "ButtonImage.png", buttonSheetOptions )
Now we create our button, instructing Corona where to find each piece. We can now set the height and width to be anything, instead of being limited by our original file size. The original button is only 100 pixels wide; here, we instruct Corona to create a button with twice that width.
local myButton = widget.newButton
	{
	sheet = buttonSheet,
	x = 250, 
	y = 300, 
	width = 200, 
	height = 60,
	topLeftFrame = 1,
	topMiddleFrame = 2,
	topRightFrame = 3,
	middleLeftFrame = 4,
	middleFrame = 5,
	middleRightFrame = 6,
	bottomLeftFrame = 7,
	bottomMiddleFrame = 8,
	bottomRightFrame = 9,
	topLeftOverFrame = 10,
	topMiddleOverFrame = 11,
	topRightOverFrame = 12,
	middleLeftOverFrame = 13,
	middleOverFrame = 14,
	middleRightOverFrame = 15,
	bottomLeftOverFrame = 16,
	bottomMiddleOverFrame = 17,
	bottomRightOverFrame = 18,
	label = "button label"
	}
The buttons below were created using this sheet, with only the width and height options changed:

Steppers

A stepper is a two button widget used to increase and decrease (by integers) until a maximum or minimum value has been reached. The default appearance of a stepper using the default, iOS, and Android themes are shown below:
The format for creating a slider is a table with several options:
local myStepper = widget.newStepper 	-- choose a unique name for the stepper
	{		
	x = x_value,				-- x coordinate for switch center
	y = y_value,				-- y coordinate for switch center
	initialValue = num_value,		-- beginning value of stepper; default is 0
	minimumValue = num_value, 		-- minimum value stepper may reach; default is 0
	maximumValue = num_value,		-- maximum value stepper may reach; unlimited by default
	timerIncrementSpeed = num_value,	-- initial speed at which each increment occurs in milliseconds; default is 1000 (one second)
	changeSpeedAtIncrement = num_value,	-- number of increments before stepper speed changes; default is 5
	id = "stepper1",			-- optional, used to refer to switch later
	onPress = function_name			-- function to fire when stepper value is changed by user
	}
The code to set up a stepper with minimum value 0, maximum value 20, and initial value 5 that triggers a function called StepperPress would be
local myStepper = widget.newStepper
	{
	x = 150,
	y = 300,
	initialValue = 5,
	minimumValue = 0,
	maximumValue = 20,
	changeSpeedAtIncrement = 5,
	timerIncrementSpeed = 500,
	onPress = StepperPress
	}
To retrieve the value of a stepper at any time, use
myStepper.value

Custom Steppers

To create a custom stepper, create an image sheet with 5 frames: one of the stepper in its normal state, one with the "step up" button disabled, one with the "step down" button disabled, one with the "step up" button being pressed, and one with the "step down" button pressed. For an example, save the "StepperImage.png" file below:
Next, we'll define an image sheet. The stepper images should all be the same size, so a rectangular image sheet is an obvious choice, and makes it easy to import into Corona:
local stepperSheetOptions = 	-- refers to StepperImage.png
	{	
	width = 254,
	height = 104,
	numFrames = 5,
	sheetContentWidth = 254,
	sheetContentHeight = 520
	}
	
local stepperSheet = graphics.newImageSheet( "StepperImage.png", stepperSheetOptions )
Finally, we'll create the stepper using this sheet:
local myStepper = widget.newStepper
    {
    x = 300,
    y = 200,
    sheet = stepperSheet,
    defaultFrame = 1,
    noPlusFrame = 2,
    noMinusFrame = 3,
    minusActiveFrame = 4,
    plusActiveFrame = 5,
    minimumValue = 0,
    maximumValue = 100,
    initialValue = 5,
    onPress = changeStepperValue
    }
To demonstrate our stepper, we'll create a function that changes a text object to reflect the current stepper value. The entire scene would be
local widget = require( "widget" )

local stepperValueText, myStepper, stepperSheet, options, changeStepperValue

stepperSheetOptions = 	-- refers to StepperImage.png
	{	
	width = 254,
	height = 104,
	numFrames = 5,
	sheetContentWidth = 254,
	sheetContentHeight = 520
	}
	
stepperSheet = graphics.newImageSheet( "StepperImage.png", stepperSheetOptions )

function changeStepperValue( event )
	stepperValueText.text = "Stepper: "..event.value
end	

myStepper = widget.newStepper{
	x = 300,
	y = 200,
	sheet = stepperSheet,
	defaultFrame = 1,
	noPlusFrame = 2,
	noMinusFrame = 3,
	minusActiveFrame = 4,
	plusActiveFrame = 5,
	minimumValue = 0,
	maximumValue = 100,
	initialValue = 5,
	onPress = changeStepperValue
}

stepperValueText = display.newText( "Stepper: 5", 100, 100, Arial, 30 )

Picker Wheel

A picker wheel allows the user to make a selection from various lists of data arranged in columns. The default appearance of a picker wheel using the default, iOS, and Android themes are shown below, displaying an example where the user can enter a date by choosing a month, date, and year:
To create a picker wheel, we first need to define the tables that will contain the choices for each column. For the date example, we could have
local months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }
local dates = { 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 }
local years = { 1975, 1976, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1965, 1987, 1988, 1989, 1990 }
Next, we configure the columns. The settings for each column (up to three) will go into a table with the following options:
{
align = "left",			-- can be "left", "right", or "center"
width = num_value,		-- width of the column
startIndex = num_value,		-- initial row of column; default is 1
labels = table_name,		-- data table defined earlier
font = font_style,		-- font for column entries; default is native.systemFontBold
fontSize = font_size,		-- font size for column entries; default is 22
fontColor = { r, g, b, a },	-- color of column text
columnColor = { r, g, b, a }	-- background color of column
}
Now create a larger table containing the column tables. We'll use this table to define the picker wheel:
local pickerColumns = 		-- choose a unique name for this table
	{
		{
		align = "left",		--  defining the left column
		width = 200,		-- width of left column
		startIndex = 5,		-- initial row of left column
		labels = months		-- data table defined earlier
		},
		{
		align = "center",	--  defining the center column
		width = 80,		-- width of center column
		startIndex = 18,	-- initial row of center column
		labels = dates		-- data table defined earlier
		},
		{
		align = "right",	--  defining the right column
		width = 140,		-- width of right column
		startIndex = 5,		-- initial row of right column
		labels = years		-- data table defined earlier
		}
	}
Finally, we define the actual picker, using the table defined above:
local pickerWheel = widget.newPickerWheel
	{
	x = 200,			-- x coordinate of center
	y = 500, 			-- y coordinate of center
	columns = pickerColumns		-- column table defined earlier
	}
Note that there is no option to fire a function upon changing the picker wheel. To use a picker wheel, you'll need a secondary button that the user can touch after making their selection in the wheel. This button can then have a listener that will obtain the values in the wheel and respond accordingly.

To get the value of a particular column in the wheel at any time, use
pickerWheel:getValues()
This will return a table whose length is equal to the number of columns. The first entry in the table is the current choice for the first column, and so on.

Progress Bars

Progress bars are typically used to show that a process is currently running, such as a scene loading. The default appearance of a progress bar using the default, iOS, and Android themes are shown below:
The format for creating a slider is a table with several options:
local myProgressBar = widget.newProgressView 	-- choose a unique name for the progress bar
	{		
	x = x_value,			-- x coordinate for progress bar center
	y = y_value,			-- y coordinate for progress bar center
	width = width_value,		-- width of progress bar 
	isAnimated = false		-- set to true to show progress bar animation; default is false
	}
We can then use the setProgress method to change the current view of the progress bar by passing a value between 0 and 1, representing a percentage:
myProgressBar:setProgress( 0.6 )
Note that the progress bar is not interactive; the user cannot change the value. Typically, you would use a timer function to change the progress as required.

Spinner Wheels

Spinners have a similar usage to progress bars, in that they are typically used to indicate a process is currently taking place. The default appearance of a progress bar using the default, iOS, and Android themes are shown below (these are animated in actual use):
The format for creating a slider is a table with several options:
local mySpinner = widget.newProgressView 	-- choose a unique name for the progress bar
			{		
			x = x_value,			-- x coordinate for spinner center
			y = y_value,			-- y coordinate for spinner center
			width = width_value,		-- width of spinner
			height = height_value,		-- height of spinner
			isAnimated = false		-- set to true to show progress bar animation; default is false
			}
We can then use the start and stop methods to animate the spinner or stop animation:
				
mySpinner:start()
mySpinner:stop()
Note that the spinner is not interactive.

Tab Bars

Tab bars are menu options, arranged in a row, that are typically positioned at the top or bottom of the screen. The default appearance of a tab bar using the default, iOS, and Android themes are shown below:
To create a tab bar, first create a table containing the attributes for your tab buttons. Each of the button should have a separate table, which will be put into a larger table when defining the tab bar. The following is an outline of what each tab button table could include:
{
id = "buttonid",		-- optional string used to refer to button later
label = "Tab Label",		-- label to appear on button
labelColor = 
	{
	default = { r, g, b },	-- color of tab label at rest
	over = { r, g, b }	-- color of tab label when selected
	},
labelXOffset = num_value,	-- optional, shifts label by specified number of pixels left (negative value) or right (positive value)
labelYOffset = num_value,	-- optional, shifts label by specified number of pixels up (negative value) or down (positive value)
font = font_style,		-- font to use for button label; default is native.systemFont
size = num_value, 		-- font size for tab label; default is 8
selected = false,		-- set to true to have this tab appear in its selected state
onPress = function_name, 	-- function to call when tab is pressed
}
Next, we put these tab button tables into another table:
local tabButtons = 		-- choose a unique name for this table
	{
		{
		label = "Red Tab",		
		selected = true,
		size = 20,		
		onPress = makeRed		
		},
		{
		label = "Green Tab",	
		size = 20,	
		onPress = makeGreen		
		},
		{
		label = "Blue Tab",	
		size = 20,		
		onPress = makeBlue		
		}
	}
and finally we create the widget.
			
local myTabBar = widget.newTabBar
	{
	x = display.contentWidth/2,			-- position the tab bar at bottom of screen
	y = display.contentHeight - 50,
	width = display.contentWidth,		
	height = 100,
	buttons = tabButtons
	}
Note that each button defined above has a different listener on it. We'll now use the tab bar to change the color of the screen background:
local widget = require( "widget" )
widget.setTheme( "widget_theme_ios" )

local bg = display.newRect(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight)
    bg:setFillColor( 1, 0, 0 )

local tabButtons, myTabBar, makeRed, makeGreen, makeBlue

function makeRed( event )
    bg:setFillColor( 1, 0, 0 )
end

function makeGreen( event )
    bg:setFillColor( 0, 1, 0 )
end

function makeBlue( event )
    bg:setFillColor( 0, 0, 1 )
end

tabButtons = 		
	{
		{
		label = "Red Tab",		
		selected = true,
		size = 20,		
		onPress = makeRed		
		},
		{
		label = "Green Tab",	
		size = 20,	
		onPress = makeGreen		
		},
		{
		label = "Blue Tab",	
		size = 20,		
		onPress = makeBlue		
		}
	}

myTabBar = widget.newTabBar
	{
	x = display.contentWidth/2,			
	width = display.contentWidth,		
	height = 100,
	buttons = tabButtons
	}

Segmented Controls

Similar to tab bars, segmented controls provide an array of options arranged in a row. The default appearance of a segmented control using the default, iOS, and Android themes are shown below:
To create a segmented control, we only need one table:
local myControl = widget.newSegmentedControl 	-- choose a unique name for the stepper
	{		
	id = "controllerid",			-- optional, sting to identify controller
	x = x_value,				-- x coordinate for controller center
	y = y_value,				-- y coordinate for controller center
	segmentWidth = width_value,		-- width of each segment
	segments = { "label 1", "label 2" },	-- table of segment labels, in order
	defaultSegment = 1,			-- segment selected at start; default is 1
	labelSize = num_value,			-- font size for labels
	labelFont = font_style, 		-- font for label
	onPress = function_name			-- function to fire when user interacts with controller
	}
Note the key differences between segmented controls and the tab bar. With a tab bar, we were able to assign unique functions to each button, as well as customize the buttons individually. With a segmented control, there is only one function associated with the controller, and the buttons are uniform in appearance.

As there is only one function involved, we need to be able to differentiate between the segments. We can use the segmentNumber property to determine which segment was touched in the handler:
local widget = require( "widget" )
widget.setTheme( "widget_theme_ios" )

local bg = display.newRect(display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight)
	bg:setFillColor( 1, 0, 0 )

local function changeColor( event )
	local selectedSegment = event.target.segmentNumber		-- find the segment that was selected
	if ( selectedSegment == 1 ) then
		bg:setFillColor( 1, 0, 0 )
	elseif ( selectedSegment == 2 ) then
		bg:setFillColor( 0, 1, 0 )
	else
		bg:setFillColor( 0, 0, 1 )
	end
end


local segmentedControl = widget.newSegmentedControl
	{
	x = display.contentWidth/2,
	y = 200,
	segmentWidth = 150,
	segments = { "Red", "Green", "Blue" },
	defaultSegment = 1,
	onPress = changeColor
	}