如何在.NET MAUI中实现Label文本背景色(类似选中文本样式)
在.NET MAUI中实现Label文本行背景高亮(类似文本选中效果)
.NET MAUI的原生Label控件没有直接提供这种仅文本行带背景、换行终止、行间带细白线的API,不过可以通过自定义控件+平台渲染器的方式实现,以下是具体方案:
步骤1:创建自定义Label控件
先定义一个继承自Label的自定义控件,添加可绑定属性来控制高亮颜色和行间隙宽度:
using Microsoft.Maui.Controls; namespace YourAppNamespace.Controls; public class HighlightLineLabel : Label { // 行高亮背景色 public static readonly BindableProperty LineHighlightColorProperty = BindableProperty.Create(nameof(LineHighlightColor), typeof(Color), typeof(HighlightLineLabel), Colors.LightYellow); public Color LineHighlightColor { get => (Color)GetValue(LineHighlightColorProperty); set => SetValue(LineHighlightColorProperty, value); } // 行间隙宽度(控制行间白线的粗细) public static readonly BindableProperty LineGapWidthProperty = BindableProperty.Create(nameof(LineGapWidth), typeof(float), typeof(HighlightLineLabel), 2f); public float LineGapWidth { get => (float)GetValue(LineGapWidthProperty); set => SetValue(LineGapWidthProperty, value); } }
步骤2:实现Android平台自定义渲染器
在Android项目中,利用LineBackgroundSpan为每行文本绘制带间隙的背景:
using Android.Content; using Android.Text; using Android.Text.Style; using Android.Widget; using YourAppNamespace.Controls; using YourAppNamespace.Platforms.Android.Renderers; using Microsoft.Maui.Controls.Compatibility.Platform.Android; using Microsoft.Maui.Graphics; [assembly: ExportRenderer(typeof(HighlightLineLabel), typeof(HighlightLineLabelRenderer))] namespace YourAppNamespace.Platforms.Android.Renderers; public class HighlightLineLabelRenderer : LabelRenderer { public HighlightLineLabelRenderer(Context context) : base(context) { } protected override void OnElementChanged(ElementChangedEventArgs<Label> e) { base.OnElementChanged(e); if (Control is TextView textView && Element is HighlightLineLabel highlightLabel) { var spannableText = new SpannableString(textView.Text); var highlightColor = highlightLabel.LineHighlightColor.ToAndroid(); var lineGap = highlightLabel.LineGapWidth; // 为整个文本添加自定义行背景Span spannableText.SetSpan( new CustomLineBackgroundSpan(highlightColor, lineGap), 0, spannableText.Length(), SpanTypes.ExclusiveExclusive); textView.TextFormatted = spannableText; } } // 自定义行背景绘制逻辑 private class CustomLineBackgroundSpan : LineBackgroundSpan { private readonly Android.Graphics.Color _highlightColor; private readonly float _lineGap; public CustomLineBackgroundSpan(Android.Graphics.Color highlightColor, float lineGap) { _highlightColor = highlightColor; _lineGap = lineGap; } public override void DrawBackground(Canvas canvas, Paint paint, int left, int right, int top, int baseline, int bottom, ICharSequence text, int start, int end, int lineNumber) { var originalColor = paint.Color; paint.Color = _highlightColor; // 绘制背景时上下留出间隙,形成行间白线 var drawRect = new Android.Graphics.RectF(left, top + _lineGap/2, right, bottom - _lineGap/2); canvas.DrawRect(drawRect, paint); paint.Color = originalColor; } } }
步骤3:实现iOS平台自定义渲染器
在iOS项目中,通过NSTextStorage和NSLayoutManager计算每行位置,手动绘制带间隙的背景:
using CoreGraphics; using Foundation; using UIKit; using YourAppNamespace.Controls; using YourAppNamespace.Platforms.iOS.Renderers; using Microsoft.Maui.Controls.Compatibility.Platform.iOS; using Microsoft.Maui.Graphics; [assembly: ExportRenderer(typeof(HighlightLineLabel), typeof(HighlightLineLabelRenderer))] namespace YourAppNamespace.Platforms.iOS.Renderers; public class HighlightLineLabelRenderer : LabelRenderer { protected override void OnElementChanged(ElementChangedEventArgs<Label> e) { base.OnElementChanged(e); if (Control is UILabel label && Element is HighlightLineLabel highlightLabel) { var text = label.Text ?? string.Empty; var textStorage = new NSTextStorage(text); var layoutManager = new NSLayoutManager(); var textContainer = new NSTextContainer(label.Bounds.Size) { LineFragmentPadding = 0, MaximumNumberOfLines = (nint)label.Lines, LineBreakMode = label.LineBreakMode }; layoutManager.AddTextContainer(textContainer); textStorage.AddLayoutManager(layoutManager); var highlightColor = highlightLabel.LineHighlightColor.ToUIColor(); var lineGap = highlightLabel.LineGapWidth; // 监听Label的绘制事件,手动绘制行背景 label.DrawText += (sender, args) => { var context = UIGraphics.GetCurrentContext(); context.SaveState(); var glyphRange = layoutManager.GlyphRangeForTextContainer(textContainer); var currentLineRange = new NSRange(0, 0); // 遍历每一行文本,绘制背景 while (layoutManager.GetLineRangeForGlyphRange(glyphRange, ref currentLineRange)) { var lineRect = layoutManager.GetLineFragmentUsedRectForGlyphRange(currentLineRange, textContainer); // 调整绘制区域,留出上下间隙 var highlightRect = new CGRect( lineRect.Left, lineRect.Top + lineGap/2, lineRect.Width, lineRect.Height - lineGap); highlightColor.SetFill(); UIGraphics.RectFill(highlightRect); // 移动到下一行 glyphRange = new NSRange(currentLineRange.Location + currentLineRange.Length, glyphRange.Length - currentLineRange.Length); } context.RestoreState(); }; } } }
步骤4:在XAML中使用自定义控件
直接引用自定义控件,配置高亮颜色和行间隙即可:
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:controls="clr-namespace:YourAppNamespace.Controls" x:Class="YourAppNamespace.MainPage"> <VerticalStackLayout Padding="20"> <controls:HighlightLineLabel Text="这是一段测试文本,用于验证行背景高亮效果。当文本自动换行时,每行都会有独立的背景色,行与行之间会显示细白线分隔,完全符合你需要的类似文本选中的视觉效果。" LineHighlightColor="#FFF9C4" LineGapWidth="2" FontSize="16" Margin="0 0 0 10"/> </VerticalStackLayout> </ContentPage>
这种方案基于原生平台API实现,性能稳定,支持自动换行、动态文本内容,并且可以通过绑定属性灵活调整样式。
内容的提问来源于stack exchange,提问作者Emilien Rakotonoelina
相关产品推荐
相关产品推荐

