Posted on by

On iOS, many apps include a share button that lets you share your app’s features, whether it be a message, an achievement, or a high score via various services like Facebook, Twitter, email, etc. On Android, the Corona SDK plugin shows all of the device’s valid methods of sharing, but on iOS, Corona doesn’t offer a pre-built sharing panel. As such, expanding upon last week’s widget.newPanel() tutorial, let’s walk through the steps to construct a sharing panel.

For iOS, this panel is implemented in two different ways, one with a block of icons and one with text-like buttons. This tutorial will focus on the latter and we’ll implement it with a widget.newTableView() so that the entire row is touchable and triggers the event.

Note that for true iOS-style functionality, this tutorial depends on the native.showPopup() API and the social plugin. The social plugin is a premium feature for Pro and Enterprise subscribers, so if you’re a Starter or Basic subscriber, you’ll need to rewrite some aspects to utilize the native.showPopup() version of Twitter and void support of Facebook.

Setting Up

Like previous tutorials, we’ll attach our new sharing panel to the widget library for easy reference. Let’s begin by requiring the widget library. Next, we’ll need to add the widget.newPanel() function from the previous tutorial. Third, begin a new function for our sharing panel.

local widget = require( "widget" )

-- Insert core function from the widget.newPanel() tutorial here!
function widget.newSharingPanel()

Create the Table View Helpers

Implementing a table view in Corona requires some “helper” functions that handle row rendering (creation) and touching of the rows. Because we must adhere to proper scoping rules in Lua, this tutorial will explain the process in a way that presents these functions before they’re actually referenced by the table view constructor. To make the table view work, two functions are necessary:

  • onRowRender() — function to draw each row
  • onRowTouch() — function to handle each row being tapped

The onRowRender() function is straightforward — it basically just determines the appearance of each row. If it’s a category row, we create a text label Share and center it within the row. If it’s not a category row, we create a text label based on what is passed to the params.label value.

    local function onRowRender( event )
        local row = event.row
        local id = row.index
        local params = event.row.params
        if ( row.isCategory ) then
            row.text = display.newText( "Share", 0, 0, native.systemFont, 14 )
            row.text:setFillColor( 0.67 )
            row.text.x = display.contentCenterX
            row.text.y = row.contentHeight * 0.5
            row:insert( row.text )
        else
            row.text = display.newText( params.label, 0, 0, native.systemFont, 18 )
            row.text:setFillColor( 0.5, 0.5, 1.0 )
            row.text.x = display.contentCenterX
            row.text.y = row.contentHeight * 0.5
            row:insert( row.text )
        end
    end

The onRowTouch() function is a little more complex…

    local function onRowTouch( event )
        local popupName = event.row.params.popupName
        local service = event.row.params.service

        if ( popupName == nil ) then  --the cancel button
            local myPanel = event.row.params.parent
            myPanel:hide()
            return true
        end

        if ( popupName == "mail" ) then
            native.showPopup( popupName, 
            { body = body, attachment = attachment } )
        elseif ( popupName == "sms" ) then
            native.showPopup( popupName, 
            { body = body } )
        elseif ( popupName == "social" ) then
            local isAvailable = native.canShowPopup( popupName, service )
            if ( isAvailable ) then
                native.showPopup( popupName, 
                { service = service, message = message, image = image, url = url } )
            else
                if ( isSimulator ) then
                    native.showAlert( "Build for device", "This plugin is not supported on the Corona Simulator, please build for an iOS/Android device or the Xcode simulator", { "OK" } )
                else
                    -- Popup is not available.. Show error message
                    native.showAlert( "Cannot send " .. service .. " message.", "Please setup your " .. service .. " account or check your network connection (on android this means that the package/app (i.e. Twitter) is not installed on the device)", { "OK" } )
                end
            end
        end
        return true
    end

First, there must be a way to determine the functionality of the cancel button. Since there is no popup for this, if the row has no popupName in its parameters, we can assume that it’s the cancel row. This also needs a reference to the parent’s panel function to call its :hide() method (this is passed in with the params as the parent option). Thus, if the cancel button is pressed, the panel will slide off the screen.

Second, each of the popups require different parameters, so we use the table view row params table to pass in the bits that each sharing popup requires. In the conditional logic, the entry popupName indicates which popup to use, and for the social plugin, service defines which service to use. Note that the social plugin may or may not be available, so we test for it and also test if we’re using the Simulator.

Create the Panel

Next, create an empty widget.newPanel() based on the widget.newPanel() tutorial:

    local panel = widget.newPanel{
        location = "bottom",
        width = display.contentWidth,
        height = 240,
        speed = 500,
        inEasing = easing.outCubic,
        outEasing = easing.outCubic
    }

This panel is rather standard. We set its location to "bottom" so that it will slide up from the bottom of the screen. We also make it the width of the screen and set the height to 240. This assumes that the panel will support Facebook, Twitter, email, and SMS, in addition to a header row and a cancel row. At a height of 40 pixels each, these 6 rows will occupy the height of the table view. Finally, we set a speed of 500 and include some easing parameters to create a more pleasing transition effect.

Create the Empty Table View

