UWP開發入門(二十二)——Storyboard和Animation


  微博上有同學問我MyerSplash是如何實現那個很炫的圖片點亮,然后移動到屏幕中央的效果。慚愧啊,我又不是作者哪里會知道。硬着頭皮去GitHub拜讀了高手的代碼,自愧弗如,比我不知道高到哪里去了……這時我就面臨一個艱難的抉擇,要么就寫個幾十篇來分析一下MyerSplash(萬一分析錯了好丟人……),要么就說看不懂(貌似也很丟人……)。

  幸虧我臨機一動,決定山寨一個極簡版,做一點微小的工作,順便寫一篇博客蹭點熱度,給某軟,給UWP續一秒……

  首先要明確我們希望以少量的代碼來模擬MyerSplash的部分效果,較少的代碼分析起來更為易懂,所以各位同學就不要抱怨說這個是五毛錢特效……

  

    <ListView ItemsSource="{Binding Photos,Mode=OneTime}" ItemContainerStyle="{StaticResource photoItemContainerStyle}">
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <ItemsWrapGrid Orientation="Horizontal"></ItemsWrapGrid>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
        <ListView.ItemTemplate>
            <DataTemplate>
                <Image Source="{Binding ImageUri,Mode=OneTime}" Stretch="UniformToFill" IsTapEnabled="True" Tapped="Image_Tapped"></Image>
            </DataTemplate>
        </ListView.ItemTemplate>
    </ListView>

  上面的XAML繪制了一個根據元素數量自動換行的列表,列表中的Item元素就是單純的Image,同時Item元素響應一個Tapped事件(這個我們后面說)。

  

  可以看到鼠標移動時,會有一個動畫,0.5秒的漸變點亮同時圖片放大的效果(生成的這個gif圖比較渣,實際效果請運行代碼)。這是通過自定義ItemContainerStyle並在其中添加VisualStateManager來實現的。

        <Style x:Key="photoItemContainerStyle" TargetType="ListViewItem">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate>
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal" />
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0:0:0.5" From="0.5" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="contentPhoto" ></DoubleAnimation>
                                            <DoubleAnimation Duration="0:0:0.5" From="1" To="1.2" Storyboard.TargetProperty="ScaleX" Storyboard.TargetName="scaleGrid" ></DoubleAnimation>
                                            <DoubleAnimation Duration="0:0:0.5" From="1" To="1.2" Storyboard.TargetProperty="ScaleY" Storyboard.TargetName="scaleGrid" ></DoubleAnimation>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                           
                            <Grid.Clip>
                                <RectangleGeometry Rect="0 0 200 200"/>
                            </Grid.Clip>

                            <Grid Background="Black">
                                <ContentPresenter x:Name="contentPhoto" Width="200" Height="200" Opacity="0.5">
                                    <ContentPresenter.RenderTransform>
                                        <ScaleTransform x:Name="scaleGrid" ScaleX="1.0" ScaleY="1.0" CenterX="100" CenterY="100"></ScaleTransform>
                                    </ContentPresenter.RenderTransform>
                                </ContentPresenter>
                            </Grid>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>

  在 <VisualState x:Name="PointerOver">這個狀態我們通過Storyboard播放了三個Animation來改變圖片的透明度,以及長寬。透明度從0.5變化至1時,圖片不再透明,背景黑色Grid不再可見,模擬高亮效果。同時通過Clip將放大后圖片的外緣裁剪仍保持原始大小。

  貌似已經做的差不多了……至少你已經學會如何山寨照片牆了。接下來我們要做點不一樣的,換一種方式來使用StoryboardAnimation,點擊圖片放大並移動到屏幕中央的功能,我打算通過C#代碼實現(話說這部分有點坑,寫得時候搞死我了……

  浮動顯示的圖片我們采用Popup來顯示,通過給Popup添加Child,並通過storyboardanimation來改變WidthHeight屬性控制圖片大小的變化。圖片的位移則是將PopupRenderTransform屬性設置為TranslateTransform,然后改變X軸和Y軸坐標來實現。

  這里需要注意Animation對象的EnableDependentAnimation屬性,這個坑爹的屬性是 Windows Runtime 8.1新增的,如果你發現自定義的Animation不能播放,又找不到任何錯誤,那就需要把這個屬性值置為true

        private void Image_Tapped(object sender, TappedRoutedEventArgs e)
        {
            popup.IsOpen = false;

            var tappedImage = e.OriginalSource as Image;
            var image = new Image { Source = tappedImage.Source };
            popup.Child = image;
            popup.IsOpen = true;

            //獲取被點擊圖片相對MainPage的坐標
            var position = tappedImage.TransformToVisual(this).TransformPoint(new Point());
            //獲取MainPage的中心坐標
            var xCenter = ActualWidth / 2 - 200 ;
            var yCenter = ActualHeight / 2 - 200;

            var storyBoard = new Storyboard();
            var extendAnimation = new DoubleAnimation { Duration = new Duration(TimeSpan.FromSeconds(0.5)), From = 200, To = 400, EnableDependentAnimation = true };
            Storyboard.SetTarget(extendAnimation, image);
            Storyboard.SetTargetProperty(extendAnimation, "Width");
            Storyboard.SetTargetProperty(extendAnimation, "Height");

            var xAnimation = new DoubleAnimation { Duration = new Duration(TimeSpan.FromSeconds(0.5)), From = position.X, To = xCenter, EnableDependentAnimation = true };
            Storyboard.SetTarget(xAnimation, popup);
            Storyboard.SetTargetProperty(xAnimation, "(UIElement.RenderTransform).(TranslateTransform.X)");

            var yAnimation = new DoubleAnimation { Duration = new Duration(TimeSpan.FromSeconds(0.5)), From = position.Y, To = yCenter, EnableDependentAnimation = true };
            Storyboard.SetTarget(yAnimation, popup);
            Storyboard.SetTargetProperty(yAnimation, "(UIElement.RenderTransform).(TranslateTransform.Y)");

            storyBoard.Children.Add(extendAnimation);
            storyBoard.Children.Add(xAnimation);
            storyBoard.Children.Add(yAnimation);

            storyBoard.Begin();
        }

  補充下Popup的定義,記得要設置popup.RenderTransform = TranslateTransform(),默認可是null

    public sealed partial class MainPage : Page
    {
        public List<PhotoModel> Photos { get; set; }

        private Popup popup = new Popup();

        public MainPage()
        {
            this.InitializeComponent();
            Photos = CreatePhotos();
            this.DataContext = this;
            popup.RenderTransform = new TranslateTransform();
        }

  總體就這么些了,大約100行左右的代碼,直接拿去賣錢肯定是不行的。作為Demo演示給吃瓜群眾,或者忽悠BOSS還是可以的。如果需要用到產品中,去GayHub下載代碼自己改吧改吧,調調UI

  有問題新浪微博@樓上那個蜀黍,免費咨詢,當然質量也是免費的程度……

  GitHub

  https://github.com/manupstairs/UWPSamples/tree/master/UWPSamples/StoryboardSample

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM