动画分割翻盖显示

时间:2014-03-17 21:08:40

标签: c# wpf animation

我想使用c#/ wpf创建一个动画分割翻页显示。我希望它看起来类似于this video中可以看到的那个,但没有3D效果。由于我对wpf没有太多经验,所以我想知道如何为单个动画字母实现UserControl。

3 个答案:

答案 0 :(得分:3)

如果没有3D,您可以使用多个图像执行此操作。

想法#1想想GIF动画。只有,您将有一组图像从1翻转到2.另一组图像从2翻转到3等...

请参阅本网站的选项2: http://www.wpfsharp.com/2011/05/11/wpf-replacement-options-for-an-animated-gif

然后,您将点击开始故事板,然后以新图像而不是同一图像结束。你拥有的图像越多,它就越不稳定。

想法#2 我的另一个想法是为每个数字使用顶部和底部图像。使用RenderTransform更改弯曲图像。

看看这个。我把它给了你一半:

<Window.Resources>
    <Storyboard x:Key="FlipNumberStoryBoard">
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleX)" Storyboard.TargetName="Img1Top">
            <EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="10"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="20"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="35"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="60"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="75"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="88"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="Img1Top">
            <EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="-2.01"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="-3.45"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="-5.55"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="-7"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="-8.75"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="-9.5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="-8.25"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Img1Top">
            <EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="0.90"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="0.80"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="0.60"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="0.40"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0.20"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="0.10"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="0.01"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="Img1Top">
            <EasingDoubleKeyFrame KeyTime="0:0:0.1" Value="2.5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.2" Value="5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.3" Value="10.1"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="15"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="20"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.6" Value="22.6"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.7" Value="24.9"/>
        </DoubleAnimationUsingKeyFrames>
        <Int32AnimationUsingKeyFrames Storyboard.TargetProperty="(Panel.ZIndex)" Storyboard.TargetName="Img2Bottom">
            <EasingInt32KeyFrame KeyTime="0:0:0.8" Value="1"/>
        </Int32AnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Img1Top">
            <DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{x:Static Visibility.Collapsed}"/>
        </ObjectAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[1].(SkewTransform.AngleX)" Storyboard.TargetName="Img2Bottom">
            <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-88"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="-75"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-60"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="-35"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-20"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="-10"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="-5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" Storyboard.TargetName="Img2Bottom">
            <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="0.01"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="0.10"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="0.20"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="0.40"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="0.60"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="0.80"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="0.90"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="1"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.X)" Storyboard.TargetName="Img2Bottom">
            <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-9.121"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="-8.87"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-8.564"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="-7"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-5.438"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="-3.5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="-2.001"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[3].(TranslateTransform.Y)" Storyboard.TargetName="Img2Bottom">
            <EasingDoubleKeyFrame KeyTime="0:0:0.8" Value="-24.75"/>
            <EasingDoubleKeyFrame KeyTime="0:0:0.9" Value="-22.5"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1" Value="-20.062"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.1" Value="-15.062"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.2" Value="-10"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.3" Value="-5.062"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.4" Value="-2.562"/>
            <EasingDoubleKeyFrame KeyTime="0:0:1.5" Value="0"/>
        </DoubleAnimationUsingKeyFrames>
        <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="Img2Bottom">
            <DiscreteObjectKeyFrame KeyTime="0:0:0.8" Value="{x:Static Visibility.Visible}"/>
        </ObjectAnimationUsingKeyFrames>
    </Storyboard>
</Window.Resources>
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="Auto"/>
        <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Image x:Name="Img2Top" Source="Images/02top.png" Grid.Row="1" Width="70" Height="50" RenderTransformOrigin="0.5,0.5" Margin="0,-1,0,0"/>
    <Image x:Name="Img1Top" Source="Images/01top.png" Grid.Row="1" Width="70" Height="50" RenderTransformOrigin="0.5,0.5" Margin="0,-1,0,0">
        <Image.RenderTransform>
            <TransformGroup>
                <ScaleTransform/>
                <SkewTransform/>
                <RotateTransform/>
                <TranslateTransform/>
            </TransformGroup>
        </Image.RenderTransform>
    </Image>
    <Image x:Name="Img2Bottom" Source="Images/02.png" Grid.Row="2" Width="70" Height="50" Visibility="Collapsed" RenderTransformOrigin="0.5,0.5">
        <Image.RenderTransform>
            <TransformGroup>
                <ScaleTransform/>
                <SkewTransform/>
                <RotateTransform/>
                <TranslateTransform/>
            </TransformGroup>
        </Image.RenderTransform>
    </Image>
    <Image x:Name="Img1Bottom" Source="Images/01.png" Grid.Row="2" Width="70" Height="50" RenderTransformOrigin="0.5,0.5"/>
    <Button Content="Next" HorizontalAlignment="Left" Margin="223.5,5,0,0" Grid.Row="3" VerticalAlignment="Top" Width="70" Click="Button_Click" />
