在WP7手机的开始屏幕,如果你Hold住某一个瓷贴,就会发现除了你按住的那个瓷贴其他全部下沉半透明,然后开始在不停地漂来漂去~~
今天来模仿一下这个效果。新建一个项目,然后在Grid里放一个ListBox。OK 开始编写 ListBox 的模版。首先是ItemsPanelTemplate。<ListBox.ItemsPanel> <ItemsPanelTemplate> <toolkit:WrapPanel/> </ItemsPanelTemplate></ListBox.ItemsPanel>我们放一个WrapPanel,让它进行自动排列和换行。然后就是主要的 ItemTemplate。 <ListBox.ItemTemplate> <DataTemplate> <Canvas Width="185" Height="185"> <Grid x:Name="grid"> <Grid.RenderTransform> <TranslateTransform/> </Grid.RenderTransform> <Grid.Resources> <Storyboard x:Name="sbTranslate"> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"> <EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/> <EasingDoubleKeyFrame x:Name="translateX" KeyTime="00:00:1" Value="0"> <EasingDoubleKeyFrame.EasingFunction> <SineEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> <DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Storyboard.TargetName="grid" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.Y)"> <EasingDoubleKeyFrame KeyTime="0:0:0" Value="0"/> <EasingDoubleKeyFrame x:Name="translateY" KeyTime="00:00:1" Value="0"> <EasingDoubleKeyFrame.EasingFunction> <SineEase EasingMode="EaseInOut"/> </EasingDoubleKeyFrame.EasingFunction> </EasingDoubleKeyFrame> </DoubleAnimationUsingKeyFrames> </Storyboard> </Grid.Resources> <Image Visibility="Collapsed" Source="/Images/StartPage_DeleteFav.png" Width="42" Height="42" HorizontalAlignment="Right" VerticalAlignment="Top" Canvas.ZIndex="1" MouseLeftButtonUp="Image_MouseLeftButtonUp" Margin="-10"/> <toolkit:HubTile GroupTag="QuickLink" Notification="{Binding Notification}" Message="{Binding Message}" Title="{Binding Title}" Source="{Binding Src}" Background="{StaticResource PhoneAccentBrush}"/> </Grid> </Canvas> </DataTemplate> </ListBox.ItemTemplate> 这里 放了一个 Grid ,里面很简单,一个 Image 用来 做 右上角删除图标。然后是一个 HubTile,简单模仿一下。主要的是 Grid 里 写的 资源,两个 DoubleAnimationUsingKeyFrames,用来操作 TranslateTransform。好,前台很简单。来看看后台。先为 ListBox 添加几个事件:Loaded="listBox_Loaded" LostFocus="listBox_LostFocus" SelectionChanged="listBox_SelectionChanged"
先来写Loaded 事件:for (int i = 0; i < listBox.Items.Count; i++) { ListBoxItem item = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromIndex(i); item.Hold += item_Hold; }为每个listboxitem 添加 必须的 Hold 事件。 void item_Hold(object sender, System.Windows.Input.GestureEventArgs e) { if (!isHold) { isHold = true; var item = sender as ListBoxItem; holdItem = item; for (int i = 0; i < items.Count; i++) { ListBoxItem _item = (ListBoxItem)listBox.ItemContainerGenerator.ContainerFromItem(items[i]); if (_item != item) { Transform(1, 0.75, _item, 0.2); var grid = FindVisualChild<Grid>(_item);var sb = grid.Resources["sbTranslate"] as Storyboard;
storyList.Add(Bouncing(sb,false), grid.DataContext);
} else { //显示按住item的关闭按钮 var img = FindVisualChild<Image>(_item); img.Visibility = System.Windows.Visibility.Visible; } } } } 在item_Hold事件里做了两件事:显示按住item的关闭按钮,其他item 下沉半透明,然后是启动漂动:Bouncing(sb,false);Bouncing 这个方法,返回一个 DispatcherTimer 第一个参数是一个Storyboard,那这里放入的就是在前台为 Grid 添加的 资源里的 Storyboard。先是找到这个 ListboxItem 里的 FindVisualChild<Grid>(_item),然后再找出他的 Storyboard。那重点来说一下这个函数。 private DispatcherTimer Bouncing(Storyboard sb,bool isover) { Random random = new Random(); DoubleKeyFrame sp0 = ((DoubleAnimationUsingKeyFrames)sb.Children[0]).KeyFrames[0]; DoubleKeyFrame ea0 = ((DoubleAnimationUsingKeyFrames)sb.Children[0]).KeyFrames[1]; DoubleKeyFrame sp1 = ((DoubleAnimationUsingKeyFrames)sb.Children[1]).KeyFrames[0]; DoubleKeyFrame ea1 = ((DoubleAnimationUsingKeyFrames)sb.Children[1]).KeyFrames[1];sp0.Value = 0;
sp1.Value = 0; ea0.Value = 0; ea1.Value = 0;DispatcherTimer dispatcherTimer = new DispatcherTimer() { Interval = TimeSpan.FromSeconds(0) };
dispatcherTimer.Tick += delegate { sb.Stop(); sp0.Value = ea0.Value; sp1.Value = ea1.Value; if (!isover) { ea0.Value = random.Next(-10, 10);//随机数 X ea1.Value = random.Next(-10, 10);//随机数 Y sb.Begin(); } dispatcherTimer.Interval = TimeSpan.FromSeconds(random.Next(9, 13) *0.1); }; if (isover) sb.Begin(); else dispatcherTimer.Start();return dispatcherTimer;
} 先是根据传入的 Storyboard 找出 它里面DoubleAnimationUsingKeyFrames的每个DoubleKeyFrame。然后在找出每个DoubleKeyFrame的Value,并初始化。接下来是生成一个DispatcherTimer对象,这里初始化的Interval是0,也就是立马执行下面Tick的事件,不会造成刚开始动画延迟的感觉。在对ea0和ea1赋值,用一个随机数,范围在-10到10。也这就在这个方圆内漂动。而上面的sp0和sp1的赋值是为了下一次动画,不是从零开始的。下面还有一句:dispatcherTimer.Interval = TimeSpan.FromSeconds(random.Next(9, 13) *0.1);这句是为了让每个Timer的间隔有所不同,就不会造成所有瓷贴同时漂动同时结束的统一动作。 OK,主要的代码都介绍完了,上图 还有很多功能,比如 listBox_SelectionChanged,OnBackKeyPress,StopBouncing,就不多介绍了,这里就说一下我实现的方法思路,就是通过,调用动画通过 Timer 来控制,来实现 飘动效果。如果有兴趣,可以继续了解我下面的 DEMO。BouncingDemo: