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

UWP中如何将12个TextBlock沿圆形排列?

在UWP中实现TextBlock沿圆形排列的正确方法

嘿,用Grid来模拟圆形排列确实只能做到近似效果——毕竟Grid是基于行列的网格布局,没法精准贴合圆形的三角函数坐标,斜向的元素肯定会偏离轨迹。这里给你两个更靠谱的实现方案,能完美实现12个TextBlock的圆形排列:

方案一:用Canvas+代码计算坐标

Canvas支持绝对定位,我们可以通过三角函数计算每个TextBlock在圆形上的精确位置,步骤很简单:

1. XAML布局

先在页面里放一个Canvas作为容器:

<Canvas x:Name="CircularCanvas" Width="200" Height="200" 
        HorizontalAlignment="Center" VerticalAlignment="Center"/>

2. 后台代码计算位置

在Canvas的Loaded事件里,遍历创建12个TextBlock,用三角函数计算每个元素的圆心坐标:

private void CircularCanvas_Loaded(object sender, RoutedEventArgs e)
{
    // 获取Canvas的中心点
    double centerX = CircularCanvas.ActualWidth / 2;
    double centerY = CircularCanvas.ActualHeight / 2;
    // 圆形半径(留出TextBlock的空间,避免超出边界)
    double radius = Math.Min(centerX, centerY) - 15;

    for (int i = 1; i <= 12; i++)
    {
        TextBlock tb = new TextBlock
        {
            Text = i.ToString(),
            FontSize = 16,
            Foreground = new SolidColorBrush(Colors.Black)
        };

        // 计算角度:从12点(-90度)开始,每个元素间隔30度(360/12)
        double angleInRadians = Math.PI * (-90 + (i - 1) * 30) / 180;
        // 计算TextBlock的中心坐标
        double x = centerX + radius * Math.Cos(angleInRadians);
        double y = centerY + radius * Math.Sin(angleInRadians);

        // 因为TextBlock加载前ActualWidth可能为0,所以在它自己的Loaded事件里调整位置
        tb.Loaded += (s, args) =>
        {
            TextBlock currentTb = s as TextBlock;
            Canvas.SetLeft(currentTb, x - currentTb.ActualWidth / 2);
            Canvas.SetTop(currentTb, y - currentTb.ActualHeight / 2);
        };

        CircularCanvas.Children.Add(tb);
    }
}

方案二:自定义CircularLayout布局控件

如果需要复用这种圆形布局,自定义一个Panel控件是更好的选择,这样以后在XAML里直接用这个布局就能自动排列元素:

1. 自定义Panel代码

创建一个继承自Panel的类,重写布局逻辑:

public class CircularLayout : Panel
{
    // 定义依赖属性:圆形半径
    public static readonly DependencyProperty RadiusProperty =
        DependencyProperty.Register(nameof(Radius), typeof(double), typeof(CircularLayout), 
            new PropertyMetadata(100.0, (d, e) => (d as CircularLayout)?.InvalidateArrange()));

    public double Radius
    {
        get => (double)GetValue(RadiusProperty);
        set => SetValue(RadiusProperty, value);
    }

    protected override Size MeasureOverride(Size availableSize)
    {
        // 让每个子元素自己计算需要的大小
        foreach (UIElement child in Children)
        {
            child.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));
        }
        // 布局的整体大小是直径的大小
        return new Size(Radius * 2, Radius * 2);
    }

    protected override Size ArrangeOverride(Size finalSize)
    {
        if (Children.Count == 0) return finalSize;

        double centerX = finalSize.Width / 2;
        double centerY = finalSize.Height / 2;
        // 每个元素之间的角度间隔
        double angleStep = 2 * Math.PI / Children.Count;

        for (int i = 0; i < Children.Count; i++)
        {
            UIElement child = Children[i];
            // 从顶部(-90度)开始排列
            double angle = angleStep * i - Math.PI / 2;
            // 计算子元素的中心坐标
            double childX = centerX + Radius * Math.Cos(angle);
            double childY = centerY + Radius * Math.Sin(angle);
            // 让子元素的中心落在圆形轨迹上,调整左上角坐标
            Rect arrangeRect = new Rect(
                childX - child.DesiredSize.Width / 2,
                childY - child.DesiredSize.Height / 2,
                child.DesiredSize.Width,
                child.DesiredSize.Height);
            
            child.Arrange(arrangeRect);
        }

        return finalSize;
    }
}

2. 在XAML中使用自定义布局

记得先引入命名空间(假设你的自定义控件在YourAppName.Controls命名空间下),然后直接添加TextBlock即可:

<Page xmlns:local="using:YourAppName.Controls">
    <Grid>
        <local:CircularLayout Radius="80" Width="200" Height="200"
                              HorizontalAlignment="Center" VerticalAlignment="Center">
            <TextBlock Text="1" FontSize="16"/>
            <TextBlock Text="2" FontSize="16"/>
            <TextBlock Text="3" FontSize="16"/>
            <TextBlock Text="4" FontSize="16"/>
            <TextBlock Text="5" FontSize="16"/>
            <TextBlock Text="6" FontSize="16"/>
            <TextBlock Text="7" FontSize="16"/>
            <TextBlock Text="8" FontSize="16"/>
            <TextBlock Text="9" FontSize="16"/>
            <TextBlock Text="10" FontSize="16"/>
            <TextBlock Text="11" FontSize="16"/>
            <TextBlock Text="12" FontSize="16"/>
        </local:CircularLayout>
    </Grid>
</Page>

这两种方法都能精准实现圆形排列,自定义布局的优势在于可复用性强,以后要加更多元素或者调整半径,直接修改属性就行,非常方便。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:48:12