</Grid>

然后点击按钮,你可以看到翻转。

using System.Windows;
using System.Windows.Media.Animation;

namespace RenderTransformExample
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void Button_Click(object sender, System.Windows.RoutedEventArgs e)
        {
            var storyboard = (Storyboard)this.Resources["FlipNumberStoryBoard"];
            storyboard.Begin();
        }
    }
}

现在把它挂起以便它只是循环显示图像取决于你。

答案 1 :(得分:2)

您可以使用ScaleTransform来实现动画,并使用一些依赖项属性来使UserControl易于使用。

首先,您必须将您的信件分成两半显示,这可以使用以下样式完成:

<Style x:Key="UpperHalf" TargetType="ContentControl">
    <Style.Setters>
        <Setter Property="FontFamily" Value="Courier New" />
        <Setter Property="Foreground" Value="Black" />
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="RenderTransformOrigin" Value="0.5,1" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                    <Border Height="{Binding ElementName=SizeRef,
                                                Path=ActualHeight,
                                                Converter={StaticResource HalfConverter}}"
                            VerticalAlignment="Top"
                            Background="{TemplateBinding Background}"
                            CornerRadius="10,10,0,0"
                            Padding="10,0">
                        <ContentPresenter Content="{TemplateBinding Content}" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>
<Style x:Key="LowerHalf" TargetType="ContentControl">
    <Style.Setters>
        <Setter Property="FontFamily" Value="Courier New" />
        <Setter Property="VerticalAlignment" Value="Bottom" />
        <Setter Property="RenderTransformOrigin" Value="0.5,0" />
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ContentControl">
                    <Border Height="{Binding ElementName=SizeRef,
                                                Path=ActualHeight,
                                                Converter={StaticResource HalfConverter}}"
                            VerticalAlignment="Bottom"
                            Background="{TemplateBinding Background}"
                            CornerRadius="0,0,10,10"
                            Padding="10,0">
                        <ContentPresenter Content="{TemplateBinding Content}">
                            <ContentPresenter.ContentTemplate>
                                <DataTemplate>
                                    <TextBlock VerticalAlignment="Bottom" Text="{Binding}" />
                                </DataTemplate>
                            </ContentPresenter.ContentTemplate>
                        </ContentPresenter>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style.Setters>
</Style>

然后显示两个重叠的字母(旧字母和新字母):

<Grid>
    <!--  Hidden textblock, only used for measurement purpose  -->
    <!--  The border is here to set the total height of the display so that we can have a small space between the two halves  -->
    <Border Margin="0,1" Visibility="Hidden">
        <TextBlock Name="SizeRef"
                   Margin="10,0"
                   FontFamily="Courier New"
                   Text="{Binding ElementName=Root,
                                  Path=Letter}" />
    </Border>

    <ContentControl Name="Letter1Top"
                    Background="Gray"
                    Content="{Binding ElementName=Root,
                                      Path=Letter1}"
                    Style="{StaticResource UpperHalf}">
        <ContentControl.RenderTransform>
            <ScaleTransform />
        </ContentControl.RenderTransform>
    </ContentControl>
    <ContentControl Name="Letter2Top"
                    Background="Gray"
                    Content="{Binding ElementName=Root,
                                      Path=Letter2}"
                    Style="{StaticResource UpperHalf}">
        <ContentControl.RenderTransform>
            <ScaleTransform />
        </ContentControl.RenderTransform>
    </ContentControl>
    <ContentControl Name="Letter1Bottom"
                    Background="Gray"
                    Content="{Binding ElementName=Root,
                                      Path=Letter1}"
                    Style="{StaticResource LowerHalf}">
        <ContentControl.RenderTransform>
            <ScaleTransform />
        </ContentControl.RenderTransform>
    </ContentControl>
    <ContentControl Name="Letter2Bottom"
                    Background="Gray"
                    Content="{Binding ElementName=Root,
                                      Path=Letter2}"
                    Style="{StaticResource LowerHalf}">
        <ContentControl.RenderTransform>
            <ScaleTransform />
        </ContentControl.RenderTransform>
    </ContentControl>
</Grid>

上面使用的属性是在后面的代码中创建的:

public partial class SplitFlapLetter
{
    public SplitFlapLetter()
    {
        InitializeComponent();
    }

    public char Letter
    {
        get { return (char)GetValue(LetterProperty); }
        set { SetValue(LetterProperty, value); }
    }

