Widgets — Creating a sliding panel

panel-feat
Share on Facebook0Share on Google+6Tweet about this on TwitterShare on LinkedIn0

Today’s tutorial demonstrates how to create a sliding panel that has many uses, ranging from games to business applications. You might build an adventure game where the player’s inventory needs to slide on the screen, then hide itself when the user is done. Or you might build a menu that slides in when the player taps the infamous “hamburger” menu icon. Yet another possibility is sliding notices in and out.

As with the previous UI tutorials on navigation panels and text fields, this tutorial will extend the widget library, creating a new widget called widget.newPanel(). Let’s look at the entire function:

For consistency, this new widget will follow the coding standard of the other widgets in the Corona open source widget library. Like other widgets, we begin by passing in a table of parameters necessary to create the panel (lines 5 through 27). These include:

  • location — where the panel originates from (left, right, top, or bottom).
  • width — the width of the panel.
  • height — the height of the panel.
  • speed — how fast the panel shows and hides (slides in or out).
  • inEasing — the transition easing method used when the panel shows.
  • outEasing — the transition easing method used when the panel hides.
  • onComplete — a function to execute when the panel completes showing and hiding.

All parameters are optional and are set to reasonable defaults. The location parameter is a string value of either "left", "right", "top" or "bottom" that defaults to "top". The speed parameter defaults to 500 milliseconds. inEasing and outEasing are linear by default but can be set to any of the standard easing methods.

onComplete is optional and defaults to nil. In the above example, we actually create two completion listeners, one for each of the actions the panel supports (panel:show() and panel:hide()).

Code notes

Let’s step through the function code and inspect some important aspects:

  • When adding the code to define the listener (lines 23-27), it’s helpful to make sure that a parameter was passed, but also that it’s a function and not some other variable type.
  • If a panel slides in from the left or right, it’s reasonable to take up the full height of the visible screen, but the width would need to be specific to the app. Panels coming in from the top or bottom may take up the full width of the device but be limited to 1/3 of the screen.
  • Line 29 creates a display.newContainer(). This is similar to display.newGroup(), except that its bounds are automatically clipped to the defined width and height. This container object is returned on line 95 to the calling function.
  • The panel is positioned off screen based on the location specified. Since there are many ways to set up the size and scale in config.lua, this function uses display.screenOriginX and display.screenOriginY to reference the left and top of the screen. Likewise, display.actualContentWidth and display.actualContentHeight represents the right and bottom edges of the screen. By setting the anchor point to the side of the container that faces the content area, we can use these values to position it. The other value will simply center the container along that edge.
  • To show and hide the panel, two methods are included named show() and hide(). Lines 53-93 implement these two functions. The panels will be shown or hidden using a simple transition.to() call, but first we need to determine where to move the panel to. If we’re sliding the panel in/out from the top or bottom, we need to transition the y value. If we’re sliding it in/out from either side, we need to use the x value. Again, we use the defined points for the sides of the screen and either add or subtract the width or height of the panel.

Using the “widget.newPanel()”

To use the panel, simply create a new object, in this case panel, and above that, the optional listener function that’s specified as the onComplete parameter:

When done, panel will be the container object to which we can add whatever content desired using the object:insert() call. To keep things more organized, display objects can optionally be added directly to the panel object:

Showing and hiding

When desired, we can show or hide the panel by simply calling the proper method:

Composer notes

If you’re using Composer, you may not want to insert the panel into the Composer group because the panel is generally intended to slide over anything else in the scene. However, if you choose to add it to the scene’s view, it should be the last thing inserted into the scene, or else you should call object:toFront() to move it to the top of the scene’s view.

On the general topic of Composer, you may ask “shouldn’t this be done with an overlay?”. While that is a valid approach, overlays are individual scenes and it takes more effort to construct and deconstruct a scene. In contrast, widget.newPanel() yields a simple slide-in/out unit which can be used with or without Composer.

In summary

This tutorial should get you started with implementing basic sliding panels in your app. With some clever adjustments to the various parameters, you can easily implement a wide variety of panels that appear from different sides of the screen and utilize unique easing transitions.

