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

Xamarin Forms实现双色圆形控件:求助设置左右颜色及文本

Dual-Color Circular Control with Center Text for Xamarin.Forms

Got it, let's solve this problem! The built-in controls like ProgressBar or basic shapes don't give you the exact dual-color circle with center text you're after, so we'll build a custom control that's flexible and easy to configure.

Approach 1: Custom ContentView with BoxViews (Simple & No External Libraries)

This method uses native Xamarin.Forms elements to create the dual-color circle, no extra packages needed.

Step 1: Create the Custom Control Class

First, define a custom ContentView with bindable properties for your required settings:

using Xamarin.Forms;

namespace YourAppNamespace
{
    public class DualColorCircle : ContentView
    {
        // Bindable properties for colors and text
        public static readonly BindableProperty LeftColorProperty =
            BindableProperty.Create(nameof(LeftColor), typeof(Color), typeof(DualColorCircle), Color.Blue);

        public static readonly BindableProperty RightColorProperty =
            BindableProperty.Create(nameof(RightColor), typeof(Color), typeof(DualColorCircle), Color.Gray);

        public static readonly BindableProperty CenterTextProperty =
            BindableProperty.Create(nameof(CenterText), typeof(string), typeof(DualColorCircle), "0%");

        public Color LeftColor
        {
            get => (Color)GetValue(LeftColorProperty);
            set => SetValue(LeftColorProperty, value);
        }

        public Color RightColor
        {
            get => (Color)GetValue(RightColorProperty);
            set => SetValue(RightColorProperty, value);
        }

        public string CenterText
        {
            get => (string)GetValue(CenterTextProperty);
            set => SetValue(CenterTextProperty, value);
        }

        public DualColorCircle()
        {
            BuildView();
        }

        private void BuildView()
        {
            // Use AbsoluteLayout to overlay the two half-circles and center label
            var layout = new AbsoluteLayout();

            // Left half-circle
            var leftHalf = new BoxView
            {
                Color = LeftColor,
                CornerRadius = new CornerRadius(100, 0, 0, 100) // Top-left, Top-right, Bottom-right, Bottom-left
            };

            // Right half-circle
            var rightHalf = new BoxView
            {
                Color = RightColor,
                CornerRadius = new CornerRadius(0, 100, 100, 0)
            };

            // Center text label
            var centerLabel = new Label
            {
                Text = CenterText,
                FontSize = Device.GetNamedSize(NamedSize.Large, typeof(Label)),
                FontAttributes = FontAttributes.Bold,
                HorizontalTextAlignment = TextAlignment.Center,
                VerticalTextAlignment = TextAlignment.Center
            };

            // Layout all elements
            AbsoluteLayout.SetLayoutBounds(leftHalf, new Rectangle(0, 0, 0.5, 1));
            AbsoluteLayout.SetLayoutFlags(leftHalf, AbsoluteLayoutFlags.All);

            AbsoluteLayout.SetLayoutBounds(rightHalf, new Rectangle(0.5, 0, 0.5, 1));
            AbsoluteLayout.SetLayoutFlags(rightHalf, AbsoluteLayoutFlags.All);

            AbsoluteLayout.SetLayoutBounds(centerLabel, new Rectangle(0.5, 0.5, 1, 1));
            AbsoluteLayout.SetLayoutFlags(centerLabel, AbsoluteLayoutFlags.PositionProportional);

            layout.Children.Add(leftHalf);
            layout.Children.Add(rightHalf);
            layout.Children.Add(centerLabel);

            Content = layout;

            // Update label when properties change
            this.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName == nameof(CenterText))
                {
                    centerLabel.Text = CenterText;
                }
                else if (e.PropertyName == nameof(LeftColor))
                {
                    leftHalf.Color = LeftColor;
                }
                else if (e.PropertyName == nameof(RightColor))
                {
                    rightHalf.Color = RightColor;
                }
            };
        }
    }
}

Step 2: Use the Control in Your Page

