How to animate scale of TextBlock in UWP

2019-04-14 15:48发布

When I use Storyboard to zoom in TextBlock it pixelates while zooming and rerenders only on complete.

<DoubleAnimationUsingKeyFrames Storyboard.TargetName="TextBlock" Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleY)">
      <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1.5"/>

Is there a way the TextBlock is rerendered each frame?

2条回答
劫难
2楼-- · 2019-04-14 16:18

I found a solution though it's not about TextBlock anymore but for me it worked:

    private void CreateText(string text)
    {
        _compositor = ElementCompositionPreview.GetElementVisual(this).Compositor;
        CreateDevice();

        _spriteTextVisual = _compositor.CreateSpriteVisual();
        _spriteTextVisual.Size = new Vector2(512, 512);

        _drawingTextSurface = _graphicsDevice.CreateDrawingSurface(new Size(512, 512), DirectXPixelFormat.B8G8R8A8UIntNormalized, DirectXAlphaMode.Premultiplied);

        using (var ds = CanvasComposition.CreateDrawingSession(_drawingTextSurface))
        {
            ds.Clear(Colors.Transparent);
            ds.DrawText(text, new Rect(0, 0, 512, 512), Colors.Black, new CanvasTextFormat
            {
                FontSize = 32,
                FontWeight = FontWeights.Light,
                VerticalAlignment = CanvasVerticalAlignment.Top,
                HorizontalAlignment = CanvasHorizontalAlignment.Center,
                LineSpacing = 32
            });
        }

        _surfaceTextBrush = _compositor.CreateSurfaceBrush(_drawingTextSurface);

        _spriteTextVisual.Brush = _surfaceTextBrush;

        ElementCompositionPreview.SetElementChildVisual(this, _spriteTextVisual);
    }

    private void CreateDevice()
    {
        _device = CanvasDevice.GetSharedDevice();
        _device.DeviceLost += Device_DeviceLost;

        if (_graphicsDevice == null)
        {
            _graphicsDevice = CanvasComposition.CreateCompositionGraphicsDevice(_compositor, _device);
        }
        else
        {
            CanvasComposition.SetCanvasDevice(_graphicsDevice, _device);
        }
    }

    private async void Device_DeviceLost(CanvasDevice sender, object args)
    {
        _device.DeviceLost -= Device_DeviceLost;
        await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, CreateDevice);
    }

Just have to make this text of max scale size.

查看更多
Melony?
3楼-- · 2019-04-14 16:43

It seems that this is by design - see this answer by Jerry Nixon on a very similar question.

Apparently this is to ensure the animation is smooth, because rendering the font fully at each frame would be expensive.

The only way you could probably overcome this is to wrap the TextBlock inside a Viewbox element and scale the Viewbox's Height property. This will however not work automatically and you also have to add EnableDependentAnimation="True" to the DoubleAnimationUsingKeyFrames element. Unfortunatelly you will see that this approach also causes layout updates on each frame and is therefore very jarring.

查看更多
登录 后发表回答