廢話不多說(shuō),先上效果

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

沒(méi)有做成安卓那種圓形的原因是...人家真的不會(huì)嘛...

好了下面是正文:

首先在工程中引入Behavior的庫(kù),我們使用Nuget。

在項(xiàng)目->引用上點(diǎn)擊右鍵,點(diǎn)擊管理Nuget程序包,然后瀏覽里搜索Microsoft.Xaml.Behaviors.Uwp.Managed

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

或者在程序包管理控制臺(tái)里(如果輸出右邊沒(méi)有這個(gè)標(biāo)簽,使用工具->Nuget包管理器->程序包管理控制臺(tái)打開(kāi)),輸入命令

Install-Package Microsoft.Xaml.Behaviors.Uwp.Managed

回車(chē),坐等,引入成功。

然后我們新建一個(gè)類(lèi),名字叫ButtonBehavior,繼承IBehavior接口,并且實(shí)現(xiàn)Attach和Detach方法(不用傻傻的敲,自動(dòng)補(bǔ)全就可以)。

這時(shí)文檔的結(jié)構(gòu)是這樣的:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

namespace MyBehavior
{    public class Base : DependencyObject, IBehavior
    {        public DependencyObject AssociatedObject { get; set; }        public void Attach(DependencyObject associatedObject)
        {
            AssociatedObject  = associatedObject;            //這里寫(xiě)代碼        }        public void Detach()
        {

        }
    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

給控件設(shè)置Behavior時(shí),程序會(huì)通過(guò)Attach方法,將控件傳到我們的類(lèi)里,也就是associatedObject。

接著,當(dāng)然是使用Composition了。。。我又不會(huì)別的。

先聲明一堆準(zhǔn)備用的對(duì)象:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

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;

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

然后該處理一下可愛(ài)的AssociatedObject了:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

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;
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

這里掛上Loaded事件是因?yàn)椋绻丶](méi)有加載完成之前設(shè)置了Behavior,我們?cè)贏ttach里獲取到的數(shù)據(jù)就不全了。

然后是Init方法,這是整個(gè)Behavior的核心:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

