react-native-skia icon indicating copy to clipboard operation
react-native-skia copied to clipboard

Text not redrawing when using useFont

Open BubbleTrouble14 opened this issue 2 years ago • 1 comments

I am using a custom font for my app and the only way to use it with skia text is by using the useFont hook. But the issue I have in development when using it, is that after code change the text doesn't re-render as the font ends up returing null. The only way to get it to show again is when reloading the entire app. For the time being I just use a default font which doesnt cause the font not redrawing as I don't have to use the useFont hook. Is there any intention to fix this ?

Here is a screenshot demonstrating it with the example app of yours. As one can see the useFont ends up returning null, thus not re-rendering the text when doing code changes.

image

BubbleTrouble14 avatar Aug 04 '22 19:08 BubbleTrouble14

Thanks, @BubbleTrouble14 - we'll investigate this one and see what's going on here - I think we're having some examples where we're using custom fonts, could you try to create a minimal repro on Github that we can look at?

chrfalch avatar Aug 07 '22 09:08 chrfalch

@chrfalch You should be able to test the issue using your skia examples actually. It may be something that only occurs on android side as i havent been able to test it on apple yet.

BubbleTrouble14 avatar Aug 07 '22 10:08 BubbleTrouble14

@chrfalch I'm having the same issue as well. In fact, this bug is causing my Skia animations to not run as well. It gets stuck here:

Xnapper-2022-08-11-11 47 04

Minimal Repro

const CircularProgressBar: FunctionComponent<ProgressBarProps> = ({
  label,
  labelX = 0,
  labelY = 0,
  textSize = 32,
}) => {
  const font = useFont(customFont, textSize)

  if (font === null) {
    return null
  }

  return (
      <Text
        x={c.x - labelX}
        y={c.y - labelY}
        font={font}
        text={label}
        color={isDarkMode ? 'white' : 'black'}
      />
  )
}

Removing useFont and the circular progress animation starts running again.

thespacemanatee avatar Aug 11 '22 03:08 thespacemanatee

@chrfalch I'm having the same issue as well. In fact, this bug is causing my Skia animations to not run as well. It gets stuck here:

Xnapper-2022-08-11-11 47 04

Minimal Repro

const CircularProgressBar: FunctionComponent<ProgressBarProps> = ({
  label,
  labelX = 0,
  labelY = 0,
  textSize = 32,
}) => {
  const font = useFont(customFont, textSize)

  if (font === null) {
    return null
  }

  return (
      <Text
        x={c.x - labelX}
        y={c.y - labelY}
        font={font}
        text={label}
        color={isDarkMode ? 'white' : 'black'}
      />
  )
}

Removing useFont and the circular progress animation starts running again.

Solved when useFont is used from the parent component and passed into the child component that is using the font instead, but I'm still facing the issue mentioned by @BubbleTrouble14.

thespacemanatee avatar Aug 11 '22 03:08 thespacemanatee

Could you show me how customFont looks like?

wcandillon avatar Aug 11 '22 06:08 wcandillon

Could you show me how customFont looks like?

As far as i have tested. It doesnt matter which custom font one uses.

BubbleTrouble14 avatar Aug 11 '22 10:08 BubbleTrouble14

@thespacemanatee could you expand on what the minimal repro is? Could you send me all the files needed to run the examples as well as the exact steps to reproduce the issue?

wcandillon avatar Aug 12 '22 06:08 wcandillon

@wcandillon my codebase is a little messy right now but I can definitely whip one up if needed. Have you tried hot-reloading with Skia examples as mentioned by @BubbleTrouble14? He mentioned that he could reproduce this issue using the Skia examples. This happens on both Android and iOS for us.

thespacemanatee avatar Aug 12 '22 17:08 thespacemanatee

