張高興的 UWP 開發筆記:用 Thumb 控件仿制一個可拖動 Button


  在 WPF 上可用的控件拖動方法在 UWP 上大多沒用,那干脆用 Thumb 仿制一個吧。

  關於 Thumb 控件的教程也不多,畢竟在 WPF 控件拖動有很多種方法, Thumb 就顯得很雞肋了。下面我就簡單的說說。(MSDN 文檔

  不談什么屬性和方法,大多數都是繼承的。主要說說 Thumb 的原生事件 DragStartedDragDeltaDragCompleted

  DragStarted 和字面意思差不多,開始拖動的時候發生的。

  DragDelta 拖動進行中,只要你鼠標不放就會一直進行。

  DragCompleted 拖動結束后發生。

 

  下面就來仿制一個可以拖動的圓形 Button,像 IPhone 的“小圓點”一樣(像下圖一樣),只不過功能單一,僅僅用來打開 MainPage 里的漢堡菜單。本文仿制 Button 的時候只需要 DragDelta 事件。

  實現很簡單,我就不寫示例了。

  我有一個 SplitView “RootSplitView”,作為漢堡菜單的容器。

  首先需要在合適的頁面敲上一個 <Thumb />,給它個 Name="RootThumb",我是把它放在頁面右下角的。

<Thumb Name="RootThumb" Height="55" Width="55" HorizontalAlignment="Right" VerticalAlignment="Bottom" Canvas.ZIndex="101" />

  這時設計器右下角應該出現了一個方塊,但它不是我需要的圓形,下面打開 Blend 進行樣式定制(前面講 橫向ListView 時提過)。默認的 Thumb 樣式如下。

<Style x:Key="ThumbStyle1" TargetType="Thumb">
            <Setter Property="Background" Value="{ThemeResource ThumbBackground}"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="IsTabStop" Value="False"/>
            <Setter Property="BorderBrush" Value="{ThemeResource ThumbBorderBrush}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Thumb">
                        <Grid>
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundPointerOver"/>
                                            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Background"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundPressed"/>
                                            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Background"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Border x:Name="Background" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"/>
                            <Border x:Name="BackgroundPointerOver" BorderBrush="{ThemeResource ThumbBorderBrushPointerOver}" BorderThickness="{TemplateBinding BorderThickness}" Background="{ThemeResource ThumbBackgroundPointerOver}" Opacity="0"/>
                            <Border x:Name="BackgroundPressed" BorderBrush="{ThemeResource ThumbBorderBrushPressed}" BorderThickness="{TemplateBinding BorderThickness}" Background="{ThemeResource ThumbBackgroundPressed}" Opacity="0"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

  因為需要一個圓形並且里面有個漢堡菜單的圖標的仿制 Button,我們需要在默認樣式提過的 RootGrid 里畫個圓,順便來個 TextBlock 用來顯示漢堡菜單的圖標。定制好的樣式如下。

<Style x:Key="ThumbStyle1" TargetType="Thumb">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="1"/>
            <Setter Property="IsTabStop" Value="False"/>
            <Setter Property="BorderBrush" Value="{ThemeResource ThumbBorderBrush}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="Thumb">
                        <Grid x:Name="RootGrid">
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="CommonStates">
                                    <VisualState x:Name="Normal"/>
                                    <VisualState x:Name="PointerOver">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundPointerOver"/>
                                            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Background"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Pressed">
                                        <Storyboard>
                                            <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="BackgroundPressed"/>
                                            <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Background"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Disabled"/>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                            <Rectangle RadiusY="25" RadiusX="25" Fill="Gray" Opacity="0.6" Stroke="{ThemeResource SystemControlBackgroundAccentBrush}" StrokeThickness="3" />
                            <TextBlock FontFamily="Segoe MDL2 Assets" Text="&#xE700;" FontSize="22" Foreground="White" HorizontalAlignment="Center" VerticalAlignment="Center" />
                            <Border x:Name="Background" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"/>
                            <Border x:Name="BackgroundPointerOver" BorderBrush="{ThemeResource ThumbBorderBrushPointerOver}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Opacity="0"/>
                            <Border x:Name="BackgroundPressed" BorderBrush="{ThemeResource ThumbBorderBrushPressed}" BorderThickness="{TemplateBinding BorderThickness}" Background="Transparent" Opacity="0"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

  這時,設計器里應該出現了這個玩意兒(得意~~~)

  Button 的 Click 事件怎么實現呢?有 PointerPressed 和 Tapped 兩個備選事件。現在的交互事件有三種:Mouse Events(鼠標事件),Touch Events(觸摸事件)和 Pointer Events(指針事件),分別為不同的設備提供不同的交互方式。說這么多廢話其實直接試試就好了。。。在 Thumb 的 xml 標記里添加 Tapped="RootThumb_Tapped",事件代碼如下

private void MainThumb_Tapped(object sender, TappedRoutedEventArgs e)
{
  RootSplitView.IsPaneOpen = !RootSplitView.IsPaneOpen;
}

  下面說說拖動怎么實現,需要編寫 DragDelta 事件。由於 Win10 設備體系龐大,UWP 上談控件坐標沒啥意義,這也正是 WPF 上的控件拖動方案沒用的原因。如果你在設計器里像 WinForm 一樣拖拽控件設計布局的話,xaml 會給被拖拽的控件一個 Margin,因此 Thumb 的拖拽實現也用的 Margin。首先你需要定義兩個 double 私有字段記錄 X, Y 軸的位移量。設計目的是 Thumb 在右下角,而頁面的坐標零點在左上角,只需要將 Thumb 的 Margin 的 Right,Bottom 給一個位移量的負值即可。完整代碼如下。

private void MainThumb_DragDelta(object sender, DragDeltaEventArgs e)
{
  // 兩個 double 類型,用來記錄偏移量   thumbX
+= e.HorizontalChange;   thumbY += e.VerticalChange;   MainThumb.Margin = new Thickness(0, 0, -thumbX, -thumbY); }

  

  這樣,一個圓形的可拖動 Button 就用 Thumb 仿制完成了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM