Using SFSymbol in widgets?

Hi all. For a calendar widget, I am trying to replace common words with SFSymbols, to conserve space.

I’m testing it with turning “call” into a phone symbol. However, instead of getting the symbol itself in my widget, I get [object SFSymbol] or [object Image] if I use the .image property.

How do I get the symbol to render? Is this a problem with my javascript, the way I’m using SFSymbols in Scriptable, or something else? Thanks!

Here’s the function I wrote — I just pass the calendar title text to it before inserting the result as the widget line text.


function mod(title_text) {
  split = title_text.split(" ");
  var result_list = [];
  var i;
  for (i=0; i<split.length; i++) {
    if (split[i].toLowerCase() == "call") {
      r = SFSymbol.named("phone.arrow.up.right")
    }
    else {
      r = split[i];
    } // end else
    result_list.push(r);
  } // end for loop
  result = result_list.join(" ");
  return result
} // end mod funx

Here’s what the widget winds up looking like:

image image

SFSymbols behave as images in Scriptable. You can call r.image and add the image to a widget.

Hm. I tried that. Here’s the section of the script that calls my function:


      let title_text = mod(futureEvents[i].title)
      let title = widget.addText(title_text) 
      title.font = Font.semiboldSystemFont(titleSizeNow)

Here’s the result:

image

Here’s the function calling the .image property


function mod(title_text) {
  split = title_text.split(" ");
  var result_list = [];
  var i;
  for (i=0; i<split.length; i++) {
    if (split[i].toLowerCase() == "call") {
      r = SFSymbol.named("phone.arrow.up.right")
      r = r.image
    }
    else {
      r = split[i];
    } // end else
    result_list.push(r);
  } // end for loop
  result = result_list.join(" ");
  return result
} // end mod funx

Were you able to get this to work? I’d be curious as I’m trying to call a SFSymbol for a battery in my greeting widget.

I wasn’t. Are you getting the same result? I’m wondering if I have to explicitly use SF fonts. I thought that was my default system font already though.

Yeah, same exact result. I’m a complete novice though. I’m sure I’m close.

Can you try something like this?

let sym = SFSymbol.named("tortoise")
let w = new ListWidget()
let wimg = w.addImage(sym.image)
wimg.imageSize = new Size(50, 50)
w.presentSmall()

Image

(iOS 14.0.1, Scriptable 1.5.1 build 166)

Can you alter the colour of the SFSymbol image?

Yes. Just set the tint color on the WidgetImage.

let sym = SFSymbol.named("tortoise")
let w = new ListWidget()
let wimg = w.addImage(sym.image)
wimg.tintColor = Color.blue()
wimg.imageSize = new Size(50, 50)
w.presentSmall()
2 Likes

Thank you so much!! That’s so simple, all my wasted effort :laughing:

Yes, this code works for me as well.

Unfortunately, I want the symbol inline with the text rather than as an image. So easier to use an emoji instead. But now I know how to use SFSymbol if it comes up again. Thanks!

Right, that’s not really supported. Depending on your exact needs, you may be able to split up your text and insert it into a horizontal stack with an SFSymbol. If tweaked correctly, it might be possible to make it look like the image is part of the text.

1 Like

I have done this in my Reddit viewer. Will update here in next day or so with example.

Here is an example with inline SFSymbols:

Has anyone else noticed that SFsymbols are sometimes not the correct aspect ratio? I’ve tried using “lock.fill”, but it looks stretched horizontally.

In addition, when I try to adjust the size of the image it scales proportionally so I can’t easily overcome this.

I want to draw the symbol image into a DrawContext, but I’m unable to change it’s color.
Eg:
let img = sym.image;
img.tintColor = Color.white(); //Not sure if this is supposed to work, but doens't throws any error.
dc.drawImageAtPoint(img, new Point(x, y))
Draws a black symbol :confused:.

I recently ran into this with an SFsymbol that was colored by default. It doesn’t look like there is a way that you can tint an image object when you’re drawing it to a DrawContext, you can only tint a WidgetImage.

Notice in the docs for image you can’t change an image at all. It would be nice if drawImageAtPoint had an optional tint parameter,

For what its worth, here’s a function for you to add to your scripts to make is easier to add a SFSymbol:

function addSymbol({
  symbol = 'applelogo',
  stack,
  color = Color.white(),
  size = 20,
}) {
  const _sym = SFSymbol.named(symbol)
  const wImg = stack.addImage(_sym.image)
  wImg.tintColor = color
  wImg.imageSize = new Size(size, size)
}

And you would use it like so:

const w = new ListWidget()
const row = w.addStack()

addSymbol({
  symbol: 'hand.thumbsup.fill',
  stack: row,
  color: Color.white(),
  size: 18,
})

I have set defaults for symbol, color and size so you can omit any one of them if the default is what you want to use, like so:

addSymbol({
  symbol: 'hand.thumbsup.fill',
  stack: vidRow,
})

Or the SFSymbol object having a color property would be nice!

1 Like