(3)FluidMoveBehavior 之模仿 Windows Phone 开始菜单的 Tile 长按后排序
2013-09-05 16:46
316 查看
这个工程和上一篇 (2)中介绍的排序大同小异,只是比上一篇交换复杂一点,不是通过单击进行交换,
而是拖动一个 Tile 到另一个 Tile 上时,判断两个 Tile 的中心距离是否符合条件来判断是否进行交换两个 Tile。
归根结底还是利用 FluidMoveBehavior 行为来使 Silverlight 的元素在重新定位时,产生动画效果。毕竟在
实际开发中,用户体验还是很重要的,生动的交互比生硬的交互会更让用户感到亲切。
当然项目中也用到了视觉状态管理相关的技术,因为不是重点,这里不会过多的介绍。
效果交互图:
View Code
第二步:定义不同的 Tile 在重叠时,判断中心点的距离,是否小于 40px,如果是,则交换两个 Tile。
如果 Tile 控件的 宽和 高设置为 150px,则各个控件的坐标为:
当拖动一个 Tile 到其它 Tile 上时,判断两个 Tile 的中心点坐标的距离:
第三步:在 MainPage 页面中,添加一个 Grid,分别放置各个自定义控件,并且每个自定义控件放在一个 Boder 里面,
并且分别注册 Border 的长按事件 Hold 统一为 Border_Hold:
第四步:在 MainPage 页面的 CodeBehind 中,定义一个类型为 Dictionary<Point, Border> 的泛型字典 dic,
当页面加载完成时,初始化该字典:
在 Border 的 Border_Hold 方法中,添加逻辑,用来处理各个 Tile 的视图状态,并且注册 ManipulationDelta 和 MouseLeftButtonUp 事件:
当手指离开选择的 Tile 时,判断各个 Tile 的中心点的距离,从而判断是否具备交换两个 Tile 的条件:
重要代码粘贴到上面了,具体代码可以下载工程。至此有关 FluidMoveBehavior 行为的三篇文章暂时写完了。
这个demo 运行的交互很简单,但是算法上还是颇费周折,想了几种实现方式,最终采用了上面的方式,重点时间
都花费在了数学计算上了。不过 demo 的代码还是比较粗糙,性能也没有优化,只是实现了大概的交互。
工程源码下载
而是拖动一个 Tile 到另一个 Tile 上时,判断两个 Tile 的中心距离是否符合条件来判断是否进行交换两个 Tile。
归根结底还是利用 FluidMoveBehavior 行为来使 Silverlight 的元素在重新定位时,产生动画效果。毕竟在
实际开发中,用户体验还是很重要的,生动的交互比生硬的交互会更让用户感到亲切。
当然项目中也用到了视觉状态管理相关的技术,因为不是重点,这里不会过多的介绍。
效果交互图:
public partial class TileControl : UserControl { public TileControl() { InitializeComponent(); this.DataContext = this; } #region TileBackground (依赖属性) /// <summary> /// Tile 的背景图片 /// </summary> public string TileBackground { get { return (string)GetValue(TileBackgroundProperty); } set { SetValue(TileBackgroundProperty, value); } } public static readonly DependencyProperty TileBackgroundProperty = DependencyProperty.Register("TileBackground", typeof(string), typeof(TileControl), new PropertyMetadata("/Assets/Tiles/FlipCycleTileMedium.png")); #endregion // 漂浮 static Random rand = new Random(); public void Float() { // 使 tile 进入不同的漂浮状态 switch (rand.Next(5)) { case 1: VisualStateManager.GoToState(this, "FloatVisualState1", false); break; case 2: VisualStateManager.GoToState(this, "FloatVisualState2", false); break; case 3: VisualStateManager.GoToState(this, "FloatVisualState3", false); break; case 4: VisualStateManager.GoToState(this, "FloatVisualState4", false); break; default: VisualStateManager.GoToState(this, "FloatVisualState3", false); break; } } // 选中 public void Checked() { VisualStateManager.GoToState(this, "CheckedVisualState", false); } // 恢复 public void Reset() { VisualStateManager.GoToState(this, "NormalVisualState", false); } }
View Code
第二步:定义不同的 Tile 在重叠时,判断中心点的距离,是否小于 40px,如果是,则交换两个 Tile。
如果 Tile 控件的 宽和 高设置为 150px,则各个控件的坐标为:
当拖动一个 Tile 到其它 Tile 上时,判断两个 Tile 的中心点坐标的距离:
第三步:在 MainPage 页面中,添加一个 Grid,分别放置各个自定义控件,并且每个自定义控件放在一个 Boder 里面,
并且分别注册 Border 的长按事件 Hold 统一为 Border_Hold:
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> <Grid.Resources> <Style TargetType="Border"> <Setter Property="Background" Value="Transparent"/> </Style> </Grid.Resources> <Grid.RowDefinitions> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> <RowDefinition Height="Auto"/> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="Auto"/> </Grid.ColumnDefinitions> <i:Interaction.Behaviors> <el:FluidMoveBehavior x:Name="fluidBehavior" AppliesTo="Children" Duration="00:00:01"> <el:FluidMoveBehavior.EaseY> <QuinticEase EasingMode="EaseOut"/> </el:FluidMoveBehavior.EaseY> <el:FluidMoveBehavior.EaseX> <QuinticEase EasingMode="EaseOut"/> </el:FluidMoveBehavior.EaseX> </el:FluidMoveBehavior> </i:Interaction.Behaviors> <Border Hold="Border_Hold"> <local:TileControl TileBackground="/Assets/Tiles/01.png"/> </Border> <Border Grid.Column="1" Hold="Border_Hold"> <local:TileControl TileBackground="/Assets/Tiles/02.png"/> </Border> <Border Grid.Row="1" Hold="Border_Hold"> <local:TileControl TileBackground="/Assets/Tiles/03.png"/> </Border> <Border Grid.Row="1" Grid.Column="1" Hold="Border_Hold"> <local:TileControl TileBackground="/Assets/Tiles/04.png"/> </Border> <Border Grid.Row="2" Hold="Border_Hold"> <local:TileControl TileBackground="/Assets/Tiles/05.png"/> </Border> <Border Grid.Row="2" Grid.Column="1" Hold="Border_Hold"> <local:TileControl TileBackground="/Assets/Tiles/06.png"/> </Border> </Grid>
第四步:在 MainPage 页面的 CodeBehind 中,定义一个类型为 Dictionary<Point, Border> 的泛型字典 dic,
当页面加载完成时,初始化该字典:
public MainPage() { InitializeComponent(); this.Loaded += MainPage_Loaded; } void MainPage_Loaded(object sender, RoutedEventArgs e) { InitDic(); } // Size : 资源素距离父元素左上角的距离 Dictionary<Point, Border> dic = new Dictionary<Point, Border>(); int childWidth; // 初始化一个字典集合,Key:border 元素的中心点坐标,value:border 自己 void InitDic() { dic.Clear(); foreach (var item in ContentPanel.Children) { childWidth = (int)item.DesiredSize.Width; Border border = item as Border; int row = Grid.GetRow(border); int col = Grid.GetColumn(border); Point position = new Point(col * childWidth + childWidth / 2, row * childWidth + childWidth / 2); border.Tag = position; dic.Add(position, border); Debug.WriteLine("point- x:" + (col * childWidth + childWidth / 2) + " y:" + (row * childWidth + childWidth / 2)); } }
在 Border 的 Border_Hold 方法中,添加逻辑,用来处理各个 Tile 的视图状态,并且注册 ManipulationDelta 和 MouseLeftButtonUp 事件:
Border borderTemp; CompositeTransform transformTemp; private void Border_Hold(object sender, System.Windows.Input.GestureEventArgs e) { e.Handled = true; borderTemp = sender as Border; // 注册 tile 右上角“图钉”图片的单击事件 (borderTemp.Child as TileControl).Assets_thumb_png.Tap += Assets_thumb_png_Tap; transformTemp = new CompositeTransform(); transformTemp.TranslateX = x; transformTemp.TranslateY = y; borderTemp.RenderTransform = transformTemp; // 拖动 border 时,改变它的坐标 borderTemp.ManipulationDelta += borderTemp_ManipulationDelta; // 当手指离开 border 时,判断各个 tile 中心点的距离 borderTemp.MouseLeftButtonUp += borderTemp_MouseLeftButtonUp; if (borderTemp.Child != null) { foreach (var item in ContentPanel.Children) { Border border = item as Border; if (border.Child != null) { TileControl tile = border.Child as TileControl; // 被选中的 tile 进入 CheckedVisualState 视图状态,其余的进入 FloatVisualState 视图状态 if (tile == (borderTemp.Child as TileControl)) { tile.Checked(); border.IsHitTestVisible = true; } else { tile.Float(); // 当处于漂浮状态时,不再接收“单击”等屏幕事件 border.IsHitTestVisible = false; } } } } }
当手指离开选择的 Tile 时,判断各个 Tile 的中心点的距离,从而判断是否具备交换两个 Tile 的条件:
void borderTemp_MouseLeftButtonUp(object sender, System.Windows.Input.MouseButtonEventArgs e) { e.Handled = true; DateTime timeStart = DateTime.Now; Debug.WriteLine("Translation.X: " + transformTemp.TranslateX); Debug.WriteLine("Translation.Y: " + transformTemp.TranslateY); Point pointSource = (Point)borderTemp.Tag; Point point = new Point(transformTemp.TranslateX + pointSource.X, transformTemp.TranslateY + pointSource.Y); bool IsSwaped = false; // 当手指离开屏幕时,判断选中的 tile 的中心点和其它中心点的直线距离, // 如果距离小于 40px,则两个 tile 互换 //换 foreach (Point position in dic.Keys) { Border border2 = dic[position]; if (borderTemp != border2) { x = (int)(point.X - position.X); y = (int)(point.Y - position.Y); // 计算两个 Tile 中心点的直线距离 int distance = (int)Math.Sqrt(x * x + y * y); if (distance < 40) { // 交换两个 tile 的位置 SwapBorder(borderTemp, border2); IsSwaped = true; break; } } } Debug.WriteLine(DateTime.Now - timeStart); if (!IsSwaped) { transformTemp.TranslateX = 0; transformTemp.TranslateY = 0; } }
重要代码粘贴到上面了,具体代码可以下载工程。至此有关 FluidMoveBehavior 行为的三篇文章暂时写完了。
这个demo 运行的交互很简单,但是算法上还是颇费周折,想了几种实现方式,最终采用了上面的方式,重点时间
都花费在了数学计算上了。不过 demo 的代码还是比较粗糙,性能也没有优化,只是实现了大概的交互。
工程源码下载
相关文章推荐
- (2)FluidMoveBehavior 之单击 Grid 中 Tile 进行排序
- listBox 中的 Image 对象使用 FluidMoveSetTagBehavior
- (1)FluidMoveBehavior 之 ListBox 中详细内容项飞出来
- [转]【全面解禁!真正的Expression Blend实战开发技巧】第八章 FluidMoveBehavior完全解析之一漂浮移动
- FluidMoveBehavior
- listbox 添加元素时使用 FluidMoveBehavior
- 【全面解禁!真正的Expression Blend实战开发技巧】第十章 FluidMoveBehavior完全解析之三飞出ListBox吧
- windows phone FluidMoveBehavior的使用
- 模仿Smartphone的开始菜单效果
- AndEngine----CardinalSplineMoveModifierExample之模仿画<W>
- 与众不同 windows phone (10) - Push Notification(推送通知)之推送 Tile 通知, 推送自定义信息
- FloatingBehavior补遗:Location属性与move事件
- 模仿igoogle【定制化、拖动排序,最大化、分屏】
- 与众不同 windows phone (8) - Tile(磁贴)
- Windows Phone 实用开发技巧(27):创建透明Tile
- SQL排序 RANK/DENSE_RANK/ROW_NUMBER/NTILE
- 与众不同 windows phone (8) - Tile(磁贴)
- 开始菜单排序
- 使用ASP.NET Atlas SortBehavior实现客户端排序
- windows phone 8.1开发:磁铁|Tile更新