Android的涟漪效应在WPF [英] Android's Ripple Effect in WPF

查看:223
本文介绍了Android的涟漪效应在WPF的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我爱,你倒好控制机器人新的动画(ListViewItem的,按钮等等等等),它做了整齐的动画是这样的:

I love Androids new animation where you touch a control (listviewitem, button etc etc) and it does a neat animation like this:

我不知道如何能在执行全球在WPF所有的'点击'控制好方法。

I'm wondering how this can be implemented in a nice way globally for all the 'clickable' controls in WPF.

我特别需要的是帮助怎么界要上的控制来创建。我想到的唯一的事情就是为对方控制自己创建用户控件(按钮,单选按钮等),在那里我有一个椭圆,以及原有的控制自己的父母。

What I specifically need help with is how the circles should be created on the control. The only thing I've thought of was to create own user-controls for each other control (buttons, radiobuttons, etc) where I have a parent for the ellipse as well as the original control itself.

<UserControl>
   <Grid MouseLeftButtonDown="handler">
      <Button/> <--- this would be the button which you normally would place
   </Grid >
</UserControl>



而在处理法然后创建上点一个椭圆 e.GetPosition(处理器)使用保证金性质,后来制作动画。该解决方案的的工作。但是,这将是一个麻烦,为每个控制我想上的连锁反应做到这一点。基本上是这样的:

And in the handler-method then create an ellipse on the point e.GetPosition(handler) using the margin-properties and later animate it. This solution would work. But it would be a hassle to do this for every control I would want the ripple effect on. Basically something like this:

void handler(object sender, MouseButtonEventArgs e)
{
   Grid parent = (Grid)sender;
   Ellipse ellipse = new Ellipse();
   ellipse.Height = 10; // would be animated
   ellipse.Width = 10; // would be animated

   Point p = e.GetPosition(parent);

   ellipse.Margin = new Thickness(p.X, p.Y, 0, 0);

   parent.Children.Add(ellipse);

   // do the animation parts to later remove the ellipse
}

有一个更清洁,更可扩展的方式放置在比,因为我刚才演示的方式与其它我的控制椭圆并不是所有的控件都支持生儿育女?

Is there a cleaner, more expandable way to place ellipses on my controls other than the way I earlier demonstrated since not all controls support having children?

推荐答案

更新:
这个问题真是太有趣了,我认为我实现了它。你可以找到它在我的Github上页: https://github.com/Domysee/WpfCustomControls 。有多个自定义的控件,您正在寻找的是RippleEffectDecorator之一。

UPDATE: This problem was so interesting to me that I implemented it. You can find it on my Github page: https://github.com/Domysee/WpfCustomControls. There are multiple custom controls, the one you are looking for is RippleEffectDecorator.

现在我解释我做了什么

我创建的自ContentControl,RippleEffectDecorator继承的自定义控制。它定义了一个额外的依赖属性HighlightBackground,它用于后台您单击的元素之后。

I created a custom control that inherits from ContentControl, RippleEffectDecorator. It defines an additional dependency property HighlightBackground, which is used for the background after you clicked the element.

RippleEffectDecorator的控件模板由一个网格,椭圆形和ContentPresenter的。

The ControlTemplate of RippleEffectDecorator consists of a Grid, an Ellipse and a ContentPresenter.

<ControlTemplate TargetType="{x:Type l:RippleEffectDecorator}">
    <Grid x:Name="PART_grid" ClipToBounds="True" Background="{TemplateBinding Background}"
            Width="{Binding ElementName=PART_contentpresenter, Path=ActualWidth}"
            Height="{Binding ElementName=PART_contentpresenter, Path=ActualHeight}">
        <Ellipse x:Name="PART_ellipse"
                        Fill="{Binding Path=HighlightBackground, RelativeSource={RelativeSource TemplatedParent}}" 
                        Width="0" Height="{Binding Path=Width, RelativeSource={RelativeSource Self}}" 
                        HorizontalAlignment="Left" VerticalAlignment="Top"/>

        <ContentPresenter x:Name="PART_contentpresenter" />
    </Grid>
</ControlTemplate>



我用了一个网格,而不是一个边界,这样我可以添加多个子元素(必要的,椭圆和ContentPresenter可以重叠)。该椭圆结合其高度属性自身的宽度,使得它始终是一个圆

I used a Grid instead of a Border so that I can add multiple child elements (necessary that Ellipse and ContentPresenter can overlap). The ellipse binds its Height property to its own width, so that it is always a circle.

