Absolute positioning of a Popover

One of the joys of open-source is to wander through the code for undocumented features. Sometimes because you hope to find something you need. Like last week, when I tried to find a way to position – the arrow of – a Popover exactly where I wanted it to be.

Inheritance

The documentation shows it does not inherit top/right/bottom/left or center from Ti.UI.View and that it does inherit show – which is strange because you probably know Popover expects a view property which determines where the arrow will show, while for a regular view this just toggles the visible option.

Source code

If we look at the source code we see that indeed a Popover does not inherit show, but defines it’s own. And while the Popover examples only demonstrate the view property, it looks like there’s also rect, animated and arrowDirection. The last one can also be set on the Popover object itself and determines the middle of which of the 4 sides of the given view the arrow will point to.

Rect

It’s the rect property that is interesting. You’ll recognise this one from Ti.UI.View.rect, where it has the coordinates and dimensions of the view relative to its parent, after it has been layed out.

Option Dialog

More interesting is another search result where it is one of the properties for Ti.UI.OptionDialog.show() about which the documentation says:

On iPad, this dialog is shown in the middle of the display or, when specified via the params argument, as a popover-like dialog attached to another view or control.

Aha, so the Option Dialog and Popover show() methods seem very much alike and at least the first one documents the existence of the rect property. But what does it do?!

The trick

Well, when documentation fails… just try! So I did and what I found out is that rect basically can be seen as the bounding box of a non-existing child of the view you’re passing. Using this we can point the arrow to anywhere within the view. Set both rect.width and rect.height to1 and then position this 1×1 child where you want it using rect.x and rect.y.

Example

To understand the next example, know that a view’s click event also has an e.x and e.y which is the coordinate of the event from the source view’s coordinate system – the source being e.source. Sounds familiar right?

Code

var win = Ti.UI.createWindow({
  backgroundColor: '#31BEE8'
});

win.addEventListener('click', function(e) {
  
  var popover = Ti.UI.iPad.createPopover({
    contentView: Ti.UI.createLabel({
      text: 'Hello World!',
      font: {
        fontSize: 40
      }
    })
  });

  popover.show({
    view: e.source,
    rect: {
      width: 1,
      height: 1,
      x: e.x,
      y: e.y
    },

    animated: false,
    arrowDirection: Ti.UI.iPad.POPOVER_ARROW_DIRECTION_DOWN
  });

});

win.open();

Demo

Popover

An alternative

An alternative would be to first create a 1×1 view where you want the Popover and then pass that view to show(). But why would you now you know about rect? :)

App imagineer: Imagining, Engineering & Speaking about Native mobile Apps with Appcelerator Titanium & Alloy • Meetup organizer • Certified Expert • Titan


Comments

  • Joseph

    Yes I figured that one out previously ‘rect’…. Very handy. Especially if the x/y of a view keeps changing.