    public static readonly DependencyProperty LetterProperty =
        DependencyProperty.Register("Letter", typeof(char), typeof(SplitFlapLetter), new UIPropertyMetadata(OnLetterChanged));

    private char Letter1
    {
        get { return (char)GetValue(Letter1Property); }
        set { SetValue(Letter1Property, value); }
    }

    public static readonly DependencyProperty Letter1Property =
        DependencyProperty.Register("Letter1", typeof(char), typeof(SplitFlapLetter), new UIPropertyMetadata(null));

    private char Letter2
    {
        get { return (char)GetValue(Letter2Property); }
        set { SetValue(Letter2Property, value); }
    }

    public static readonly DependencyProperty Letter2Property =
        DependencyProperty.Register("Letter2", typeof(char), typeof(SplitFlapLetter), new UIPropertyMetadata(null));

    private bool _isLetter1Active;

    private static void OnLetterChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var uc = d as SplitFlapLetter;
        if (uc == null) return;

        if (uc._isLetter1Active)
            uc.Letter2 = uc.Letter;
        else
            uc.Letter1 = uc.Letter;

        var sb = uc.FindResource(uc._isLetter1Active ? "GotoLetter2Animation" : "GotoLetter1Animation") as Storyboard;
        if (sb != null) sb.Begin();

        uc._isLetter1Active = !uc._isLetter1Active;
    }

    private readonly List<char> _letters = new List<char> { 'A', 'B', 'C', 'D', 'E' };

    private void OnClick(object sender, MouseButtonEventArgs e)
    {
        Letter = _letters[(_letters.IndexOf(Letter) + 1) % _letters.Count];
    }
}

Letter属性是唯一的公共属性,并且有一个监听器对其进行更改。 此侦听器将Letter1或Letter2设置为新值,每次运行时都会更改,以便其他属性仍设置为旧值。

然后启动UserControl资源中定义的两个故事板之一:

<Storyboard x:Key="GotoLetter1Animation">
    <DoubleAnimation Duration="0:0:0"
                        Storyboard.TargetName="Letter1Bottom"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="0" />

    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter2Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="2" />
    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter2Bottom"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="1" />
    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter1Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="1" />
    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter1Bottom"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="2" />

    <DoubleAnimation Duration="0:0:0.2"
                        From="1"
                        Storyboard.TargetName="Letter2Top"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="0" />

    <DoubleAnimation BeginTime="0:0:0.2"
                        Duration="0:0:0.2"
                        From="0"
                        Storyboard.TargetName="Letter1Bottom"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="1" />

    <Int32Animation BeginTime="0:0:0.4"
                    Duration="0:0:0"
                    Storyboard.TargetName="Letter1Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="2" />
    <Int32Animation BeginTime="0:0:0.4"
                    Duration="0:0:0"
                    Storyboard.TargetName="Letter2Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="1" />

    <DoubleAnimation BeginTime="0:0:0.4"
                        Duration="0:0:0"
                        Storyboard.TargetName="Letter2Top"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="1" />
</Storyboard>

<Storyboard x:Key="GotoLetter2Animation">
    <DoubleAnimation Duration="0:0:0"
                        Storyboard.TargetName="Letter2Bottom"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="0" />

    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter1Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="2" />
    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter1Bottom"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="1" />
    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter2Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="1" />
    <Int32Animation Duration="0:0:0"
                    Storyboard.TargetName="Letter2Bottom"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="2" />

    <DoubleAnimation Duration="0:0:0.2"
                        From="1"
                        Storyboard.TargetName="Letter1Top"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="0" />

    <DoubleAnimation BeginTime="0:0:0.2"
                        Duration="0:0:0.2"
                        From="0"
                        Storyboard.TargetName="Letter2Bottom"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="1" />

    <Int32Animation BeginTime="0:0:0.4"
                    Duration="0:0:0"
                    Storyboard.TargetName="Letter2Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="2" />
    <Int32Animation BeginTime="0:0:0.4"
                    Duration="0:0:0"
                    Storyboard.TargetName="Letter1Top"
                    Storyboard.TargetProperty="(Panel.ZIndex)"
                    To="1" />

    <DoubleAnimation BeginTime="0:0:0.4"
                        Duration="0:0:0"
                        Storyboard.TargetName="Letter1Top"
                        Storyboard.TargetProperty="(Border.RenderTransform).(ScaleTransform.ScaleY)"
                        To="1" />
</Storyboard>

可能有一些方法可以减少这个xaml,并且只使用一个会使用相应目标的故事板。

答案 2 :(得分:1)

我认为this项目可以真正为您提供基础。

不幸的是,如果没有3D,我不会看到这种分离式翻盖显示效果如何。

祝你好运!