I had the same issue (only tested on iOS), my solution is to use the last non null font:

  const font = useFont(monoRegular, 8);
  const lastNonNullFont = useRef(font);
  if (font) {
    // Font becomes null after hot-reload during dev.
    lastNonNullFont.current = font;
  }
  
 if (lastNonNullFont.current === null) {
    return null;
  }

  // use lastNonNullFont.current

Although I'm having a worse issue on prod build of Android as the font is always null, possibly relating to dexguard as it's only null on the CI build which does dexguard and proguard. However these font's work fine elsewhere and in react-native-svg.

dominictobias avatar Aug 16 '22 15:08 dominictobias

Same problem here, is there any old version that useFont worked? I'm testing the library for the first time

RalissonMattias avatar Aug 16 '22 16:08 RalissonMattias

Same problem here, is there any old version that useFont worked? I'm testing the library for the first time

Don’t think so. For the time being i just use the default font. Which is never null.

BubbleTrouble14 avatar Aug 16 '22 16:08 BubbleTrouble14

Same problem here, is there any old version that useFont worked? I'm testing the library for the first time

Don’t think so. For the time being i just use the default font. Which is never null.

Do you have an example using the default font?

RalissonMattias avatar Aug 16 '22 16:08 RalissonMattias

Same problem here, is there any old version that useFont worked? I'm testing the library for the first time

Don’t think so. For the time being i just use the default font. Which is never null.

Do you have an example using the default font?

Here you go: (Sry for bad formatting on my phone)

const typeface = Skia.FontMgr.RefDefault().matchFamilyStyle('serif'); if (!typeface) { throw new Error('Helvetica not found'); } const font = Skia.Font(typeface, 9);

BubbleTrouble14 avatar Aug 16 '22 16:08 BubbleTrouble14

Same problem here, is there any old version that useFont worked? I'm testing the library for the first time

Don’t think so. For the time being i just use the default font. Which is never null.

Do you have an example using the default font?

Here you go: (Sry for bad formatting on my phone)

const typeface = Skia.FontMgr.RefDefault().matchFamilyStyle('serif'); if (!typeface) { throw new Error('Helvetica not found'); } const font = Skia.Font(typeface, 9);

Oh! Thank you. But here it didn't work FontMgr is not found. Version: ^0.1.141

RalissonMattias avatar Aug 16 '22 16:08 RalissonMattias

Ah then they removed it in the latest release. Downgrading would make it work for the time being.

Same problem here, is there any old version that useFont worked? I'm testing the library for the first time

Don’t think so. For the time being i just use the default font. Which is never null.

Do you have an example using the default font?

Here you go: (Sry for bad formatting on my phone) const typeface = Skia.FontMgr.RefDefault().matchFamilyStyle('serif'); if (!typeface) { throw new Error('Helvetica not found'); } const font = Skia.Font(typeface, 9);

Oh! Thank you. But here it didn't work FontMgr is not found. Version: ^0.1.141

BubbleTrouble14 avatar Aug 16 '22 17:08 BubbleTrouble14

We think this issue might be fixed now. Please feel free to reopen the issue if it is persisting.

wcandillon avatar Aug 19 '22 08:08 wcandillon

UseFont examples, all using custom fonts, Since method like Skia.FontMgr.RefDefault().matchFamilyStyle('serif') has been removed, how should I use the system default font? @wcandillon

zhiqingchen avatar Sep 07 '22 06:09 zhiqingchen

I'm having the same issue that @zhiqingchen describes here ^ how should we import fonts now? I can't find documentation anywhere :(

aymather avatar Sep 21 '22 23:09 aymather

@aymather Do you have any ideas?

zhiqingchen avatar Sep 30 '22 08:09 zhiqingchen

We do not support "system" fonts at the moment, currently you need to import the fonts manually, like in this example: https://github.com/Shopify/react-native-skia/blob/main/example/src/Examples/Wallet/components/Label.tsx#L31 I hope this helps

wcandillon avatar Sep 30 '22 08:09 wcandillon