// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. 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.TwoWay, coerceValue: (b, v) => Math.Clamp((double)v, 0, 1), 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(0xE0, 0xE0, 0xE0), 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(0x21, 0x96, 0xF3), 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(0xBD, 0xBD, 0xBD), 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, 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, 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) { var trackY = bounds.MidY; var trackTop = trackY - BarHeight / 2; var trackBottom = trackY + BarHeight / 2; // 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) { var 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(200, BarHeight + 8); } } /// /// Event args for progress changed events. /// public class ProgressChangedEventArgs : EventArgs { public double Progress { get; } public ProgressChangedEventArgs(double progress) => Progress = progress; }