To use this widget in your own projects, please download the code from our GitHub repository.


Share on Facebook0Share on Google+6Tweet about this on TwitterShare on LinkedIn0
Rob Miracle

Rob Miracle creates mobile apps for his own enjoyment and the amusement of others. He serves the Corona Community in the forums, on the blog, and at local events.

This entry has 25 replies

  1. Harry Tran says:

    This looks awesome, is this available now for all users including the ones using the Basic Edition?

    • Rob Miracle says:

      Hi Harry. I believe all the techniques here are available to all subscriber tiers.

      Rob

  2. Kerem says:

    Excellent work! Thank you very much! Any luck for this new widget to be included in the core and supported going forward?

    • Peter says:

      +1

    • Rob Miracle says:

      Sometimes we add new features to the core and write tutorials to help you understand how to use them. Other times like this, it’s a matter of showing you how to do things and give you an ah-ha moment and empower you to build the features you need.

      We are in the process of adding it to the community code and to our GitHub repository for those who want to fork the project and customize it to their needs.

  3. Hey I rolled my own similar to this, but this one has some much more elegant solutions than mine. *YOINK*! Thanks a ton!

  4. Dave baxter says:

    These type of tutorials could do with some images or a video, so we can see the finished result. Then we can decide if it something that we would find useful.

    Dave

  5. Martin says:

    Hi,

    Could you add an example implementation? As a newbie it is very difficult to get this example working…..

    Martin

  6. Could add a full example with story board??

  7. Rob Miracle says:

    Okay here’s an example: http://coronalabs.com/blog/2014/04/15/tutorial-creating-a-sharing-panel/

    Not a fully functional one with Storyboard, but you should be able to drop this into any project. The thing with Storyboard and Composer is you probably do not want to insert it into the view group since it’s supposed to be on top of everything. But then you become responsible for removing it.

  8. Mahdi says:

    wow, this is great! Keep up the good work #teamCorona!

  9. Jeff Leigh says:

    How about a screen shot or two in these post Rob?

    Can’t tell if this is immediately useful to me without having to try it.

    Picture speaks a thousand words 🙂

    • Rob Miracle says:

      Hi Jeff. I understand the desire for this, which is one reason we did this week’s “sharing panel” tutorial (referenced two posts above), so you could see it in action (and there is a screen shot with it. To demoed anything more would have required a tutorial on it’s own, ergo this week’s sharing panel.

  10. Poh says:

    Hi Rob,

    Can you change the location of entry on the fly? Meaning is it possible to say rotate the entry from left clockwise to bottom each time panel:show() is called by setting the location dynamically?

    Thanks.

    • Rob Miracle says:

      I’m not sure I follow what you want to do. But the show code is pretty straight forward, so you can modify it to do what you want.

  11. david says:

    Nice tutorial, it would be nice to block clicks/etc of the parent scene where slide panel shows up at the top of the scene.

    • Rob Miracle says:

      Some programmers might want to have background items touchable. It’s easy to fix that. Had we done a Composer overlay scene, you would have had a chance to set the .isModal flag. You can expand this to include your own version of .isModal by having a full screen invisible rectangle that has it’s .isHitTestable property set to true and then add a touch and tap handler to it that consumes them.

      Rob

      • Sang says:

        Hi Rob

        I am not sure where should I put “.isModal = true” above code to make the background items untouchable?

        Please, advise.

        Thank you.

        Sang.

        • Rob Miracle says:

          The sliding panel as written does not support .isModal. That’s a feature using Composer. If you want to implement something similar to .isModal, simply put a touch and tap handler on the panels’s background that throws the touch or tap away.

  12. Miro says:

    Can I use display.new BitmapText instead display.newText?

    • Miro says:

      I answer myself … yes 🙂

      panel.title = display.newBitmapText(“Old text”, screenCenterX, screenCenterY, “lobster0”, 42)
      panel:insert( panel.title )

      ….

      panel.title:setText(“New text”)

      Works 🙂

    • Rob Miracle says:

      We don’t provide a display.newBitmapText API, but if you have one, no reason you can’t use it.

Leave a reply

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">