现在的重要组成部分:动画

Now to the important part: the animation.

网格定义它的资源故事板,这是每一个MouseDown事件播放。

The Grid defines in its resources a Storyboard, which is played on every MouseDown event.

<Storyboard x:Key="PART_animation" Storyboard.TargetName="PART_ellipse">
    <DoubleAnimation Storyboard.TargetProperty="Width" From="0" />
    <ThicknessAnimation Storyboard.TargetProperty="Margin" />
    <DoubleAnimation BeginTime="0:0:1" Duration="0:0:0.25" Storyboard.TargetProperty="Opacity"
                From="1" To="0" />
    <DoubleAnimation Storyboard.TargetProperty="Width" To="0" BeginTime="0:0:1.25" Duration="0:0:0" />
    <DoubleAnimation BeginTime="0:0:1.25" Duration="0:0:0" Storyboard.TargetProperty="Opacity" To="1" />
</Storyboard>



,故事情节动画椭圆的width属性,使其完全填充的区域。它也有动画的保证金,因为相对于左上角点(不是围绕其中心)椭圆位置本身。

The storyboard animates the width property of the ellipse so that it fills the area completely. It also has to animate the Margin, because the ellipse positions itself relative to the upper left point (not around its center).

椭圆的开始位置,它的目标宽度和其在整个效果容器位置必须编程设置。
我覆盖OnApplyTemplate()方法将事件处理程序添加到鼠标按下事件,这将启动故事板,并将所有必要的值。

The start position of the ellipse, its target width and its position in the container throughout the effect has to be set programmatically. I overwrite the OnApplyTemplate() method to add an event handler to the mouse down event, which starts the storyboard and sets all necessary values.

public override void OnApplyTemplate()
{
    base.OnApplyTemplate();

    ellipse = GetTemplateChild("PART_ellipse") as Ellipse;
    grid = GetTemplateChild("PART_grid") as Grid;
    animation = grid.FindResource("PART_animation") as Storyboard;

    this.AddHandler(MouseDownEvent, new RoutedEventHandler((sender, e) =>
    {
        var targetWidth = Math.Max(ActualWidth, ActualHeight) * 2;
        var mousePosition = (e as MouseButtonEventArgs).GetPosition(this);
        var startMargin = new Thickness(mousePosition.X, mousePosition.Y, 0, 0);
        //set initial margin to mouse position
        ellipse.Margin = startMargin;
        //set the to value of the animation that animates the width to the target width
        (animation.Children[0] as DoubleAnimation).To = targetWidth;
        //set the to and from values of the animation that animates the distance relative to the container (grid)
        (animation.Children[1] as ThicknessAnimation).From = startMargin;
        (animation.Children[1] as ThicknessAnimation).To = new Thickness(mousePosition.X - targetWidth / 2, mousePosition.Y - targetWidth / 2, 0, 0);
        ellipse.BeginStoryboard(animation);
    }), true);
}

注意:的AddHandler的最后一个参数()决定你是否要接受处理的事件。这是该设置为true重要,因为有些UI元素处理鼠标事件(如按钮)。否则,MouseDownEvent不火,而不是执行,因此该动画。

Note: the last parameter of AddHandler() determines whether or not you want to receive handled events. It is important to set this to true, because some UiElements handle mouse events (e.g. Button). Otherwise the MouseDownEvent would not fire and therefore the animation not executed.

要使用它只需添加上你想有这种效果RippleEffectDecorator的子元素,和背景透明:

To use it simply add the element on which you want to have this effect as child of RippleEffectDecorator, and the Background to Transparent:

<cc:RippleEffectDecorator Background="Green" HighlightBackground="LightGreen">
    <Button FontSize="60" Background="Transparent">stuff</Button>
</cc:RippleEffectDecorator>



注2:的一些元素包括在模板上的鼠标悬停触发器(如钮),因此隐藏效果。如果你不想,你必须设置按钮的模板,并删除这些触发器。最简单的方法是使用混合,得到它的按钮模板,删除所有触发器并将其添加为你的按钮模板。

Note2: some elements include triggers which set the template on MouseOver (e.g. Button) and therefore hide the effect. If you dont want that you have to set the template of the button and remove these triggers. The easiest way is to use Blend, get the template of the button from it, remove all triggers and add it as template of your button.

这篇关于Android的涟漪效应在WPF的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