Add the control to your XAML page (don't forget the namespace declaration):

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourAppNamespace"
             x:Class="YourAppNamespace.MainPage">

    <StackLayout Padding="20" VerticalOptions="Center" HorizontalOptions="Center">
        <!-- Custom dual-color circle -->
        <local:DualColorCircle 
            WidthRequest="200" 
            HeightRequest="200"
            LeftColor="#2196F3"
            RightColor="#E0E0E0"
            CenterText="50%" />
    </StackLayout>
</ContentPage>

Approach 2: SkiaSharp (Smoother, More Flexible)

If you want smoother edges or plan to add animations later, SkiaSharp is a great choice. First, install the SkiaSharp.Views.Forms NuGet package.

Step 1: Create the SkiaSharp Control

using SkiaSharp;
using SkiaSharp.Views.Forms;
using Xamarin.Forms;

namespace YourAppNamespace
{
    public class DualColorCircleSK : ContentView
    {
        public static readonly BindableProperty LeftColorProperty =
            BindableProperty.Create(nameof(LeftColor), typeof(Color), typeof(DualColorCircleSK), Color.Blue);

        public static readonly BindableProperty RightColorProperty =
            BindableProperty.Create(nameof(RightColor), typeof(Color), typeof(DualColorCircleSK), Color.Gray);

        public static readonly BindableProperty CenterTextProperty =
            BindableProperty.Create(nameof(CenterText), typeof(string), typeof(DualColorCircleSK), "0%");

        public Color LeftColor
        {
            get => (Color)GetValue(LeftColorProperty);
            set => SetValue(LeftColorProperty, value);
        }

        public Color RightColor
        {
            get => (Color)GetValue(RightColorProperty);
            set => SetValue(RightColorProperty, value);
        }

        public string CenterText
        {
            get => (string)GetValue(CenterTextProperty);
            set => SetValue(CenterTextProperty, value);
        }

        private SKCanvasView canvasView;

        public DualColorCircleSK()
        {
            canvasView = new SKCanvasView();
            canvasView.PaintSurface += OnCanvasViewPaintSurface;
            Content = canvasView;

            // Redraw when properties change
            this.PropertyChanged += (s, e) =>
            {
                if (e.PropertyName is nameof(LeftColor) or nameof(RightColor) or nameof(CenterText))
                {
                    canvasView.InvalidateSurface();
                }
            };
        }

        private void OnCanvasViewPaintSurface(object sender, SKPaintSurfaceEventArgs e)
        {
            SKImageInfo info = e.Info;
            SKSurface surface = e.Surface;
            SKCanvas canvas = surface.Canvas;

            canvas.Clear();

            // Calculate circle bounds
            float radius = Math.Min(info.Width, info.Height) / 2f;
            SKPoint center = new SKPoint(info.Width / 2f, info.Height / 2f);
            SKRect circleRect = new SKRect(center.X - radius, center.Y - radius, center.X + radius, center.Y + radius);

            // Draw left half-circle
            using (SKPaint leftPaint = new SKPaint())
            {
                leftPaint.Color = LeftColor.ToSKColor();
                leftPaint.IsAntialias = true;
                canvas.DrawArc(circleRect, 90, 180, true, leftPaint);
            }

            // Draw right half-circle
            using (SKPaint rightPaint = new SKPaint())
            {
                rightPaint.Color = RightColor.ToSKColor();
                rightPaint.IsAntialias = true;
                canvas.DrawArc(circleRect, 270, 180, true, rightPaint);
            }

            // Draw center text
            using (SKPaint textPaint = new SKPaint())
            {
                textPaint.Color = Colors.Black.ToSKColor();
                textPaint.TextSize = radius * 0.4f;
                textPaint.IsAntialias = true;
                textPaint.TextAlign = SKTextAlign.Center;
                textPaint.Typeface = SKTypeface.FromFamilyName(null, SKFontStyle.Bold);

                // Calculate text position to center it vertically
                SKRect textBounds = new SKRect();
                textPaint.MeasureText(CenterText, ref textBounds);
                float textY = center.Y - textBounds.MidY;

                canvas.DrawText(CenterText, center.X, textY, textPaint);
            }
        }
    }
}

Step 2: Use the SkiaSharp Control

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourAppNamespace"
             xmlns:skia="clr-namespace:SkiaSharp.Views.Forms;assembly=SkiaSharp.Views.Forms"
             x:Class="YourAppNamespace.MainPage">

    <StackLayout Padding="20" VerticalOptions="Center" HorizontalOptions="Center">
        <local:DualColorCircleSK 
            WidthRequest="200" 
            HeightRequest="200"
            LeftColor="#4CAF50"
            RightColor="#FFC107"
            CenterText="75%" />
    </StackLayout>
</ContentPage>

Both approaches let you easily set the left/right colors and center text, and the SkiaSharp version gives you more control over rendering quality and potential animations. Pick whichever fits your project's needs!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 10:13:15