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

如何在.NET MAUI中实现支持半星的滑动评分条

实现跨平台可滑动评分控件(支持半星)

核心思路

  • 用PanGestureRecognizer捕获滑动手势,将滑动距离转换为0-5分的评分值(支持0.5步长)
  • 每个星星根据当前评分判断自身状态:全满、半满、空
  • 实时更新星星显示状态,对外暴露可绑定的评分属性供业务层获取输入值

具体实现步骤

1. 定义星星状态与基础控件

先创建星星状态枚举,区分三种显示状态:

public enum StarFillState
{
    Empty,
    Half,
    Full
}

编写可复用的星星控件(StarView),根据状态切换对应图片:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="YourNamespace.StarView">
    <ContentView.Content>
        <Image x:Name="StarImage" Aspect="AspectFit" />
    </ContentView.Content>
</ContentView>

后台代码绑定状态属性,自动切换图片:

public partial class StarView : ContentView
{
    public static readonly BindableProperty StateProperty =
        BindableProperty.Create(nameof(State), typeof(StarFillState), typeof(StarView), StarFillState.Empty, propertyChanged: OnStateChanged);

    public StarFillState State
    {
        get => (StarFillState)GetValue(StateProperty);
        set => SetValue(StateProperty, value);
    }

    private static void OnStateChanged(BindableObject bindable, object oldValue, object newValue)
    {
        var starView = (StarView)bindable;
        switch ((StarFillState)newValue)
        {
            case StarFillState.Empty:
                starView.StarImage.Source = "star_empty.png";
                break;
            case StarFillState.Half:
                starView.StarImage.Source = "star_half.png";
                break;
            case StarFillState.Full:
                starView.StarImage.Source = "star_full.png";
                break;
        }
    }

    public StarView()
    {
        InitializeComponent();
    }
}

2. 构建滑动评分容器

用HorizontalStackLayout承载星星控件,添加滑动手势识别器:

<ContentView xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:local="clr-namespace:YourNamespace"
             x:Class="YourNamespace.SwipeRatingControl">
    <ContentView.Content>
        <HorizontalStackLayout x:Name="StarsContainer" Spacing="4">
            <HorizontalStackLayout.GestureRecognizers>
                <PanGestureRecognizer PanUpdated="OnPanUpdated" />
            </HorizontalStackLayout.GestureRecognizers>
            <local:StarView x:Name="Star1" />
            <local:StarView x:Name="Star2" />
            <local:StarView x:Name="Star3" />
            <local:StarView x:Name="Star4" />
            <local:StarView x:Name="Star5" />
        </HorizontalStackLayout>
    </ContentView.Content>
</ContentView>

3. 处理滑动逻辑与状态更新

后台代码计算滑动位置对应的评分,实时更新每个星星的状态:

public partial class SwipeRatingControl : ContentView
{
    public static readonly BindableProperty RatingProperty =
        BindableProperty.Create(nameof(Rating), typeof(double), typeof(SwipeRatingControl), 0.0, BindingMode.TwoWay);

    public double Rating
    {
        get => (double)GetValue(RatingProperty);
        set => SetValue(RatingProperty, value);
    }

    private double _totalWidth;
    private List<StarView> _stars;

    public SwipeRatingControl()
    {
        InitializeComponent();
        _stars = new List<StarView> { Star1, Star2, Star3, Star4, Star5 };
        SizeChanged += OnSizeChanged;
    }

    private void OnSizeChanged(object sender, EventArgs e)
    {
        _totalWidth = StarsContainer.Width;
    }

    private void OnPanUpdated(object sender, PanUpdatedEventArgs e)
    {
        if (_totalWidth <= 0) return;

        switch (e.StatusType)
        {
            case GestureStatus.Running:
                var relativeX = Math.Clamp(e.TotalX / _totalWidth, 0, 1);
                Rating = Math.Round(relativeX * 5 * 2) / 2; // 强制保留0.5步长
                UpdateStars();
                break;
        }
    }

    private void UpdateStars()
    {
        for (int i = 0; i < _stars.Count; i++)
        {
            var starRank = i + 1;
            if (Rating >= starRank)
            {
                _stars[i].State = StarFillState.Full;
            }
            else if (Rating >= starRank - 0.5)
            {
                _stars[i].State = StarFillState.Half;
            }
            else
            {
                _stars[i].State = StarFillState.Empty;
            }
        }
    }
}

4. 业务层使用控件

在页面中直接引用控件,通过绑定获取用户输入的评分:

<local:SwipeRatingControl Rating="{Binding UserSelectedRating}" />

平台适配注意事项

  • 确保星星图片(star_empty.png、star_half.png、star_full.png)已正确放置在Android和iOS的资源目录中
  • iOS上可通过调整PanGestureRecognizer.MinimumDistance属性,避免滑动误触
  • Android上需确保HorizontalStackLayout.InputTransparent为false,保证手势能被正常捕获

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 04:52:34