UWP: Use Behavior to achieve the dynamic Button click effect, uwpbutton
Let's talk about the effect first.
The reason why the circle is not made into Android is...
The following is the body:
First introduce the Behavior library in the project. We use Nuget.
Right-click Project> reference, Click Manage Nuget packages, and search for Microsoft. Xaml. Behaviors. Uwp. Managed.
Or in the package Management Console (if the tag does not exist on the right of the output, open it in tools> Nuget Package Manager> package management console) and enter the command
Install-Package Microsoft.Xaml.Behaviors.Uwp.Managed
Press enter, sit down, etc., introduced successfully.
Then, we create a new class named ButtonBehavior, which inherits the IBehavior interface and implements the Attach and Detach methods (you don't need to be silly, you can automatically complete it ).
The structure of the document is as follows:
Namespaces MyBehavior {public class Base: DependencyObject, IBehavior {public DependencyObject AssociatedObject {get; set;} public void Attach (DependencyObject associatedObject) {AssociatedObject = associatedObject; // write code here} public void Detach (){}}}
When Behavior is set for the control, the program will pass the control to our class through the Attach method, that is, associatedObject.
Then, of course, use Composition... I have nothing else.
First declare a bunch of objects for use:
double SizeValue;double ScaleValue;Compositor compositor;Visual hostVisual;ContainerVisual containerVisual;SpriteVisual rectVisual;ScalarKeyFrameAnimation PressSizeAnimation;ScalarKeyFrameAnimation PressOffsetAnimation;ScalarKeyFrameAnimation PressOpacityAnimation;CompositionAnimationGroup PressAnimationGroup;ScalarKeyFrameAnimation ReleaseSizeAnimation;ScalarKeyFrameAnimation ReleaseOffsetAnimation;ScalarKeyFrameAnimation ReleaseOpacityAnimation;CompositionAnimationGroup ReleaseAnimationGroup;
Then we should handle the cute AssociatedObject:
public virtual void Attach(DependencyObject associatedObject){ AssociatedObject = associatedObject; if (AssociatedObject is FrameworkElement element) { if (element.ActualWidth > 0 && element.ActualHeight > 0) Init(); else element.Loaded += Element_Loaded; hostVisual = ElementCompositionPreview.GetElementVisual(element); compositor = hostVisual.Compositor; element.AddHandler(UIElement.PointerPressedEvent, new PointerEventHandler(Element_PointerPressed), true); element.AddHandler(UIElement.PointerReleasedEvent, new PointerEventHandler(Element_PointerReleased), true); } else return;}
The Loaded event is hung here because if Behavior is set before the control is Loaded, the data we get in Attach will be incomplete.
Then there is the Init method, which is the core of the entire Behavior:
Void Init () {if (AssociatedObject is FrameworkElement) {hostVisual = ElementCompositionPreview. getElementVisual (element); // obtain the control Visual compositor = hostVisual. compositor; // get Compositor. Most Composition objects require it to create var temp = ElementCompositionPreview. getElementChildVisual (element); if (temp is ContainerVisual tempContainerVisual) containerVisual = tempContainerVisual; else {containerVisual = compositor. createContainerVisual (); // create ContainerVisual ElementCompositionPreview. setElementChildVisual (element, containerVisual); // set ContainerVisual to the sub-Visual of the control }}}
There is a small pitfall. In the ElementCompositionPreview class, only the SetElementChildVisual method is available, but there is no RemoveChildVisual method. Therefore, we can insert a sub-ContainerVisual to the button. ContainerVisual can be called a container to hold other Visual and can be removed. If this is not done, an error occurs when the Behavior is removed.
Then write an animation. The animation is divided into two parts: Press and release. My idea is that when you press the mouse, you can get the starting coordinate, move the special effect Visual to the starting abscissa, and then set the width of the special effect Visual from 0 to the same width as the control, at the same time, the special effect Visual from the starting position (0, 0) on the Right) slowly move to the left, so as to produce an outward diffusion effect.
If you have the idea, continue to write the Init method:
Void Init () {if (AssociatedObject is FrameworkElement) {hostVisual = ElementCompositionPreview. getElementVisual (element); // obtain the control Visual compositor = hostVisual. compositor; // get Compositor. Most Composition objects require it to create var temp = ElementCompositionPreview. getElementChildVisual (element); if (temp is ContainerVisual tempContainerVisual) containerVisual = tempContainerVisual; else {containerVisual = Compositor. createContainerVisual (); // create ContainerVisual ElementCompositionPreview. setElementChildVisual (element, containerVisual); // set ContainerVisual to the sub-Visual of the control} rectVisual = compositor. createSpriteVisual (); // create our main, special effect Visual var bindSizeAnimation = compositor. createExpressionAnimation ("hostVisual. size. Y "); bindSizeAnimation. setReferenceParameter ("hostVisual", hostVisual); rectVisual. startAni Mation ("Size. Y ", bindSizeAnimation); // create an Expression Animation and bind the height of the special effect Visual we created with the height of the control Visual to rectVisual. brush = compositor. createColorBrush (Windows. UI. colors. black); // set the paint rectVisual of the special effect Visual. opacity = 0f; // sets the initial transparency of the special effect Visual containerVisual. children. insertAtTop (rectVisual); insert the special effect Visual to the top of ContainerVisual var easeIn = compositor. createCubicBezierEasingFunction (new Vector2 (0.5f, 0.0f), new Vector2 (1.0f, 1. 0f); // The Bessert curve PressSizeAnimation = compositor used to create a key frame animation. createScalarKeyFrameAnimation (); PressSizeAnimation. insertKeyFrame (0f, 0f, easeIn); PressSizeAnimation. insertExpressionKeyFrame (1f, "hostVisual. size. X ", easeIn); PressSizeAnimation. setReferenceParameter ("hostVisual", hostVisual); PressSizeAnimation. duration = TimeSpan. fromSeconds (1); PressSizeAnimation. stopBehavior = AnimationStopBehavior. LeaveCurrentValue; // when the animation is paused halfway, set the current animation value to PressSizeAnimation on the object. target = "Size. X "; // After the animation is created and pressed, the animation of the Key Frame of the special effect Visual width lasts for 1 second. PressOffsetAnimation = compositor. createScalarKeyFrameAnimation (); PressOffsetAnimation. insertExpressionKeyFrame (0f, "This. currentValue ", easeIn); PressOffsetAnimation. insertKeyFrame (1f, 0f, easeIn); PressOffsetAnimation. duration = TimeSpan. fromSeconds (1); PressOffsetAnimation. stopBehavi Or = AnimationStopBehavior. leaveCurrentValue; PressOffsetAnimation. target = "Offset. X "; // After the animation is created and pressed, the animation of the key frame at the horizontal offset of the special effect Visual lasts for 1 second. PressOpacityAnimation = compositor. createScalarKeyFrameAnimation (); PressOpacityAnimation. insertKeyFrame (0f, 0.3f, easeIn); PressOpacityAnimation. insertKeyFrame (1f, 0.5f, easeIn); PressOpacityAnimation. duration = TimeSpan. fromSeconds (1); PressOpacityAnimation. stopBehavior = Anim AtionStopBehavior. leaveCurrentValue; PressOpacityAnimation. target = "Opacity"; // Key Frame Animation for the transparency of the special effect Visual after the press is created, lasting 1 second PressAnimationGroup = compositor. createAnimationGroup (); PressAnimationGroup. add (PressSizeAnimation); PressAnimationGroup. add (PressOffsetAnimation); PressAnimationGroup. add (PressOpacityAnimation); // create an animation group and put the three Animations together, similar to Storyboard ReleaseSizeAnimation = compositor. createScalarKeyFrameAni Mation (); ReleaseSizeAnimation. insertExpressionKeyFrame (0f, "This. currentValue ", easeIn); // This. currentValue is a special usage in Expression Animation. You can pass the current value of the set attribute to the animation ReleaseSizeAnimation. insertExpressionKeyFrame (1f, "hostVisual. size. X ", easeIn); ReleaseSizeAnimation. setReferenceParameter ("hostVisual", hostVisual); ReleaseSizeAnimation. duration = TimeSpan. fromSeconds (0.2); ReleaseSizeAnimation. stopBehavior = AnimationStop Behavior. LeaveCurrentValue; ReleaseSizeAnimation. Target = "Size. X"; // After the animation is created and released, the key frame animation of the special effect Visual width lasts for 0.2 seconds. ReleaseOffsetAnimation = compositor. createScalarKeyFrameAnimation (); ReleaseOffsetAnimation. insertExpressionKeyFrame (0f, "This. currentValue ", easeIn); ReleaseOffsetAnimation. insertKeyFrame (1f, 0f, easeIn); ReleaseOffsetAnimation. duration = TimeSpan. fromSeconds (0.2); ReleaseOffsetAnimation. stopBehavior = AnimationStopBehavior. leaveCurrentValue; ReleaseOffsetAnimation. target = "Offset. X "; // effect after the release is created The Key Frame Animation of Visual horizontal offset, lasting 0.2 seconds. ReleaseOpacityAnimation = compositor. createScalarKeyFrameAnimation (); ReleaseOpacityAnimation. insertExpressionKeyFrame (0f, "This. currentValue ", easeIn); ReleaseOpacityAnimation. insertKeyFrame (1f, 0f, easeIn); ReleaseOpacityAnimation. duration = TimeSpan. fromSeconds (0.2); ReleaseOpacityAnimation. delayTime = TimeSpan. fromSeconds (0.2); ReleaseOpacityAnimation. stopBehavior = AnimationStopBehavior. leave CurrentValue; ReleaseOpacityAnimation. Target = "Opacity"; // After the animation is created and released, the key frame animation of the effect Visual transparency lasts for 0.2 seconds. ReleaseAnimationGroup = compositor. CreateAnimationGroup (); ReleaseAnimationGroup. Add (animation); ReleaseAnimationGroup. Add (ReleaseOffsetAnimation); ReleaseAnimationGroup. Add (animation); // create an animation group }}
Everything is ready. I am in arrears. Do you still remember the PointerPressed and PointerReleased Methods attached to the control in the Attach method?
+ = And-= cannot be used here, because the Pointer event is very special (which cannot be remembered). The last parameter of AddHandler must be used, and the value of HandlerEventToo is true, can be processed correctly.
Private void Element_PointerPressed (object sender, PointerRoutedEventArgs e) {if (AssociatedObject is FrameworkElement element) {var point = e. getCurrentPoint (element ). position. toVector2 (); // obtain the rectVisual coordinate of the click relative to the control. stopAnimationGroup (PressAnimationGroup); rectVisual. stopAnimationGroup (ReleaseAnimationGroup); // stop the animation rectVisual being played. offset = new Vector3 (point. x, 0f, 0f); // set the starting abscissa of the special effect Visual to the abscissa of the click, and the ordinate to 0 rectVisual. startAnimationGroup (PressAnimationGroup); // start to press the animation} private void Element_PointerReleased (object sender, PointerRoutedEventArgs e) {rectVisual. stopAnimationGroup (PressAnimationGroup); rectVisual. stopAnimationGroup (ReleaseAnimationGroup); // stop the animation rectVisual being played. startAnimationGroup (ReleaseAnimationGroup); // The animation to be released}
Finally, write a Detach method to wipe your ass:
Public void Detach () {if (AssociatedObject is UIElement element) {element. removeHandler (UIElement. pointerPressedEvent, new PointerEventHandler (Element_PointerPressed); element. removeHandler (UIElement. pointerReleasedEvent, new PointerEventHandler (Element_PointerReleased);} // uninstall the event rectVisual. stopAnimationGroup (PressAnimationGroup); rectVisual. stopAnimationGroup (ReleaseAnimationGroup); // stop the containerVisual animation. children. remove (rectVisual); // Remove special effect Visual}
It's easy, isn't it?
The usage is also simple:
<Page ... xmlns:Interactivity="using:Microsoft.Xaml.Interactivity" xmlns:MyBehaviors="using:MyBehaviors" ... <Button> <Interactivity:Interaction.Behaviors> <MyBehaviors:ButtonBehavior /> </Interactivity:Interaction.Behaviors> </Button>
How many steps can an elephant shut down the refrigerator?
1. Set behavior to get the control object;
2. Operate the control object in behavior;
3. Remove behavior.
That's simple. Next, it's time to dig a hole (the pit returned by the last slide has not been filled ...):