前言
看到过其他平台游戏中第三方sdk的一些悬浮的小助手,近来无聊,就做个玩儿,看着比较简单,做起来还是花费了不少力气。
开始
首先是页面的xaml代码,其实比较简单,就是一些Canvas里面装了些image和一个border(是作为按钮展开后的背景)。下面注释的那个canvas是为了看到悬浮窗在界面右边的时的效果,方便做动画添加的,读者不用在意
要求悬浮按钮可以拖动,拖动后靠在自动屏幕边上显示,拖动的时候超过屏幕的中轴就靠在右边,点击按钮向左边以此展开按钮,如果拖动后在屏幕中轴左边则靠左侧边上,点击屏幕向右依次展开,再次点击收回按钮。(展开按钮的时候我有添加了个选择动画,旋转了360度,)考虑到动画需要变化,以前悬浮窗的中的按钮位置也要根据拖放的位置动态变化,所以动画和布局都用代码控制。
<phone:PhoneApplicationPage.Resources>
<Style x:Key="imageS" TargetType="Image">
<Setter Property="Width" Value="50"/>
<Setter Property="Height" Value="50"/>
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
</Style>
<!--<Storyboard x:Name="Storyboard1">
<DoubleAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.RenderTransform).(CompositeTransform.ScaleX)" Storyboard.TargetName="border">
<EasingDoubleKeyFrame KeyTime="0" Value="0.04"/>
<EasingDoubleKeyFrame KeyTime="0:0:0.4" Value="1.003"/>
</DoubleAnimationUsingKeyFrames>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="border">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
<DiscreteObjectKeyFrame KeyTime="0:0:0.4">
<DiscreteObjectKeyFrame.Value>
<Visibility>Visible</Visibility>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>-->
</phone:PhoneApplicationPage.Resources>
<!--LayoutRoot 是包含所有页面内容的根网格-->
<Grid>
<Grid.Background>
<ImageBrush Stretch="Fill" ImageSource="/Assets/Image/bg1.jpg"/>
</Grid.Background>
<Canvas x:Name="HoverContentner" HorizontalAlignment="Left" Height="50" Margin="0,0,0,0" VerticalAlignment="Top" Width="300" >
<Border Visibility="Collapsed" x:Name="border" Width="300" Height="47" HorizontalAlignment="Left" VerticalAlignment="Top" CornerRadius="12" Background="#B2D1DAC7" RenderTransformOrigin="0.0,0.0">
<Border.RenderTransform>
<CompositeTransform/>
</Border.RenderTransform>
</Border>
<Image x:Name="image0" Style="{StaticResource imageS}" Source="/Assets/Image/button1.png" Tap="image0_Tap" ManipulationDelta="image0_ManipulationDelta" ManipulationCompleted="image0_ManipulationCompleted" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Collapsed" x:Name="image1" Style="{StaticResource imageS}" Canvas.Left="60" Source="/Assets/Image/button2.png" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Collapsed" x:Name="image2" Style="{StaticResource imageS}" Canvas.Left="120" Source="/Assets/Image/button3.png">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Collapsed" x:Name="image3" Style="{StaticResource imageS}" Canvas.Left="180" Source="/Assets/Image/button4.png">
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Collapsed" x:Name="image4" Style="{StaticResource imageS}" Canvas.Left="240" Source="/Assets/Image/button5.png" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
</Canvas>
<!--<Canvas x:Name="HoverContentnerRight" HorizontalAlignment="Left" Height="50" Margin="180,300,0,0" VerticalAlignment="Top" Width="300">
<Image Visibility="Visible" Style="{StaticResource imageS}" Canvas.Left="180" Source="/Assets/Image/button2.png" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Visible" Style="{StaticResource imageS}" Canvas.Left="120" Source="/Assets/Image/button3.png" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Visible" Style="{StaticResource imageS}" Canvas.Left="60" Source="/Assets/Image/button4.png" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image Visibility="Visible" Style="{StaticResource imageS}" Canvas.Left="0" Source="/Assets/Image/button5.png" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
<Image x:Name="image0left" Style="{StaticResource imageS}" Canvas.Left="240" Source="/Assets/Image/button1.png" Tap="image0_Tap" ManipulationDelta="image0_ManipulationDelta" ManipulationCompleted="image0_ManipulationCompleted" >
<Image.RenderTransform>
<CompositeTransform/>
</Image.RenderTransform>
</Image>
</Canvas>-->
</Grid>
</phone:PhoneApplicationPage>
一些定义的变量
private int trasnlateLength = 60;
private bool left = true;
private bool lastleft = true;//lastleft上次
private Storyboard expandstory = null;
private Storyboard hidestory = null;
private bool isStoryBegin = true;
首先是处理拖动的代码
private void image0_ManipulationDelta(object sender, System.Windows.Input.ManipulationDeltaEventArgs e)
{
if (image1.Visibility == Visibility.Visible)
{
}
else
{
double oldleft = HoverContentner.Margin.Left;
double oldtop = HoverContentner.Margin.Top;
//if (!left && e.DeltaManipulation.Translation.X<0)
//{
// oldleft += -e.DeltaManipulation.Translation.X;
//}
//else
//{
// oldleft += e.DeltaManipulation.Translation.X;
//}
oldleft += e.DeltaManipulation.Translation.X;
oldtop += e.DeltaManipulation.Translation.Y;
// Debug.WriteLine("左边距"+oldleft + "............... 右边距"+ oldtop);
HoverContentner.Margin = new Thickness(oldleft, oldtop, 0, 0);
this.UpdateLayout();
}
}
拖动完成后根据位置靠边显示
private void image0_ManipulationCompleted(object sender, System.Windows.Input.ManipulationCompletedEventArgs e)
{
if (e.TotalManipulation.Translation.X==0.0f&&e.TotalManipulation.Translation.Y==0.0f)
{
return;
}
// Debug.WriteLine(" HoverContentner.Margin.left: " + HoverContentner.Margin.Left);
if (left &&HoverContentner.Margin.Left < 220)
{
HoverContentner.Margin = new Thickness(0, HoverContentner.Margin.Top, 0, 0);
updateCanvas(true);
}
else if (left &&HoverContentner.Margin.Left > 220)
{
HoverContentner.Margin = new Thickness(185, HoverContentner.Margin.Top, 0, 0);
updateCanvas(false);
}
else if (!left&&HoverContentner.Margin.Left > 0)
{
HoverContentner.Margin = new Thickness(185, HoverContentner.Margin.Top, 0, 0);
updateCanvas(false);
}
else
{
HoverContentner.Margin = new Thickness(0, HoverContentner.Margin.Top, 0, 0);
updateCanvas(true);
}
}
然后更新布局
private void updateCanvas( bool isleft)
{
left = isleft;
if (isleft)
{
// trasnlateLength = 60;
Canvas.SetLeft(image0, 0);
Canvas.SetLeft(image1, 60);
Canvas.SetLeft(image2, 120);
Canvas.SetLeft(image3, 185);
Canvas.SetLeft(image4, 240);
border.HorizontalAlignment = HorizontalAlignment.Left;
border.RenderTransformOrigin = new Point(0, 0);
}
else
{
// trasnlateLength = -60;
Canvas.SetLeft(image0, 240);
Canvas.SetLeft(image1, 185);
Canvas.SetLeft(image2, 120);
Canvas.SetLeft(image3, 60);
Canvas.SetLeft(image4, 0);
border.HorizontalAlignment = HorizontalAlignment.Right;
border.RenderTransformOrigin = new Point(1, 1);
HoverContentner.Width = 300;
//image1.Visibility = Visibility.Visible;
//image2.Visibility = Visibility.Visible;
//image3.Visibility = Visibility.Visible;
//image4.Visibility = Visibility.Visible;
UpdateLayout();
}
}
点击图片时开始执行动画,一个展开的和一个收回的动画,如果上次悬浮窗的位置和这次的位置不同(上次在左边,这次在右边,则更新动画)
private void image0_Tap(object sender, System.Windows.Input.GestureEventArgs e)
{
if (lastleft != left)//如果方向改变则刷新动画
{
expandstory = CreateExpand();
hidestory = HideExpand();
}
if (isStoryBegin)
{
expandstory.Begin();
isStoryBegin = false;
}
else
{
hidestory.Begin();
isStoryBegin = true;
}
}
展开的动画
private Storyboard CreateExpand()
{
Storyboard expand = new Storyboard();
#region 旋转动画
for (int i = 0; i < 5; i++)
{
//旋转动画
DoubleAnimationUsingKeyFrames rotation = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(rotation, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.Rotation)"));
//只有动画在xaml中才可以使用这个方法
// Storyboard.SetTargetName(rotation, "image" + i);
Storyboard.SetTarget(rotation, this.FindName("image" + i) as Image);
EasingDoubleKeyFrame startAngle = new EasingDoubleKeyFrame();
startAngle.Value = -360;
startAngle.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0));
rotation.KeyFrames.Add(startAngle);
if (i == 2)
{
rotation.BeginTime = TimeSpan.FromMilliseconds(50);
}
else if (i == 3)
{
rotation.BeginTime = TimeSpan.FromMilliseconds(100);
}
else if (i == 4)
{
rotation.BeginTime = TimeSpan.FromMilliseconds(150);
}
EasingDoubleKeyFrame endAngle = new EasingDoubleKeyFrame();
endAngle.Value = 0;
endAngle.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
rotation.KeyFrames.Add(endAngle);
expand.Children.Add(rotation);
}
#endregion
for (int i = 1; i < 5; i++)
{
#region 平移动画
//X轴平移
DoubleAnimationUsingKeyFrames xtranslate = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(xtranslate, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.TranslateX)"));
Storyboard.SetTarget(xtranslate, this.FindName("image" + i) as Image);
//起始点
EasingDoubleKeyFrame xstartPoint = new EasingDoubleKeyFrame();
xstartPoint.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0));
if (i == 1)
{
xstartPoint.Value = left ? -trasnlateLength : trasnlateLength;
}
else if (i == 2)
{
xtranslate.BeginTime = TimeSpan.FromMilliseconds(50);
xstartPoint.Value = left ? -trasnlateLength * 2 : trasnlateLength * 2;
}
else if (i == 3)
{
xtranslate.BeginTime = TimeSpan.FromMilliseconds(100);
xstartPoint.Value = left ? -trasnlateLength * 3 : trasnlateLength * 3;
}
else if (i == 4)
{
xtranslate.BeginTime = TimeSpan.FromMilliseconds(150);
xstartPoint.Value = left ? -trasnlateLength * 4 : trasnlateLength * 4; ;
}
lastleft = left;
xstartPoint.EasingFunction = new PowerEase() { EasingMode = 0 };
//终点
EasingDoubleKeyFrame xendPoint = new EasingDoubleKeyFrame();
xendPoint.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
xendPoint.Value = 0;
xendPoint.EasingFunction = new PowerEase() { EasingMode = 0 };
xtranslate.KeyFrames.Add(xstartPoint);
xtranslate.KeyFrames.Add(xendPoint);
expand.Children.Add(xtranslate);
#endregion
#region 改变属性值的动画
//改变属性值的动画
ObjectAnimationUsingKeyFrames visi = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(visi, new PropertyPath("(UIElement.Visibility)"));
Storyboard.SetTarget(visi, this.FindName("image" + i) as Image);
DiscreteObjectKeyFrame startObj = new DiscreteObjectKeyFrame();
startObj.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0));
startObj.Value = Visibility.Visible;
DiscreteObjectKeyFrame endObj = new DiscreteObjectKeyFrame();
endObj.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
endObj.Value = Visibility.Visible;
if (i == 2)
{
visi.BeginTime = TimeSpan.FromMilliseconds(50);
}
else if (i == 3)
{
visi.BeginTime = TimeSpan.FromMilliseconds(100);
}
else if (i == 4)
{
visi.BeginTime = TimeSpan.FromMilliseconds(150);
}
visi.KeyFrames.Add(startObj);
visi.KeyFrames.Add(endObj);
expand.Children.Add(visi);
#endregion
}
#region 缩放动画
//X轴平移
DoubleAnimationUsingKeyFrames xtranslateb = new DoubleAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(xtranslateb, new PropertyPath("(UIElement.RenderTransform).(CompositeTransform.ScaleX)"));
Storyboard.SetTarget(xtranslateb, this.FindName("border" ) as Border);
//起始点
EasingDoubleKeyFrame xstartPointb = new EasingDoubleKeyFrame();
xstartPointb.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0));
xstartPointb.Value = 0.04f;
xstartPointb.EasingFunction = new PowerEase() { EasingMode = 0 };
//终点
EasingDoubleKeyFrame xendPointb = new EasingDoubleKeyFrame();
xendPointb.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
xendPointb.Value = 1;
xendPointb.EasingFunction = new PowerEase() { EasingMode = 0 };
xtranslateb.KeyFrames.Add(xstartPointb);
xtranslateb.KeyFrames.Add(xendPointb);
expand.Children.Add(xtranslateb);
#endregion
#region 改变border属性值的动画
//改变属性值的动画
ObjectAnimationUsingKeyFrames visib = new ObjectAnimationUsingKeyFrames();
Storyboard.SetTargetProperty(visib, new PropertyPath("(UIElement.Visibility)"));
Storyboard.SetTarget(visib, this.FindName("border") as Border);
DiscreteObjectKeyFrame startObjb = new DiscreteObjectKeyFrame();
startObjb.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0));
startObjb.Value = Visibility.Visible;
DiscreteObjectKeyFrame endObjb = new DiscreteObjectKeyFrame();
endObjb.KeyTime = KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(300));
endObjb.Value = Visibility.Visible;
visib.KeyFrames.Add(startObjb);
visib.KeyFrames.Add(endObjb);
expand.Children.Add(visib);
#endregion
return expand;
}
还有个收缩的动画就不给大家贴出来了,留给大家一个自己动手的过程。哇咔咔,下面贴张动态图,吸引下诸位眼球。