Preview 3: Complete control implementation with XAML data binding
Major milestone adding full control functionality: Controls Enhanced: - Entry/Editor: Full keyboard input, cursor navigation, selection, clipboard - CollectionView: Data binding, selection highlighting, scrolling - CheckBox/Switch/Slider: Interactive state management - Picker/DatePicker/TimePicker: Dropdown selection with popup overlays - ProgressBar/ActivityIndicator: Animated progress display - Button: Press/release visual states - Border/Frame: Rounded corners, stroke styling - Label: Text wrapping, alignment, decorations - Grid/StackLayout: Margin and padding support Features Added: - DisplayAlert dialogs with button actions - NavigationPage with toolbar and back navigation - Shell with flyout menu navigation - XAML value converters for data binding - Margin support in all layout containers - Popup overlay system for pickers New Samples: - TodoApp: Full CRUD task manager with NavigationPage - ShellDemo: Comprehensive control showcase Removed: - ControlGallery (replaced by ShellDemo) - LinuxDemo (replaced by TodoApp) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,40 +6,156 @@ using SkiaSharp;
|
||||
namespace Microsoft.Maui.Platform;
|
||||
|
||||
/// <summary>
|
||||
/// Skia-rendered progress bar control.
|
||||
/// Skia-rendered progress bar control with full XAML styling support.
|
||||
/// </summary>
|
||||
public class SkiaProgressBar : SkiaView
|
||||
{
|
||||
private double _progress;
|
||||
#region BindableProperties
|
||||
|
||||
/// <summary>
|
||||
/// Bindable property for Progress.
|
||||
/// </summary>
|
||||
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());
|
||||
|
||||
/// <summary>
|
||||
/// Bindable property for TrackColor.
|
||||
/// </summary>
|
||||
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());
|
||||
|
||||
/// <summary>
|
||||
/// Bindable property for ProgressColor.
|
||||
/// </summary>
|
||||
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());
|
||||
|
||||
/// <summary>
|
||||
/// Bindable property for DisabledColor.
|
||||
/// </summary>
|
||||
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());
|
||||
|
||||
/// <summary>
|
||||
/// Bindable property for BarHeight.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty BarHeightProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(BarHeight),
|
||||
typeof(float),
|
||||
typeof(SkiaProgressBar),
|
||||
4f,
|
||||
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).InvalidateMeasure());
|
||||
|
||||
/// <summary>
|
||||
/// Bindable property for CornerRadius.
|
||||
/// </summary>
|
||||
public static readonly BindableProperty CornerRadiusProperty =
|
||||
BindableProperty.Create(
|
||||
nameof(CornerRadius),
|
||||
typeof(float),
|
||||
typeof(SkiaProgressBar),
|
||||
2f,
|
||||
propertyChanged: (b, o, n) => ((SkiaProgressBar)b).Invalidate());
|
||||
|
||||
#endregion
|
||||
|
||||
#region Properties
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the progress value (0.0 to 1.0).
|
||||
/// </summary>
|
||||
public double Progress
|
||||
{
|
||||
get => _progress;
|
||||
set
|
||||
{
|
||||
var clamped = Math.Clamp(value, 0, 1);
|
||||
if (_progress != clamped)
|
||||
{
|
||||
_progress = clamped;
|
||||
ProgressChanged?.Invoke(this, new ProgressChangedEventArgs(_progress));
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
get => (double)GetValue(ProgressProperty);
|
||||
set => SetValue(ProgressProperty, value);
|
||||
}
|
||||
|
||||
public SKColor TrackColor { get; set; } = new SKColor(0xE0, 0xE0, 0xE0);
|
||||
public SKColor ProgressColor { get; set; } = new SKColor(0x21, 0x96, 0xF3);
|
||||
public SKColor DisabledColor { get; set; } = new SKColor(0xBD, 0xBD, 0xBD);
|
||||
public float Height { get; set; } = 4;
|
||||
public float CornerRadius { get; set; } = 2;
|
||||
/// <summary>
|
||||
/// Gets or sets the track color.
|
||||
/// </summary>
|
||||
public SKColor TrackColor
|
||||
{
|
||||
get => (SKColor)GetValue(TrackColorProperty);
|
||||
set => SetValue(TrackColorProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the progress color.
|
||||
/// </summary>
|
||||
public SKColor ProgressColor
|
||||
{
|
||||
get => (SKColor)GetValue(ProgressColorProperty);
|
||||
set => SetValue(ProgressColorProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the disabled color.
|
||||
/// </summary>
|
||||
public SKColor DisabledColor
|
||||
{
|
||||
get => (SKColor)GetValue(DisabledColorProperty);
|
||||
set => SetValue(DisabledColorProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the bar height.
|
||||
/// </summary>
|
||||
public float BarHeight
|
||||
{
|
||||
get => (float)GetValue(BarHeightProperty);
|
||||
set => SetValue(BarHeightProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the corner radius.
|
||||
/// </summary>
|
||||
public float CornerRadius
|
||||
{
|
||||
get => (float)GetValue(CornerRadiusProperty);
|
||||
set => SetValue(CornerRadiusProperty, value);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <summary>
|
||||
/// Event raised when progress changes.
|
||||
/// </summary>
|
||||
public event EventHandler<ProgressChangedEventArgs>? 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 - Height / 2;
|
||||
var trackBottom = trackY + Height / 2;
|
||||
var trackTop = trackY - BarHeight / 2;
|
||||
var trackBottom = trackY + BarHeight / 2;
|
||||
|
||||
// Draw track
|
||||
using var trackPaint = new SKPaint
|
||||
@@ -75,10 +191,13 @@ public class SkiaProgressBar : SkiaView
|
||||
|
||||
protected override SKSize MeasureOverride(SKSize availableSize)
|
||||
{
|
||||
return new SKSize(200, Height + 8);
|
||||
return new SKSize(200, BarHeight + 8);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Event args for progress changed events.
|
||||
/// </summary>
|
||||
public class ProgressChangedEventArgs : EventArgs
|
||||
{
|
||||
public double Progress { get; }
|
||||
|
||||
Reference in New Issue
Block a user