While I am a huge fan of widgets on iOS, most apps miss the mark in terms of
what they offer via their widgets. Because I’m not one to settle, I have been on
a quest to build my own widgets so that I can get exactly what I desire.
Fortunately, I happened upon Scriptable (thanks Geoff!), which makes it extremely easy to write your own iOS widgets with good ol’ JavaScript!
Sadly, the documentation kinda sucks, at least in terms of providing examples.
There is a gallery of scripts other folks have written, but it was pretty thin. The content available was more in line with existing scripts that you could leverage, and not clean examples of how to do things.
While writing my own widget, I had to figure out how to get things to align the
way I wanted them. Specifically, I wanted to be able to utilize the entire widget area, and have everything space itself out accordingly. Essentially, I wanted things to function like they do when using the flexible box (flexbox
) in CSS.
Fortunately, Scriptable provides an addSpacer()
method, that you can pass in a length value to. If you omit the length argument, or pass it a null
value, the
spacer will become flexible, and will consume any left over space.
Armed with this, you can center text or build out a grid system that will span
the entirety of the widget!
For demonstration purposes, I put together a script that creates a 9 by 9 grid,
that will stretch both horizontally and vertically to full the widget. Each area has text that tells you which part of the widget it is (like a compass):
async function createWidget() {
const widget = new ListWidget();
const layoutStack = widget.addStack();
layoutStack.layoutVertically();
const topStack = layoutStack.addStack();
const northWestEl = topStack.addText('NW');
topStack.addSpacer();
const northEL = topStack.addText('N');
topStack.addSpacer();
const northEastEl = topStack.addText('NE');
layoutStack.addSpacer();
const middleStack = layoutStack.addStack();
const westEl = middleStack.addText('W');
middleStack.addSpacer();
const centerEl = middleStack.addText('Center');
middleStack.addSpacer();
const eastEl = middleStack.addText('E');
layoutStack.addSpacer();
const bottomStack = layoutStack.addStack();
const southWestEl = bottomStack.addText('SW');
bottomStack.addSpacer();
const southEl = bottomStack.addText('S');
bottomStack.addSpacer();
const southEastEl = bottomStack.addText('SE');
return widget;
}
const widget = await createWidget();
if (config.runsInWidget) {
Script.setWidget(widget);
} else {
widget.presentLarge();
}
Script.complete();
JavaScriptThe resulting widget looks like this (captured from the Scriptable macOS beta
app):
