Shopify / react-native-skia

High-performance React Native Graphics using Skia
https://shopify.github.io/react-native-skia
MIT License
6.86k stars 442 forks source link

[Android] Text with dynamic width parent makes text stretch/compress #1561

Open joarkosberg opened 1 year ago

joarkosberg commented 1 year ago

Description

So I have two skia text components beside each other horizontally and I want them to stay close. The text of the components are dynamic related to a graph. So I need the width of the text parent to change based on the text width.

This is a combination of reanimated parent view and skia text field. So might not be skia specific, but looks like it maybe. Or just me using this wrong 😊

Version

0.1.188

Steps to reproduce

Per now I do something like the provided example, an animated view from reanimated (3) outside, with a canvas + text from skia inside. The reanimated view uses an animated style, with changing width based on the text, which is a shared value.

This works nicely on iOS, the view resizes nicely and the text is shown as it should. 2023-05-10 13 27 06

But on Android the text get compressed/stretched a lot when changing values. The background resizes fine in as seen in the gif, but the text compresses/stretches 2023-05-10 13 26 42

Snack, code example, screenshot, or link to a repository

    text: SharedValue<string>;
    fontSize: number; 
    const lineHeight = fontSize * 1.4;
    const font = useFont(font, fontSize);

    const animatedStyle = useAnimatedStyle(() => {
        const newSize =
            (font?.getTextWidth(text.value) ?? 0) * offsetMultiplier;
        return {
            width: newSize,
            height: lineHeight,
        };
    });

    return (
        <Animated.View style={animatedStyle}>
            <Canvas
                style={{
                    flex: 1
               }}
            >
                <Text
                    text={text}
                    font={font}
                    y={fontSize}
                    x={0}
                />
            </Canvas>
        </Animated.View>
    );
joarkosberg commented 1 year ago

Note that putting both texts inside one canvas, with dynamic X position of the second text works for both iOS and Android. Which probably is the preferred way of doing this 😊

chrfalch commented 1 year ago

Could you try to extend the example so that I can copy it into the example app and run it? Make sure there are now other external dependencies in use except for Skia and Reanimated.

wcandillon commented 1 year ago

We would definitely need a small standalone reproducible example here.

joarkosberg commented 1 year ago

Sorry for being a bit slow on providing example, I created a example from the react native starter with only skia and reanimated added here: https://github.com/joarkosberg/SkiaTest .

Added just one text component width dynamic width, where iOS is fine and Android compresses/stretches. Might be a problem with my usage as well here, but in case it is a bug 😊

iOS test app: Simulator Screen Recording - iPhone 8 - 2023-05-19 at 09 46 26

Android test app:

device-2023-05-19-094649.webm

wcandillon commented 1 year ago

Oups, that looks bad πŸ˜… Thanks for taking the time to make a reproducible example. Small question: would the same bug happens too with a circle for instance? Or is it only with Text?

joarkosberg commented 1 year ago

Oups, that looks bad πŸ˜… Thanks for taking the time to make a reproducible example. Small question: would the same bug happens too with a circle for instance? Or is it only with Text?

Tested with circle now, it is the same behaviour as Text. Tested also with having height and width dynamic (radius*4), which made the circle not compress/stretch on android, but it got displaced when changing size. Seems like both this displacement and the compress/stretch is based on some of the last components properties.

device-2023-05-19-1016227.webm