The only thing that will be added to the panel is the table view. The following code creates an empty table view widget and inserts it in the panel widget. Note that the rendering and touch parameters reference the functions that we created above.

    local tableView = widget.newTableView{
        top = 0, 
        left = 0,
        width = display.contentWidth - 16, 
        height = 240, 
        backgroundColor = { 0.9 }, 
        noLines = true,
        onRowRender = onRowRender,
        onRowTouch = onRowTouch 
    }
    tableView.x = 0
    tableView.y = 0
    panel:insert( tableView )

Insert the Rows

Next, we’ll insert the rows into the table — a header row, rows for the various popups, and a cancel row.

    -- Header row
    tableView:insertRow{
        rowHeight = 40,
        isCategory = true,
        rowColor = { 1, 1, 1 },
    }
    -- Facebook row
    tableView:insertRow{
        rowHeight = 40,
        isCategory = false,
        rowColor = { 1, 1, 1 },
        params = {
            popupName = "social",
            service = "facebook",
            label = "Facebook",
            message = "Some text to post to facebook",
            image = nil,  -- See the native.showPopup("social") plugin for image parameters.
            url = nil,    -- See the native.showPopup("social") plugin for url parameters.
        }
    }
    -- Twitter row
    tableView:insertRow{
        rowHeight = 40,
        isCategory = false,
        rowColor = { 1, 1, 1 },
        params = {
            popupName = "social",
            service = "twitter",
            label = "Twitter",
            message = "Some text to post to twitter",
            image = nil,  -- See the native.showPopup("social") plugin for image parameters.
            url = nil,    -- See the native.showPopup("social") plugin for url parameters.
        }
    }
    -- Email row
    tableView:insertRow{
        rowHeight = 40,
        isCategory = false,
        rowColor = { 1, 1, 1 },
        params = {
            popupName = "mail",
            label = "Email",
            body = "Some text to email",
            attachment = nil, -- See the native.showPopup("mail") API for attachment parameters.
        }
    }
    -- SMS row
    tableView:insertRow{
        rowHeight = 40,
        isCategory = false,
        rowColor = { 1, 1, 1 },
        params = {
            popupName = "sms",
            label = "Message",
            body = "Some text to text",
        }
    }
    -- Cancel row
    tableView:insertRow{
        rowHeight = 40,
        isCategory = false,
        rowColor = { 1, 1, 1 },
        params = {
            label = "Cancel",
            parent = panel
        }
    }
    return panel

Close the Function

Finally, don’t forget to close the widget.newSharingPanel() function with an end statement!

end

Showing the Panel

To create the actual panel and get an object reference to it, simply call the newSharingPanel() function:

local sharePanel = widget.newSharingPanel()

Then, to show and hide the panel, use the following methods that are built in to the widget.newPanel() function:

sharePanel:show()

sharePanel:hide()

sharing_panel

Conclusion

Hopefully this tutorial gets you started with implementing a basic sharing panel in the iOS 7 style. To experiment with this project further, please download the sample project and, as usual, leave your feedback below.


Posted by . Thanks for reading...

10 Responses to “Tutorial: Creating a Sharing Panel”

  1. Kerem

    Nice! I’m sure this will be useful.

    How about a blurred glass backdrop? I recall Walter long time ago had shown a demo doing this with G2 filters. Take a snapshot of screen before popping up panel, apply blur filter and set it as background to the popup panel etc. Something along these lines.

    Reply
    • Rob Miracle

      Sure it’s possible. There isn’t any reason, if you wanted the blurred background that you couldn’t implement Walter’s tutorial with this.

      Reply
  2. JCH_APPLE

    Hi,

    You should replace “row” with “target” in the rowTouch listener (line 123 & 124)
    You also use an unknown serviceName var line 158 (should be replaced with service I think)

    This way code is OK

    Reply
    • Rob Miracle

      Are you referring to these two lines?

      local popupName = event.row.params.popupName
      local service = event.row.params.service

      If so, event.row.params is correct for this. I’ll fix up the serviceName issue. Thanks for pointing it out.

      Reply
      • JCH_APPLE

        Yes, I’ve tried the code with daily build 2258, using

        local popupName = event.row.params.popupName
        local service = event.row.params.service

        generates an error

        /Applis_CORONA/_2014/SlidePanel/main.lua:123: attempt to index field ‘row’ (a nil value)

        “row” is correct in onRowRender event but not in onRowTouch

        Reply
        • Rob Miracle

          Okay thanks for the report. This will require some deeper investigation.

          Rob

          Reply
  3. Peter Dwyer

    Hey Rob, as per JCH_APPLE’s comment. onRowTouch should be using event.target not event.row so the listed code doesn’t work.

    >_<

    Reply
  4. Dave Baxter

    Weird thing for me it ran once and clicking cancel made it slide down like it should, then after refreshing (CMD+R) I started getting the error.

    Now I always get the error!

    Dave

    Reply
  5. Rob Miracle

    Try to use it with out a tap.. Hold the press just a little longer. Do you still get the error? What version of Corona are you using?

    Reply

Leave a Reply

  • (Will Not Be Published)