void Init()
{    if (AssociatedObject is FrameworkElement element)
    {
        hostVisual = ElementCompositionPreview.GetElementVisual(element); //獲取控件Visual
        compositor = hostVisual.Compositor;  //獲取Compositor,Composition的大多數(shù)對(duì)象都需要他來(lái)創(chuàng)建

        var temp = ElementCompositionPreview.GetElementChildVisual(element);        if (temp is ContainerVisual tempContainerVisual) containerVisual = tempContainerVisual;        else
        {
            containerVisual = compositor.CreateContainerVisual();  //創(chuàng)建ContainerVisual
            ElementCompositionPreview.SetElementChildVisual(element, containerVisual);  //把ContainerVisual設(shè)置成控件的子Visual        }

    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

這里有個(gè)小坑,ElementCompositionPreview類(lèi)里,只有SetElementChildVisual方法,卻并沒(méi)有RemoveChildVisual的方法。所以我們給按鈕插入一個(gè)子ContainerVisual,ContainerVisual可以所謂容器盛放其他Visual,并且,可以移除。如果不這么做,移除Behavior的時(shí)候會(huì)爆錯(cuò)。

然后寫(xiě)動(dòng)畫(huà),動(dòng)畫(huà)分為兩部分,分別是按下和釋放。我的思路是這樣,鼠標(biāo)按下時(shí),獲取到起始坐標(biāo),把讓特效Visual移動(dòng)到起始橫坐標(biāo)的位置,然后讓特效Visual的寬度從0到和控件寬度一樣大,與此同時(shí),特效Visual從起始位置((0,0)的右邊)慢慢向左移動(dòng),這樣就能制作出一個(gè)向外擴(kuò)散的效果。

思路有了,繼續(xù)寫(xiě)Init方法:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

void Init()
{    if (AssociatedObject is FrameworkElement element)
    {
        hostVisual = ElementCompositionPreview.GetElementVisual(element); //獲取控件Visual
        compositor = hostVisual.Compositor;  //獲取Compositor,Composition的大多數(shù)對(duì)象都需要他來(lái)創(chuàng)建

        var temp = ElementCompositionPreview.GetElementChildVisual(element);        if (temp is ContainerVisual tempContainerVisual) containerVisual = tempContainerVisual;        else
        {
            containerVisual = compositor.CreateContainerVisual();  //創(chuàng)建ContainerVisual
            ElementCompositionPreview.SetElementChildVisual(element, containerVisual);  //把ContainerVisual設(shè)置成控件的子Visual        }

        rectVisual = compositor.CreateSpriteVisual();  //創(chuàng)建我們的正主,特效Visual

        var bindSizeAnimation = compositor.CreateExpressionAnimation("hostVisual.Size.Y");
        bindSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);
        rectVisual.StartAnimation("Size.Y", bindSizeAnimation);        //創(chuàng)建一個(gè)表達(dá)式動(dòng)畫(huà),把我們自己創(chuàng)建的特效Visual的高度和控件Visual的高度綁定到一起
        rectVisual.Brush = compositor.CreateColorBrush(Windows.UI.Colors.Black);  //設(shè)置特效Visual的筆刷
        rectVisual.Opacity = 0f;  //設(shè)置特效Visual的初始透明度
        containerVisual.Children.InsertAtTop(rectVisual);  把特效Visual插入到ContainerVisual的頂部        var easeIn = compositor.CreateCubicBezierEasingFunction(new Vector2(0.5f, 0.0f), new Vector2(1.0f, 1.0f));        //創(chuàng)建一個(gè)關(guān)鍵幀動(dòng)畫(huà)用到的貝塞爾曲線
        PressSizeAnimation = compositor.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;  //動(dòng)畫(huà)中途暫停時(shí),將動(dòng)畫(huà)的當(dāng)前值設(shè)定到對(duì)象上
        PressSizeAnimation.Target = "Size.X";        //創(chuàng)建按下后,特效Visual的寬度的關(guān)鍵幀動(dòng)畫(huà),持續(xù)1秒
        PressOffsetAnimation = compositor.CreateScalarKeyFrameAnimation();
        PressOffsetAnimation.InsertExpressionKeyFrame(0f, "This.CurrentValue", easeIn);
        PressOffsetAnimation.InsertKeyFrame(1f, 0f, easeIn);
        PressOffsetAnimation.Duration = TimeSpan.FromSeconds(1);
        PressOffsetAnimation.StopBehavior = AnimationStopBehavior.LeaveCurrentValue;
        PressOffsetAnimation.Target = "Offset.X";        //創(chuàng)建按下后,特效Visual的橫向偏移的關(guān)鍵幀動(dòng)畫(huà),持續(xù)1秒
        PressOpacityAnimation = compositor.CreateScalarKeyFrameAnimation();
        PressOpacityAnimation.InsertKeyFrame(0f, 0.3f, easeIn);
        PressOpacityAnimation.InsertKeyFrame(1f, 0.5f, easeIn);
        PressOpacityAnimation.Duration = TimeSpan.FromSeconds(1);
        PressOpacityAnimation.StopBehavior = AnimationStopBehavior.LeaveCurrentValue;
        PressOpacityAnimation.Target = "Opacity";        //創(chuàng)建按下后,特效Visual的透明度的關(guān)鍵幀動(dòng)畫(huà),持續(xù)1秒

        PressAnimationGroup = compositor.CreateAnimationGroup();
        PressAnimationGroup.Add(PressSizeAnimation);
        PressAnimationGroup.Add(PressOffsetAnimation);
        PressAnimationGroup.Add(PressOpacityAnimation);        //創(chuàng)建一個(gè)動(dòng)畫(huà)組,把上面三個(gè)動(dòng)畫(huà)放在一起,類(lèi)似Storyboard

        ReleaseSizeAnimation = compositor.CreateScalarKeyFrameAnimation();
        ReleaseSizeAnimation.InsertExpressionKeyFrame(0f, "This.CurrentValue", easeIn);        //This.CurrentValue是表達(dá)式動(dòng)畫(huà)中的一個(gè)特殊用法,可以將設(shè)置的屬性的當(dāng)前值傳遞給動(dòng)畫(huà)
        ReleaseSizeAnimation.InsertExpressionKeyFrame(1f, "hostVisual.Size.X", easeIn);
        ReleaseSizeAnimation.SetReferenceParameter("hostVisual", hostVisual);
        ReleaseSizeAnimation.Duration = TimeSpan.FromSeconds(0.2);
        ReleaseSizeAnimation.StopBehavior = AnimationStopBehavior.LeaveCurrentValue;
        ReleaseSizeAnimation.Target = "Size.X";        //創(chuàng)建釋放后,特效Visual的寬度的關(guān)鍵幀動(dòng)畫(huà),持續(xù)0.2秒。
        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";        //創(chuàng)建釋放后,特效Visual的橫向偏移的關(guān)鍵幀動(dòng)畫(huà),持續(xù)0.2秒。
        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.LeaveCurrentValue;
        ReleaseOpacityAnimation.Target = "Opacity";        //創(chuàng)建釋放后,特效Visual的透明度的關(guān)鍵幀動(dòng)畫(huà),持續(xù)0.2秒。
        ReleaseAnimationGroup = compositor.CreateAnimationGroup();
        ReleaseAnimationGroup.Add(ReleaseSizeAnimation);
        ReleaseAnimationGroup.Add(ReleaseOffsetAnimation);
        ReleaseAnimationGroup.Add(ReleaseOpacityAnimation);        //創(chuàng)建動(dòng)畫(huà)組    }
}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

萬(wàn)事俱備,只欠東風(fēng),還記得Attach方法里給控件掛上的PointerPressed和PointerReleased方法不?

這里不能用+=和-=,因?yàn)镻ointer的事件很特殊(怎么個(gè)說(shuō)法記不清了),必須要用到AddHandler的最后一個(gè)參數(shù),HandlerEventToo為true,才能正確的處理。

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

private void Element_PointerPressed(object sender, PointerRoutedEventArgs e)
{    if (AssociatedObject is FrameworkElement element)
    {        var point = e.GetCurrentPoint(element).Position.ToVector2();  //獲取點(diǎn)擊相對(duì)于控件的坐標(biāo)
        rectVisual.StopAnimationGroup(PressAnimationGroup);
        rectVisual.StopAnimationGroup(ReleaseAnimationGroup);        //停止正在播放的動(dòng)畫(huà)
        rectVisual.Offset = new Vector3(point.X, 0f, 0f);  //設(shè)置特效Visual的起始橫坐標(biāo)為點(diǎn)擊的橫坐標(biāo),縱坐標(biāo)為0
        rectVisual.StartAnimationGroup(PressAnimationGroup);  //開(kāi)始按下的動(dòng)畫(huà)    }

}private void Element_PointerReleased(object sender, PointerRoutedEventArgs e)
{
    rectVisual.StopAnimationGroup(PressAnimationGroup);
    rectVisual.StopAnimationGroup(ReleaseAnimationGroup);    //停止正在播放的動(dòng)畫(huà)
    rectVisual.StartAnimationGroup(ReleaseAnimationGroup);  //開(kāi)始釋放的動(dòng)畫(huà)}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

最后再寫(xiě)一個(gè)Detach方法擦屁股就大功告成了:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

public void Detach()
{    if (AssociatedObject is UIElement element)
    {
        element.RemoveHandler(UIElement.PointerPressedEvent, new PointerEventHandler(Element_PointerPressed));
        element.RemoveHandler(UIElement.PointerReleasedEvent, new PointerEventHandler(Element_PointerReleased));
    }    //卸載事件
    rectVisual.StopAnimationGroup(PressAnimationGroup);
    rectVisual.StopAnimationGroup(ReleaseAnimationGroup);    //停止動(dòng)畫(huà)
    containerVisual.Children.Remove(rectVisual);    //移除特效Visual}

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

很輕松,不是嗎?

使用方法也很簡(jiǎn)單:

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

<Page    ...    
    xmlns:Interactivity="using:Microsoft.Xaml.Interactivity"
    xmlns:MyBehaviors="using:MyBehaviors"

    ...

    <Button>
        <Interactivity:Interaction.Behaviors>
            <MyBehaviors:ButtonBehavior />
        </Interactivity:Interaction.Behaviors>
    </Button>

大學(xué)生就業(yè)培訓(xùn),高中生培訓(xùn),在職人員轉(zhuǎn)行培訓(xùn),企業(yè)團(tuán)訓(xùn)

 

把大象關(guān)冰箱,統(tǒng)共分幾步?

1、設(shè)置behavior,獲取到控件對(duì)象;

2、在behavior中操作控件對(duì)象;

3、移除behavior。

就這么簡(jiǎn)單。接下來(lái)又到了挖坑時(shí)間(話說(shuō)上次滑動(dòng)返回的坑還沒(méi)填...):


http://www.cnblogs.com/blue-fire/p/7237158.html