// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using Microsoft.Maui.Controls; using SkiaSharp; namespace Microsoft.Maui.Platform; /// /// Skia-rendered progress bar control with full XAML styling support. /// public class SkiaProgressBar : SkiaView { #region BindableProperties /// /// Bindable property for Progress. /// public static readonly BindableProperty ProgressProperty = BindableProperty.Create( nameof(Progress), typeof(double), typeof(SkiaProgressBar), 0.0, BindingMode.OneWay, coerceValue: (b, v) => Math.Clamp((double)v, 0.0, 1.0), propertyChanged: (b, o, n) => ((SkiaProgressBar)b).OnProgressChanged()); /// /// Bindable property for TrackColor. /// public static readonly BindableProperty TrackColorProperty = BindableProperty.Create( nameof(TrackColor), typeof(SKColor), typeof(SkiaProgressBar), new SKColor(224, 224, 224), BindingMode.TwoWay, propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate()); /// /// Bindable property for ProgressColor. /// public static readonly BindableProperty ProgressColorProperty = BindableProperty.Create( nameof(ProgressColor), typeof(SKColor), typeof(SkiaProgressBar), new SKColor(33, 150, 243), BindingMode.TwoWay, propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate()); /// /// Bindable property for DisabledColor. /// public static readonly BindableProperty DisabledColorProperty = BindableProperty.Create( nameof(DisabledColor), typeof(SKColor), typeof(SkiaProgressBar), new SKColor(189, 189, 189), BindingMode.TwoWay, propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate()); /// /// Bindable property for BarHeight. /// public static readonly BindableProperty BarHeightProperty = BindableProperty.Create( nameof(BarHeight), typeof(float), typeof(SkiaProgressBar), 4f, BindingMode.TwoWay, propertyChanged: (b, o, n) => ((SkiaProgressBar)b).InvalidateMeasure()); /// /// Bindable property for CornerRadius. /// public static readonly BindableProperty CornerRadiusProperty = BindableProperty.Create( nameof(CornerRadius), typeof(float), typeof(SkiaProgressBar), 2f, BindingMode.TwoWay, propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate()); #endregion #region Properties /// /// Gets or sets the progress value (0.0 to 1.0). /// public double Progress { get => (double)GetValue(ProgressProperty); set => SetValue(ProgressProperty, value); } /// /// Gets or sets the track color. /// public SKColor TrackColor { get => (SKColor)GetValue(TrackColorProperty); set => SetValue(TrackColorProperty, value); } /// /// Gets or sets the progress color. /// public SKColor ProgressColor { get => (SKColor)GetValue(ProgressColorProperty); set => SetValue(ProgressColorProperty, value); } /// /// Gets or sets the disabled color. /// public SKColor DisabledColor { get => (SKColor)GetValue(DisabledColorProperty); set => SetValue(DisabledColorProperty, value); } /// /// Gets or sets the bar height. /// public float BarHeight { get => (float)GetValue(BarHeightProperty); set => SetValue(BarHeightProperty, value); } /// /// Gets or sets the corner radius. /// public float CornerRadius { get => (float)GetValue(CornerRadiusProperty); set => SetValue(CornerRadiusProperty, value); } #endregion /// /// Event raised when progress changes. /// public event EventHandler? ProgressChanged; private void OnProgressChanged() { ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(Progress)); Invalidate(); } protected override void OnDraw(SKCanvas canvas, SKRect bounds) { float midY = bounds.MidY; float trackTop = midY - BarHeight / 2f; float trackBottom = midY + BarHeight / 2f; // Draw track using var trackPaint = new SKPaint { Color = IsEnabled ? TrackColor : DisabledColor, IsAntialias = true, Style = SKPaintStyle.Fill }; var trackRect = new SKRoundRect( new SKRect(bounds.Left, trackTop, bounds.Right, trackBottom), CornerRadius); canvas.DrawRoundRect(trackRect, trackPaint); // Draw progress if (Progress > 0.0) { float progressWidth = bounds.Width * (float)Progress; using var progressPaint = new SKPaint { Color = IsEnabled ? ProgressColor : DisabledColor, IsAntialias = true, Style = SKPaintStyle.Fill }; var progressRect = new SKRoundRect( new SKRect(bounds.Left, trackTop, bounds.Left + progressWidth, trackBottom), CornerRadius); canvas.DrawRoundRect(progressRect, progressPaint); } } protected override SKSize MeasureOverride(SKSize availableSize) { return new SKSize(200f, BarHeight + 8f); } } /// /// Event args for progress changed events. /// public class ProgressChangedEventArgs : EventArgs { public double Progress { get; } public ProgressChangedEventArgs(double progress) => Progress = progress; }