You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UWP项目中选择指示器动画偏移至目标按钮下方的问题

问题分析与解决方案

问题原因

  1. 坐标参考系不匹配:SelectionIndicator与按钮所在的Buttons StackPanel不在同一父容器下,使用clickedButton.TransformToVisual(Buttons)计算的是按钮相对于Buttons的Y坐标,但SelectionIndicator的位置参考系是外层Grid,两者坐标空间不一致,导致动画偏移。
  2. 未处理垂直居中:当前仅计算按钮顶部位置,未让SelectionIndicator垂直居中于按钮,不符合Windows设置的交互样式。

解决方案

步骤1:调整XAML结构(推荐)

将SelectionIndicator移至按钮所在的Buttons StackPanel内,确保两者坐标参考系统一:

<Page
    x:Class="Library.Views.MainMenuView"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:Library.Helpers"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationBackgroundBrush}">

    <Grid>
        <Border HorizontalAlignment="Left" MaxWidth="400" MinWidth="200" Width="Auto" Height="Auto" Background="{ThemeResource ControlBackgroundBrush}" BorderBrush="{ThemeResource ControlHoveredBorderBrush}" BorderThickness="1" CornerRadius="0,8,8,0" >
            <StackPanel x:Name="Buttons">
                <!-- 将SelectionIndicator移至此处,与按钮同层级 -->
                <Border x:Name="SelectionIndicator" Visibility="Collapsed" Background="{ThemeResource SystemAccentColor}" Height="30" Width="5" CornerRadius="3" HorizontalAlignment="Left" Margin="5,0,0,0" VerticalAlignment="Top"/>
                
                <Button x:Name="Home" Style="{StaticResource UIButtonStyle}" Width="300" Height="40" FontSize="20" HorizontalAlignment="Center" Margin="5,8,12,8" Click="Button_Click">
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                        <Image Source="/Assets/HomeNoBGRes.png" Width="35" Height="30" Margin ="0,0,10,0" Stretch="Fill"/>
                        <TextBlock Text="Home" FontSize="20" Width="240"/>
                    </StackPanel>
                </Button>
                <Button x:Name="Projects" Style="{StaticResource UIButtonStyle}" Width="300" Height="40" FontSize="20" HorizontalAlignment="Center" Margin="5,8,12,8" Click="Button_Click">
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                        <Image Source="/Assets/ProjectsNoBGRes.png" Width="30" Height="30" Margin ="0,0,10,0" Stretch="Fill"/>
                        <TextBlock Text="My Projects" FontSize="20" Width="240"/>
                    </StackPanel>
                </Button>
                <Border Background="{ThemeResource ControlHoveredBackgroundBrush}" Width="270" Height="5" CornerRadius="3" HorizontalAlignment="Center"/>
                <Button x:Name="Documents" Style="{StaticResource UIButtonStyle}" Width="300" Height="40" FontSize="20" HorizontalAlignment="Center" Margin="5,8,12,8" Click="Button_Click">
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                        <Image Source="/Assets/DocsNoBGRes.png" Width="30" Height="30" Margin ="0,0,10,0" Stretch="Fill"/>
                        <TextBlock Text="Documents" FontSize="20" Width="240"/>
                    </StackPanel>
                </Button>
                <Button x:Name="Paper" Style="{StaticResource UIButtonStyle}" Width="300" Height="40" FontSize="20" HorizontalAlignment="Center" Margin="5,8,12,8" Click="Button_Click">
                    <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
                        <Image Source="/Assets/PaperNoBGRes.png" Width="30" Height="30" Margin ="0,0,10,0" Stretch="Fill"/>
                        <TextBlock Text="Paper" FontSize="20" Width="240"/>
                    </StackPanel>
                </Button>
            </StackPanel>
        </Border>
    </Grid>
</Page>

步骤2:修改C#动画代码

调整坐标计算逻辑,实现指示器垂直居中于按钮:

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (SelectionIndicator.Visibility == Visibility.Collapsed) 
        SelectionIndicator.Visibility = Visibility.Visible;

    if (sender is Button clickedButton) 
    { 
        // 获取按钮相对于Buttons容器的顶部Y坐标
        Point buttonTopPos = clickedButton.TransformToVisual(Buttons).TransformPoint(new Point(0, 0));
        // 计算指示器需要的Y偏移:按钮顶部 + (按钮高度 - 指示器高度)/2,实现垂直居中
        double targetTranslateY = buttonTopPos.Y + (clickedButton.ActualHeight - SelectionIndicator.ActualHeight) / 2;

        if (SelectionIndicator.RenderTransform is null || !(SelectionIndicator.RenderTransform is CompositeTransform)) 
            SelectionIndicator.RenderTransform = new CompositeTransform();

        CompositeTransform transform = SelectionIndicator.RenderTransform as CompositeTransform;

        Storyboard storyboard = new Storyboard();
        DoubleAnimation moveAnimation = new DoubleAnimation
        {
            To = targetTranslateY,
            Duration = TimeSpan.FromSeconds(0.5),
            EnableDependentAnimation = true,
            EasingFunction = new CircleEase { EasingMode = EasingMode.EaseInOut },
        };

        Storyboard.SetTarget(moveAnimation, transform);
        Storyboard.SetTargetProperty(moveAnimation, "TranslateY");

        storyboard.Children.Add(moveAnimation);
        storyboard.Begin();
    }
}

替代方案(不调整XAML结构)

若不想修改XAML,可将坐标参考系改为共同父容器Grid,调整偏移计算:

private void Button_Click(object sender, RoutedEventArgs e)
{
    if (SelectionIndicator.Visibility == Visibility.Collapsed) 
        SelectionIndicator.Visibility = Visibility.Visible;

    if (sender is Button clickedButton) 
    { 
        var parentGrid = this.Content as Grid;
        // 获取按钮相对于Grid的位置
        Point buttonPos = clickedButton.TransformToVisual(parentGrid).TransformPoint(new Point(0, 0));
        // 获取指示器初始位置相对于Grid的Y坐标
        Point indicatorInitPos = SelectionIndicator.TransformToVisual(parentGrid).TransformPoint(new Point(0, 0));
        // 计算目标偏移:按钮Y - 指示器初始Y + 居中调整
        double targetTranslateY = buttonPos.Y - indicatorInitPos.Y + (clickedButton.ActualHeight - SelectionIndicator.ActualHeight)/2;

        if (SelectionIndicator.RenderTransform is null || !(SelectionIndicator.RenderTransform is CompositeTransform)) 
            SelectionIndicator.RenderTransform = new CompositeTransform();

        CompositeTransform transform = SelectionIndicator.RenderTransform as CompositeTransform;

        Storyboard storyboard = new Storyboard();
        DoubleAnimation moveAnimation = new DoubleAnimation
        {
            To = targetTranslateY,
            Duration = TimeSpan.FromSeconds(0.5),
            EnableDependentAnimation = true,
            EasingFunction = new CircleEase { EasingMode = EasingMode.EaseInOut },
        };

        Storyboard.SetTarget(moveAnimation, transform);
        Storyboard.SetTargetProperty(moveAnimation, "TranslateY");

        storyboard.Children.Add(moveAnimation);
        storyboard.Begin();
    }
}

内容的提问来源于stack exchange,提问作者brushymilbil

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:59:50