2010-12-30 11 views
2

Ich animiere ein TextBlock. In 60 Sekunden erhöht sich FontSize von 8pt auf 200pt. Alles funktioniert gut, nur dass sich meine Animation ein wenig nach oben und unten bewegt, während der Text wächst. Warum passiert das und ist es möglich dies zu vermeiden?WPF: Animation ist nicht glatt

Ich habe eine sehr einfache XAML-Datei:

<Window x:Class="Timer.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Width="800" 
     Height="500" 
     Title="MainWindow" 
     Loaded="Window_Loaded"> 

    <Grid> 

     <TextBlock 
      Name="TimerTextBlock" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center" 
      Text="00h : 00m : 00.000s" /> 

    </Grid> 

</Window> 

Und ebenso einfache Code-behind:

public partial class MainWindow : Window 
{ 
    private const string timerFormat = "{0:hh'h : 'mm'm : 'ss'.'fff's'}"; 
    private DispatcherTimer dispatcherTimer; 
    private DateTime targetTime; 

    public MainWindow() 
    { 
     InitializeComponent(); 
    } 

    private void Window_Loaded(object sender, RoutedEventArgs e) 
    { 
     targetTime = DateTime.Now.AddSeconds(60); 
     double totalTime = targetTime.Subtract(DateTime.Now).TotalMilliseconds; 

     DoubleAnimation animation = new DoubleAnimation(); 
     animation.From = TimerTextBlock.FontSize; 
     animation.To = 200; 
     animation.Duration = new Duration(targetTime.Subtract(DateTime.Now)); 
     TimerTextBlock.BeginAnimation(TextBlock.FontSizeProperty, animation); 

     dispatcherTimer = new DispatcherTimer(); 
     dispatcherTimer.Interval = TimeSpan.FromMilliseconds(1); 
     dispatcherTimer.Tick += new EventHandler(dispatcherTimer_Tick); 
     dispatcherTimer.Start(); 
    } 

    private void dispatcherTimer_Tick(object sender, EventArgs e) 
    { 
     if (DateTime.Compare(targetTime, DateTime.Now) > 0) 
     { 
      TimerTextBlock.Text = 
       string.Format(timerFormat, targetTime.Subtract(DateTime.Now)); 
     } 
    } 
} 

Danke für alle Erklärungen.

+0

Ich kam zu dem Schluss, dass es definitiv das Problem mit "Pixel Splitting" ist. Es macht Sinn, ein bisschen zu hacken, da das Steuerelement in eine Situation kommt, in der es irgendwo zwischen zwei Pixeln gezeichnet werden muss. Aber gibt es einen Weg, dies irgendwie zu vermeiden? – Boris

+0

Ich habe nach Antworten im Internet gesucht und bin auf einige "MatrixAnimations" gestoßen. Was ist das, könnte es den Trick machen? (Und wenn ja, wie?) – Boris

Antwort

2

Ihr Problem beim vertikalen Springen ist auf die Rundung von Font-Rendering zurückzuführen. Insbesondere wird WPF die Subpixelschrifthöhe vermeiden, um die Schriftartenglättung zu ermöglichen. Eine Möglichkeit, dies zu vermeiden, besteht darin, Ihren Text in eine Pfadgeometrie umzuwandeln und dann mithilfe einer Skalierungstransformation zu animieren.

Hier ist eine alternative Version Ihres Beispiels ohne das Springen. Die neue XAML ist:

<Grid> 
    <Path Name="Path" HorizontalAlignment="Center" VerticalAlignment="Center"/> 
</Grid> 

und der neue Code, wenn Sie das Fenster laden:

SetText(""); 
var transform = new ScaleTransform(1, 1); 
Path.LayoutTransform = transform; 
var animationX = new DoubleAnimation(1, 10, new Duration(TimeSpan.FromSeconds(60))); 
transform.BeginAnimation(ScaleTransform.ScaleXProperty, animationX); 
var animationY = new DoubleAnimation(1, 10, new Duration(TimeSpan.FromSeconds(60))); 
transform.BeginAnimation(ScaleTransform.ScaleYProperty, animationY); 

und eine neue Methode, den Text zu setzen, die anmiated ist:

private void SetText(string text) 
{ 
    var formatted = new FormattedText(text, CultureInfo.CurrentCulture, FlowDirection.LeftToRight, new Typeface("Lucida Console"), 12, Brushes.Black); 
    Path.Data = formatted.BuildGeometry(new Point(0, 0)); 
    Path.Fill = Brushes.Black; 
} 

und Sie Rufen Sie SetText von Ihrem Timer-Ereignishandler auf.

Beachten Sie, dass Sie eine Textzeichenfolge fester Länge und eine Schriftart mit konstanter Breite verwenden müssen, um horizontale Jumpiness zu vermeiden.

+0

+ 1 Sehr schön. Der Text wird jetzt reibungslos animiert, es gibt jedoch leichte Alias-Effekte auf dem Text, wenn er wächst. Wird das erwartet? –

+0

Sub-Pixel-Anti-Aliasing ist für die Glättung der Animation essentiell. Es ist also ein Kompromiss: knackiger Text oder flüssige Animationen. –

+0

Nice one. Zu schade, dass Sie auf die Textzeichenfolge mit fester Länge und eine Schriftart mit konstanter Breite beschränkt sind, aber es gibt keine andere Möglichkeit, den Text zentriert auszurichten. – Boris