Added samples to showcase how to customize existing controls and create new ones

This commit is contained in:
Javier Suárez Ruiz 2021-09-26 18:34:15 +02:00
Родитель 24212c1e87
Коммит fcad11ceca
40 изменённых файлов: 1282 добавлений и 103 удалений

Просмотреть файл

@ -84,7 +84,7 @@
<ItemGroup Condition="$(TargetFramework.Contains('-windows')) == true ">
<PackageReference Include="Microsoft.Graphics.Win2D" />
<PackageReference Include="Microsoft.Maui.Graphics.Win2D.WinUI.Desktop" Version="6.0.100-preview.6.299" />
<PackageReference Include="Microsoft.Maui.Graphics.Win2D.WinUI.Desktop" Version="6.0.100-rc.1.382" />
</ItemGroup>
</Project>

Просмотреть файл

@ -8,6 +8,7 @@ namespace GraphicsControls.Sample
{
InitializeComponent();
//MainPage = new CustomControlsPage();
MainPage = new MainPage();
}
}

Просмотреть файл

@ -0,0 +1,121 @@
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Controls;
namespace GraphicsControls.Sample.Controls
{
public class CustomSliderDrawable : Slider
{
}
public class CustomSliderDrawableHandler : SliderHandler
{
protected override ISliderDrawable CreateDrawable() => new CustomDrawable();
}
public class CustomDrawable : ViewDrawable<ISlider>, ISliderDrawable
{
RectangleF trackRect = new RectangleF();
public RectangleF TrackRect => trackRect;
RectangleF touchTargetRect = new RectangleF(0, 0, 44, 44);
public RectangleF TouchTargetRect => touchTargetRect;
public void DrawBackground(ICanvas canvas, RectangleF dirtyRect, ISlider slider)
{
canvas.SaveState();
canvas.FillColor = Color.FromArgb("#7630FE"); //slider.MaximumTrackColor.WithDefault(Colors.White.ToArgbHex());
var x = dirtyRect.X;
var width = dirtyRect.Width;
var height = 1;
trackRect.X = x;
trackRect.Width = width;
var y = (float)((dirtyRect.Height - height) / 2);
canvas.FillRoundedRectangle(x, y, width, height, 6);
canvas.RestoreState();
}
public void DrawText(ICanvas canvas, RectangleF dirtyRect, ISlider slider)
{
}
public void DrawThumb(ICanvas canvas, RectangleF dirtyRect, ISlider slider)
{
float size = 38f;
float strokeWidth = 0.5f;
var value = slider.Value / slider.Maximum - slider.Minimum;
var x = (float)((dirtyRect.Width * value) - (size / 2));
if (x <= strokeWidth)
x = strokeWidth;
if (x >= dirtyRect.Width - (size + strokeWidth))
x = dirtyRect.Width - (size + strokeWidth);
var y = (float)((dirtyRect.Height - size) / 2);
canvas.SaveState();
canvas.StrokeColor = Color.FromArgb("#4F01E0"); //slider.ThumbColor.WithDefault(Colors.Black.ToArgbHex());
canvas.StrokeSize = strokeWidth;
var linearGradientPaint = new LinearGradientPaint
{
StartColor = Color.FromArgb("#B589D6"),
EndColor = Color.FromArgb("#552586")
};
linearGradientPaint.StartPoint = new Point(0, 0);
linearGradientPaint.EndPoint = new Point(0.8, 1.0);
canvas.SetFillPaint(linearGradientPaint, new RectangleF(x, y, size, size)); //slider.ThumbColor.WithDefault(Colors.White.ToArgbHex());
canvas.SetShadow(new SizeF(6, 6), 6, Color.FromArgb("#99330194"));
touchTargetRect.Center(new PointF(x, y));
canvas.FillRoundedRectangle(x, y, size, size, 6);
canvas.RestoreState();
canvas.SaveState();
canvas.SetShadow(new SizeF(-6, -6), 6, Color.FromArgb("#999E27FF"));
canvas.DrawRoundedRectangle(x, y, size, size, 6);
canvas.RestoreState();
canvas.RestoreState();
float marginX = 3;
float marginY = 13;
canvas.Translate(x + marginX, y + marginY);
var vBuilder = new PathBuilder();
var path = vBuilder.BuildPath("M6.0190067,0.16500799L7.4250088,1.5890061 3.9923439,4.979006 14.419033,4.979006 14.419033,6.9799988 3.699379,6.9799988 7.4300079,10.708995 6.015007,12.123994 0,6.1090004z M25.982016,0L32.001003,5.9430005 25.985983,11.958999 24.571004,10.543993 28.167773,6.9479963 18.027001,6.9479963 18.027001,4.9470035 28.144115,4.9470035 24.576009,1.4240091z");
canvas.FillColor = Colors.White;
canvas.FillPath(path);
canvas.SaveState();
}
public void DrawTrackProgress(ICanvas canvas, RectangleF dirtyRect, ISlider slider)
{
}
}
}

Просмотреть файл

@ -0,0 +1,48 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Controls;
namespace GraphicsControls.Sample.Controls
{
public class CustomSliderMapper : Slider
{
}
public class CustomSliderMapperHandler : SliderHandler
{
public CustomSliderMapperHandler()
{
DrawMapper[nameof(ISliderDrawable.DrawThumb)] = (canvas, rect, drawable, slider) =>
{
canvas.SaveState();
float size = 28f;
float strokeWidth = 0.5f;
canvas.StrokeColor = slider.ThumbColor.WithDefault(Colors.White.ToArgbHex());
canvas.StrokeSize = strokeWidth;
var value = (slider.Value / slider.Maximum) - slider.Minimum;
var x = (float)((rect.Width * value) - (size / 2));
if (x <= strokeWidth)
x = strokeWidth;
if (x >= rect.Width - (size + strokeWidth))
x = rect.Width - (size + strokeWidth);
var y = (float)((rect.Height - size) / 2);
canvas.FillColor = slider.ThumbColor.WithDefault(slider.IsEnabled ? Colors.White.ToArgbHex() : Colors.Gray.ToArgbHex());
canvas.SetShadow(new SizeF(1, 1), 2, CanvasDefaults.DefaultShadowColor);
canvas.FillEllipse(x, y, size, size);
canvas.DrawEllipse(x, y, size, size);
canvas.RestoreState();
};
}
}
}

Просмотреть файл

@ -0,0 +1,42 @@
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Controls;
namespace GraphicsControls.Sample.Controls
{
public class DrawCustomSlider : Slider
{
}
public class DrawCustomSliderHandler : SliderHandler
{
protected override ISliderDrawable CreateDrawable() => new MaterialSliderDrawable();
public override void Draw(ICanvas canvas, RectangleF dirtyRect)
{
canvas.SaveState();
canvas.FontColor = Fluent.Color.Foreground.Black.ToColor();
canvas.FontSize = 8f;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
var x = dirtyRect.X;
var y = dirtyRect.Y;
canvas.SetToBoldSystemFont();
string valueString = VirtualView.Value.ToString("####0.00");
const float margin = 12.0f;
canvas.DrawString(valueString, x, y, width - margin, height, HorizontalAlignment.Right, VerticalAlignment.Top);
canvas.RestoreState();
base.Draw(canvas, dirtyRect);
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
namespace GraphicsControls.Sample.Controls
{
public enum AvatarSize
{
Small,
Large,
XXLarge
}
}

Просмотреть файл

@ -0,0 +1,61 @@
namespace GraphicsControls.Sample.Controls
{
public static class AvatarSizeExtensions
{
public static int GetAvatarSize(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 48;
case AvatarSize.Large:
return 72;
case AvatarSize.XXLarge:
return 120;
}
}
public static int GetAvatarIndicatorSize(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 12;
case AvatarSize.Large:
return 20;
case AvatarSize.XXLarge:
return 36;
}
}
public static float GetAvatarIndicatorIconScale(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 1.0f;
case AvatarSize.Large:
return 1.5f;
case AvatarSize.XXLarge:
return 2.5f;
}
}
public static int GetInitialsFontSize(this AvatarSize avatarSize)
{
switch (avatarSize)
{
case AvatarSize.Small:
default:
return 20;
case AvatarSize.Large:
return 28;
case AvatarSize.XXLarge:
return 42;
}
}
}
}

Просмотреть файл

@ -0,0 +1,162 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
using Microsoft.Maui.Graphics.Controls;
using System.Diagnostics;
namespace GraphicsControls.Sample.Controls
{
public class Persona : Microsoft.Maui.Graphics.Controls.GraphicsView
{
public Persona()
{
UpdateAvatarSize();
}
public static readonly BindableProperty NameProperty =
BindableProperty.Create(nameof(Name), typeof(string), typeof(Persona), string.Empty);
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public static readonly BindableProperty AvatarSizeProperty =
BindableProperty.Create(nameof(AvatarSize), typeof(AvatarSize), typeof(Persona), AvatarSize.Small,
propertyChanged: OnAvatarSizeChanged);
static void OnAvatarSizeChanged(BindableObject bindable, object oldValue, object newValue)
{
(bindable as Persona)?.UpdateAvatarSize();
}
public AvatarSize AvatarSize
{
get { return (AvatarSize)GetValue(AvatarSizeProperty); }
set { SetValue(AvatarSizeProperty, value); }
}
public override void Draw(ICanvas canvas, RectangleF dirtyRect)
{
base.Draw(canvas, dirtyRect);
DrawBackground(canvas, dirtyRect);
DrawIndicator(canvas, dirtyRect);
DrawInitials(canvas, dirtyRect);
}
public override void OnTouchDown(Point point)
{
Debug.WriteLine($"Touch Down {point}");
}
void DrawBackground(ICanvas canvas, RectangleF dirtyRect)
{
canvas.SaveState();
canvas.FillColor = Color.FromArgb("#4967F5");
var x = dirtyRect.X;
var y = dirtyRect.Y;
var height = AvatarSize.GetAvatarSize();
var width = height;
canvas.FillEllipse(x, y, width, height);
canvas.RestoreState();
}
public virtual void DrawIndicator(ICanvas canvas, RectangleF dirtyRect)
{
canvas.SaveState();
canvas.FillColor = Color.FromArgb("#FFFFFF");
var position = AvatarSize.GetAvatarSize() - AvatarSize.GetAvatarIndicatorSize();
var x = position;
var y = x;
var avatarIndicatorBorderHeight = AvatarSize.GetAvatarIndicatorSize();
var avatarIndicatorBorderWidth = avatarIndicatorBorderHeight;
canvas.FillEllipse(x, y, avatarIndicatorBorderWidth, avatarIndicatorBorderHeight);
canvas.RestoreState();
canvas.SaveState();
var borderWidth = 4;
canvas.FillColor = Color.FromArgb("#6BB700");
var avatarSize = AvatarSize.GetAvatarIndicatorSize() - borderWidth;
var avatarIndicatorFillHeight = avatarSize;
var avatarIndicatorFillWidth = avatarIndicatorFillHeight;
canvas.FillEllipse(x + borderWidth / 2, y + borderWidth / 2, avatarIndicatorFillWidth, avatarIndicatorFillHeight);
canvas.RestoreState();
canvas.SaveState();
var translateX = avatarSize / 4;
var translateY = avatarSize / 3;
canvas.Translate(x + translateX, y + translateY);
var scale = AvatarSize.GetAvatarIndicatorIconScale();
canvas.Scale(scale, scale);
var vBuilder = new PathBuilder();
var path =
vBuilder.BuildPath(
"M6.13281 0.707031C6.24219 0.707031 6.34375 0.727865 6.4375 0.769531C6.53385 0.808594 6.61719 0.863281 6.6875 0.933594C6.75781 1.00391 6.8125 1.08724 6.85156 1.18359C6.89323 1.27734 6.91406 1.37891 6.91406 1.48828C6.91406 1.59245 6.89453 1.69271 6.85547 1.78906C6.81641 1.88542 6.76042 1.97005 6.6875 2.04297L3.58594 5.14844C3.51302 5.22135 3.42839 5.27865 3.33203 5.32031C3.23568 5.35938 3.13542 5.37891 3.03125 5.37891C2.92708 5.37891 2.82682 5.35938 2.73047 5.32031C2.63411 5.27865 2.54948 5.22135 2.47656 5.14844L1.0625 3.73438C0.989583 3.66146 0.932292 3.57682 0.890625 3.48047C0.851562 3.38411 0.832031 3.28385 0.832031 3.17969C0.832031 3.07031 0.852865 2.96875 0.894531 2.875C0.936198 2.77865 0.992188 2.69531 1.0625 2.625C1.13281 2.55469 1.21484 2.5 1.30859 2.46094C1.40495 2.41927 1.50781 2.39844 1.61719 2.39844C1.72135 2.39844 1.82161 2.41797 1.91797 2.45703C2.01432 2.49609 2.09896 2.55208 2.17188 2.625L3.03125 3.48438L5.57812 0.933594C5.65104 0.860677 5.73568 0.804688 5.83203 0.765625C5.92839 0.726562 6.02865 0.707031 6.13281 0.707031Z");
canvas.FillColor = Colors.White;
canvas.FillPath(path);
canvas.RestoreState();
}
void DrawInitials(ICanvas canvas, RectangleF dirtyRect)
{
canvas.SaveState();
canvas.FontColor = Color.FromArgb(Fluent.Color.Foreground.White);
canvas.FontSize = AvatarSize.GetInitialsFontSize();
var height = AvatarSize.GetAvatarSize();
var width = height;
var initials = GetInitials(Name);
canvas.DrawString(initials, 0, 0, width, height, HorizontalAlignment.Center, VerticalAlignment.Center);
canvas.RestoreState();
}
void UpdateAvatarSize() => HeightRequest = WidthRequest = AvatarSize.GetAvatarSize();
string GetInitials(string text)
{
string result = string.Empty;
bool v = true;
for (int i = 0; i < text.Length; i++)
{
if (text[i] == ' ')
v = true;
else if (text[i] != ' ' && v)
{
result += text[i];
v = false;
}
}
return result;
}
}
}

Просмотреть файл

@ -0,0 +1,186 @@
using GraphicsControls.Sample.Controls;
using Microsoft.Maui;
using Microsoft.Maui.Controls;
using Microsoft.Maui.Graphics;
namespace GraphicsControls.Sample
{
public class CustomControlsPage : ContentPage
{
readonly Color PageBackgroundColor = Color.FromArgb("#FFFFFF");
readonly Color SectionHeaderBackgroundColor = Color.FromArgb("#E9E9E9");
readonly Color SectionBackgroundColor = Color.FromArgb("#FAFAFA");
public CustomControlsPage()
{
BackgroundColor = PageBackgroundColor;
var scrollView = new ScrollView();
var verticalStack = new StackLayout() { Margin = 12 };
verticalStack.Add(CreateHeader());
verticalStack.Add(CreateDrawCustomSlider());
//verticalStack.Add(CreateCustomSliderMapper());
verticalStack.Add(CreateCustomSliderDrawable());
verticalStack.Add(CreatePersona());
scrollView.Content = verticalStack;
Content = scrollView;
}
IView CreateHeader()
{
var container = new StackLayout();
container.Add(new Label
{
FontSize = 18,
FontAttributes = FontAttributes.Bold,
Text = "Customize using Microsoft.Maui.Graphics.Controls",
TextColor = Colors.Black,
Margin = new Thickness(0, 24, 0, 0)
});
container.Add(new Label
{
Text = "An example where learn how to customize existing controls as well as create new drawn controls.",
TextColor = Colors.Black
});
return container;
}
IView CreateContainer(string title, View content)
{
var contentContainer = new StackLayout
{
BackgroundColor = SectionBackgroundColor
};
var header = new Label
{
BackgroundColor = SectionHeaderBackgroundColor,
Padding = 12,
Text = title,
TextColor = Colors.Black
};
contentContainer.Children.Add(header);
contentContainer.Children.Add(content);
var container = new Grid
{
BackgroundColor = SectionBackgroundColor,
Padding = 0,
Margin = new Thickness(0, 6)
};
container.Children.Add(contentContainer);
return container;
}
IView CreateDrawCustomSlider()
{
var layout = new StackLayout
{
Margin = new Thickness(12, 6, 12, 24)
};
layout.Children.Add(new Label { FontSize = 9, TextColor = Colors.Gray, Text = "Draw custom Slider" });
var drawCustomSlider = new DrawCustomSlider
{
Minimum = 0,
Maximum = 10,
Value = 4
};
layout.Children.Add(drawCustomSlider);
return CreateContainer("DrawCustomSlider", layout);
}
IView CreateCustomSliderMapper()
{
var layout = new StackLayout
{
Margin = new Thickness(12, 6, 12, 24)
};
layout.Children.Add(new Label { FontSize = 9, TextColor = Colors.Gray, Text = "Custom Slider using Mapper" });
var customSliderMapper = new CustomSliderMapper
{
Minimum = 0,
Maximum = 10,
Value = 4
};
layout.Children.Add(customSliderMapper);
return CreateContainer("CustomSliderMapper", layout);
}
IView CreateCustomSliderDrawable()
{
var layout = new StackLayout
{
Margin = new Thickness(12, 6, 12, 24)
};
layout.Children.Add(new Label { FontSize = 9, TextColor = Colors.Gray, Text = "Custom Slider using a custom Drawable" });
var customSliderMapper = new CustomSliderDrawable
{
Minimum = 0,
Maximum = 10,
Value = 4
};
layout.Children.Add(customSliderMapper);
return CreateContainer("CustomSliderDrawable", layout);
}
IView CreatePersona()
{
var layout = new StackLayout
{
Margin = new Thickness(12, 6, 12, 24)
};
layout.Children.Add(new Label { FontSize = 9, TextColor = Colors.Gray, Text = "Fluent Persona control" });
var persona1 = new Persona
{
Name = "Javier Suarez",
AvatarSize = AvatarSize.Small,
Margin = new Thickness(0, 6)
};
var persona2 = new Persona
{
Name = "David Ortinau",
AvatarSize = AvatarSize.Large,
Margin = new Thickness(0, 6)
};
var persona3 = new Persona
{
Name = "Jhon Dick",
AvatarSize = AvatarSize.XXLarge,
Margin = new Thickness(0, 6)
};
layout.Children.Add(persona1);
layout.Children.Add(persona2);
layout.Children.Add(persona3);
return CreateContainer("Persona", layout);
}
}
}

Просмотреть файл

@ -3,11 +3,13 @@
<PropertyGroup>
<!-- iOS, Android, MacCatalyst -->
<TargetFrameworks>net6.0-ios;net6.0-android;net6.0-maccatalyst</TargetFrameworks>
<RuntimeIdentifiers Condition="$(TargetFramework.Contains('-android'))">android-arm;android-arm64;android-x86;android-x64</RuntimeIdentifiers>
<OutputType>Exe</OutputType>
<UseMaui>true</UseMaui>
<SingleProject>true</SingleProject>
<RootNamespace>GraphicsControls.Sample</RootNamespace>
<EnablePreviewMsixTooling>true</EnablePreviewMsixTooling>
<!-- Display name -->
<ApplicationTitle>GraphicsControls.Sample</ApplicationTitle>

Просмотреть файл

@ -81,7 +81,6 @@ namespace GraphicsControls.Sample
var container = new Grid
{
BackgroundColor = SectionBackgroundColor,
IsClippedToBounds = true,
Padding = 0,
Margin = new Thickness(0, 6)
};

Просмотреть файл

@ -0,0 +1,31 @@
using Microsoft.Maui;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Graphics.Controls.Hosting;
using Microsoft.Maui.Controls.Xaml;
using Microsoft.Maui.Hosting;
using GraphicsControls.Sample.Controls;
[assembly: XamlCompilationAttribute(XamlCompilationOptions.Compile)]
namespace GraphicsControls.Sample
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var appBuilder = MauiApp.CreateBuilder();
appBuilder
.UseMauiApp<App>()
.ConfigureGraphicsControls()
.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(CustomSliderDrawable), typeof(CustomSliderDrawableHandler));
handlers.AddHandler(typeof(CustomSliderMapper), typeof(CustomSliderMapperHandler));
handlers.AddHandler(typeof(DrawCustomSlider), typeof(DrawCustomSliderHandler));
});
return appBuilder.Build();
}
}
}

Просмотреть файл

@ -6,8 +6,11 @@ namespace GraphicsControls.Sample
{
[Activity(
Theme = "@style/Maui.SplashTheme",
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode | ConfigChanges.ScreenLayout | ConfigChanges.SmallestScreenSize)]
MainLauncher = true,
ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation | ConfigChanges.UiMode)]
[IntentFilter(
new[] { Microsoft.Maui.Essentials.Platform.Intent.ActionAppAction },
Categories = new[] { Android.Content.Intent.CategoryDefault })]
public class MainActivity : MauiAppCompatActivity
{
}

Просмотреть файл

@ -6,11 +6,13 @@ using System;
namespace GraphicsControls.Sample
{
[Application]
public class MainApplication : MauiApplication<Startup>
public class MainApplication : MauiApplication
{
public MainApplication(IntPtr handle, JniHandleOwnership ownership)
: base(handle, ownership)
{
}
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}

Просмотреть файл

@ -4,7 +4,8 @@ using Microsoft.Maui;
namespace GraphicsControls.Sample
{
[Register("AppDelegate")]
public class AppDelegate : MauiUIApplicationDelegate<Startup>
public class AppDelegate : MauiUIApplicationDelegate
{
protected override MauiApp CreateMauiApp() => MauiProgram.CreateMauiApp();
}
}

Просмотреть файл

@ -1,20 +0,0 @@
using Microsoft.Maui;
using Microsoft.Maui.Controls.Hosting;
using Microsoft.Maui.Hosting;
using Microsoft.Maui.Graphics.Controls.Hosting;
using Microsoft.Maui.Controls.Xaml;
[assembly: XamlCompilationAttribute(XamlCompilationOptions.Compile)]
namespace GraphicsControls.Sample
{
public class Startup : IStartup
{
public void Configure(IAppHostBuilder appBuilder)
{
appBuilder
.UseMauiApp<App>()
.ConfigureGraphicsControls();
}
}
}

Просмотреть файл

@ -15,7 +15,7 @@
<PackageId>Microsoft.Maui.Graphics.Controls</PackageId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Maui.Graphics" Version="6.0.100-preview.6.299" />
<PackageReference Include="Microsoft.Maui.Graphics" Version="6.0.100-rc.1.382" />
</ItemGroup>
<Import Project="..\..\Microsoft.Maui.Graphics.Controls.MultiTargeting.targets" />
</Project>

Просмотреть файл

@ -10,15 +10,12 @@ namespace Microsoft.Maui.Graphics.Controls
public static PropertyMapper<IButton> PropertyMapper = new PropertyMapper<IButton>(ViewHandler.Mapper)
{
Actions =
{
[nameof(IButton.Background)] = ViewHandler.MapInvalidate,
[nameof(IButton.Text)] = ViewHandler.MapInvalidate,
[nameof(IButton.TextColor)] = ViewHandler.MapInvalidate,
[nameof(IButton.Font)] = ViewHandler.MapInvalidate,
[nameof(IButton.CharacterSpacing)] = ViewHandler.MapInvalidate,
[nameof(IButton.Padding)] = ViewHandler.MapInvalidate
}
[nameof(IButton.Background)] = ViewHandler.MapInvalidate,
[nameof(IButton.Text)] = ViewHandler.MapInvalidate,
[nameof(IButton.TextColor)] = ViewHandler.MapInvalidate,
[nameof(IButton.Font)] = ViewHandler.MapInvalidate,
[nameof(IButton.CharacterSpacing)] = ViewHandler.MapInvalidate,
[nameof(IButton.Padding)] = ViewHandler.MapInvalidate
};
public static DrawMapper<IButtonDrawable, IButton> DrawMapper = new DrawMapper<IButtonDrawable, IButton>(ViewHandler.DrawMapper)

Просмотреть файл

@ -6,10 +6,7 @@ namespace Microsoft.Maui.Graphics.Controls
{
public static PropertyMapper<ICheckBox> PropertyMapper = new PropertyMapper<ICheckBox>(ViewHandler.Mapper)
{
Actions =
{
[nameof(ICheckBox.IsChecked)] = ViewHandler.MapInvalidate
}
[nameof(ICheckBox.IsChecked)] = ViewHandler.MapInvalidate
};
public static DrawMapper<ICheckBoxDrawable, ICheckBox> DrawMapper = new DrawMapper<ICheckBoxDrawable, ICheckBox>(ViewHandler.DrawMapper)

Просмотреть файл

@ -11,14 +11,15 @@
else
canvas.FillColor = datePicker.IsEnabled ? Material.Color.Gray5.ToColor() : Material.Color.Gray3.ToColor();
const float cornerRadius = 4.0f;
var x = dirtyRect.X;
var y = dirtyRect.Y;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
var vBuilder = new PathBuilder();
var path =
vBuilder.BuildPath(
$"M0 4C0 1.79086 1.79086 0 4 0H{width - 4}C{width - 2}.209 0 {width} 1.79086 {width} 4V56H0V4Z");
canvas.FillPath(path);
canvas.FillRoundedRectangle(x, y, width, height, cornerRadius, cornerRadius, 0, 0);
canvas.RestoreState();
}

Просмотреть файл

@ -63,6 +63,11 @@ namespace Microsoft.Maui.Graphics.Controls
if (!(Drawable is MaterialEditorDrawable))
return;
bool hasText = !string.IsNullOrEmpty(VirtualView.Text);
if (hasText)
return;
if (_animationManager == null)
_animationManager = MauiContext?.Services.GetRequiredService<IAnimationManager>();

Просмотреть файл

@ -22,14 +22,15 @@ namespace Microsoft.Maui.Graphics.Controls
else
canvas.FillColor = editor.IsEnabled ? Material.Color.Gray5.ToColor() : Material.Color.Gray3.ToColor();
const float cornerRadius = 4.0f;
var x = dirtyRect.X;
var y = dirtyRect.Y;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
var vBuilder = new PathBuilder();
var path =
vBuilder.BuildPath(
$"M0 4C0 1.79086 1.79086 0 4 0H{width - 4}C{width - 2}.209 0 {width} 1.79086 {width} 4V114.95H0V4Z");
canvas.FillPath(path);
canvas.FillRoundedRectangle(x, y, width, height, cornerRadius, cornerRadius, 0, 0);
canvas.RestoreState();
}

Просмотреть файл

@ -72,6 +72,11 @@ namespace Microsoft.Maui.Graphics.Controls
if (!(Drawable is MaterialEntryDrawable))
return;
bool hasText = !string.IsNullOrEmpty(VirtualView.Text);
if (hasText)
return;
if (_animationManager == null)
_animationManager = MauiContext?.Services.GetRequiredService<IAnimationManager>();

Просмотреть файл

@ -28,14 +28,15 @@ namespace Microsoft.Maui.Graphics.Controls
else
canvas.FillColor = entry.IsEnabled ? Material.Color.Gray5.ToColor() : Material.Color.Gray3.ToColor();
const float cornerRadius = 4.0f;
var x = dirtyRect.X;
var y = dirtyRect.Y;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
var vBuilder = new PathBuilder();
var path =
vBuilder.BuildPath(
$"M0 4C0 1.79086 1.79086 0 4 0H{width - 4}C{width - 2}.209 0 {width} 1.79086 {width} 4V56H0V4Z");
canvas.FillPath(path);
canvas.FillRoundedRectangle(x, y, width, height, cornerRadius, cornerRadius, 0, 0);
canvas.RestoreState();
}

Просмотреть файл

@ -0,0 +1,111 @@
using Microsoft.Maui.Controls;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Microsoft.Maui.Graphics.Controls
{
public abstract class GraphicsView : ContentView, IGraphicsView, IGraphicsLayerManager
{
public GraphicsView()
{
GraphicsLayers = new List<string>();
}
public virtual List<string> GraphicsLayers { get; }
public event EventHandler Loaded;
public event EventHandler Unloaded;
public event EventHandler TouchDown;
public event EventHandler TouchMove;
public event EventHandler TouchUp;
[EditorBrowsable(EditorBrowsableState.Never)]
public event EventHandler Invalidated;
public void InvalidateDraw() => Invalidated?.Invoke(this, EventArgs.Empty);
public virtual void Draw(ICanvas canvas, RectangleF dirtyRect)
{
foreach (var layer in GraphicsLayers)
DrawLayer(layer, canvas, dirtyRect);
}
public virtual void DrawLayer(string layer, ICanvas canvas, RectangleF dirtyRect)
{
}
public virtual void Load()
{
Loaded?.Invoke(this, EventArgs.Empty);
}
public virtual void Unload()
{
Unloaded?.Invoke(this, EventArgs.Empty);
}
public virtual void OnTouchDown(Point point)
{
TouchDown?.Invoke(this, EventArgs.Empty);
}
public virtual void OnTouchMove(Point point)
{
TouchMove?.Invoke(this, EventArgs.Empty);
}
public virtual void OnTouchUp(Point point)
{
TouchUp?.Invoke(this, EventArgs.Empty);
}
public int GetLayerIndex(string layerName)
{
for (int i = 0; i < GraphicsLayers.Count(); i++)
if (GraphicsLayers.ElementAt(i) == layerName)
return i;
return -1;
}
public void AddLayer(string layer)
{
GraphicsLayers.Add(layer);
InvalidateDraw();
}
public void AddLayer(int index, string layer)
{
GraphicsLayers.Insert(index, layer);
InvalidateDraw();
}
public void RemoveLayer(string layerName)
{
for (int i = 0; i < GraphicsLayers.Count(); i++)
{
if (GraphicsLayers.ElementAt(i) == layerName)
{
GraphicsLayers.RemoveAt(i);
InvalidateDraw();
break;
}
}
}
public void RemoveLayer(int index)
{
GraphicsLayers.RemoveAt(index);
InvalidateDraw();
}
}
}

Просмотреть файл

@ -0,0 +1,73 @@
using Android.Views;
using Microsoft.Maui.Graphics.Native;
using Microsoft.Maui.Handlers;
using APointF = Android.Graphics.PointF;
namespace Microsoft.Maui.Graphics.Controls
{
public partial class GraphicsViewHandler : ViewHandler<IGraphicsView, NativeGraphicsView>
{
protected override NativeGraphicsView CreateNativeView()
{
var nativeGraphicsView = new NativeGraphicsView(Context)
{
Drawable = VirtualView
};
return nativeGraphicsView;
}
protected override void ConnectHandler(NativeGraphicsView nativeView)
{
base.ConnectHandler(nativeView);
nativeView.ViewAttachedToWindow += OnViewAttachedToWindow;
nativeView.ViewDetachedFromWindow += OnViewDetachedFromWindow;
nativeView.Touch += OnTouch;
}
protected override void DisconnectHandler(NativeGraphicsView nativeView)
{
base.DisconnectHandler(nativeView);
nativeView.ViewAttachedToWindow -= OnViewAttachedToWindow;
nativeView.ViewDetachedFromWindow -= OnViewDetachedFromWindow;
nativeView.Touch -= OnTouch;
}
void OnViewAttachedToWindow(object? sender, View.ViewAttachedToWindowEventArgs e)
{
VirtualView?.Load();
}
void OnViewDetachedFromWindow(object? sender, View.ViewDetachedFromWindowEventArgs e)
{
VirtualView?.Unload();
}
void OnTouch(object? sender, View.TouchEventArgs e)
{
if (e.Event == null)
return;
float density = Context?.Resources?.DisplayMetrics?.Density ?? 1.0f;
APointF point = new APointF(e.Event.GetX() / density, e.Event.GetY() / density);
switch (e.Event.Action)
{
case MotionEventActions.Down:
VirtualView?.OnTouchDown(new Point(point.X, point.Y));
break;
case MotionEventActions.Move:
VirtualView?.OnTouchMove(new Point(point.X, point.Y));
break;
case MotionEventActions.Up:
case MotionEventActions.Cancel:
VirtualView?.OnTouchUp(new Point(point.X, point.Y));
break;
default:
break;
}
}
}
}

Просмотреть файл

@ -0,0 +1,9 @@
using System;
namespace Microsoft.Maui.Graphics.Controls
{
public partial class GraphicsViewHandler : ViewHandler<IGraphicsView, object>
{
protected override object CreateNativeView() => throw new NotImplementedException();
}
}

Просмотреть файл

@ -0,0 +1,100 @@
using Microsoft.Maui.Graphics.Win2D;
using Microsoft.Maui.Handlers;
using Microsoft.UI.Xaml.Input;
using System;
using System.Diagnostics;
namespace Microsoft.Maui.Graphics.Controls
{
public partial class GraphicsViewHandler : ViewHandler<IGraphicsView, W2DGraphicsView>
{
protected override W2DGraphicsView CreateNativeView() => new W2DGraphicsView
{
Drawable = VirtualView
};
protected override void ConnectHandler(W2DGraphicsView nativeView)
{
base.ConnectHandler(nativeView);
nativeView.PointerPressed += OnPointerPressed;
nativeView.PointerMoved += OnPointerMoved;
nativeView.PointerReleased += OnPointerReleased;
nativeView.PointerCanceled += OnPointerCanceled;
}
protected override void DisconnectHandler(W2DGraphicsView nativeView)
{
base.DisconnectHandler(nativeView);
nativeView.PointerPressed -= OnPointerPressed;
nativeView.PointerMoved -= OnPointerMoved;
nativeView.PointerReleased -= OnPointerReleased;
nativeView.PointerCanceled -= OnPointerCanceled;
}
void OnPointerPressed(object sender, PointerRoutedEventArgs e)
{
try
{
var currentPoint = e.GetCurrentPoint(NativeView);
var currentPosition = currentPoint.Position;
var point = new Point(currentPosition.X, currentPosition.Y);
VirtualView?.OnTouchDown(point);
}
catch (Exception exc)
{
Debug.WriteLine("An unexpected error occured handling a touch event within the control.", exc);
}
}
void OnPointerMoved(object sender, PointerRoutedEventArgs e)
{
try
{
var currentPoint = e.GetCurrentPoint(NativeView);
var currentPosition = currentPoint.Position;
var point = new Point(currentPosition.X, currentPosition.Y);
VirtualView?.OnTouchMove(point);
}
catch (Exception exc)
{
Debug.WriteLine("An unexpected error occured handling a touch moved event within the control.", exc);
}
}
void OnPointerReleased(object sender, PointerRoutedEventArgs e)
{
try
{
var currentPoint = e.GetCurrentPoint(NativeView);
var currentPosition = currentPoint.Position;
var point = new Point(currentPosition.X, currentPosition.Y);
VirtualView?.OnTouchUp(point);
}
catch (Exception exc)
{
Debug.WriteLine("An unexpected error occured handling a touch ended event within the control.", exc);
}
}
void OnPointerCanceled(object sender, PointerRoutedEventArgs e)
{
try
{
var currentPoint = e.GetCurrentPoint(NativeView);
var currentPosition = currentPoint.Position;
var point = new Point(currentPosition.X, currentPosition.Y);
VirtualView?.OnTouchUp(point);
}
catch (Exception exc)
{
Debug.WriteLine("An unexpected error occured cancelling the touches within the control.", exc);
}
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
namespace Microsoft.Maui.Graphics.Controls
{
public partial class GraphicsViewHandler
{
public static IPropertyMapper<IGraphicsView, GraphicsViewHandler> GraphicsViewMapper = new PropertyMapper<IGraphicsView, GraphicsViewHandler>(ViewMapper);
public GraphicsViewHandler() : base(GraphicsViewMapper)
{
}
public GraphicsViewHandler(IPropertyMapper mapper) : base(mapper ?? GraphicsViewMapper)
{
}
}
}

Просмотреть файл

@ -0,0 +1,142 @@
using Foundation;
using Microsoft.Maui.Graphics.Native;
using Microsoft.Maui.Handlers;
using System;
using UIKit;
namespace Microsoft.Maui.Graphics.Controls
{
public class TouchEventArgs : EventArgs
{
public TouchEventArgs(Point point)
{
Point = point;
}
public Point Point { get; set; }
}
public class TouchNativeGraphicsView : NativeGraphicsView
{
public event EventHandler<TouchEventArgs> TouchDown;
public event EventHandler<TouchEventArgs> TouchMove;
public event EventHandler<TouchEventArgs> TouchUp;
public override void TouchesBegan(NSSet touches, UIEvent? evt)
{
base.TouchesBegan(touches, evt);
var viewPoints = this.GetPointsInView(evt);
PointF viewPoint = viewPoints.Length > 0 ? viewPoints[0] : PointF.Zero;
var point = new Point(viewPoint.X, viewPoint.Y);
TouchDown?.Invoke(this, new TouchEventArgs(point));
}
public override void TouchesMoved(NSSet touches, UIEvent? evt)
{
base.TouchesMoved(touches, evt);
var viewPoints = this.GetPointsInView(evt);
PointF viewPoint = viewPoints.Length > 0 ? viewPoints[0] : PointF.Zero;
var point = new Point(viewPoint.X, viewPoint.Y);
TouchMove?.Invoke(this, new TouchEventArgs(point));
}
public override void TouchesEnded(NSSet touches, UIEvent? evt)
{
base.TouchesEnded(touches, evt);
var viewPoints = this.GetPointsInView(evt);
PointF viewPoint = viewPoints.Length > 0 ? viewPoints[0] : PointF.Zero;
var point = new Point(viewPoint.X, viewPoint.Y);
TouchUp?.Invoke(this, new TouchEventArgs(point));
}
public override void TouchesCancelled(NSSet touches, UIEvent? evt)
{
base.TouchesCancelled(touches, evt);
var viewPoints = this.GetPointsInView(evt);
PointF viewPoint = viewPoints.Length > 0 ? viewPoints[0] : PointF.Zero;
var point = new Point(viewPoint.X, viewPoint.Y);
TouchUp?.Invoke(this, new TouchEventArgs(point));
}
}
public partial class GraphicsViewHandler : ViewHandler<IGraphicsView, TouchNativeGraphicsView>
{
const NSKeyValueObservingOptions observingOptions = NSKeyValueObservingOptions.Initial | NSKeyValueObservingOptions.OldNew | NSKeyValueObservingOptions.Prior;
IDisposable? _isLoadedObserverDisposable;
protected override TouchNativeGraphicsView CreateNativeView()
{
var nativeGraphicsView = new TouchNativeGraphicsView
{
UserInteractionEnabled = true,
BackgroundColor = UIColor.Clear,
Drawable = VirtualView
};
return nativeGraphicsView;
}
protected override void ConnectHandler(TouchNativeGraphicsView nativeView)
{
base.ConnectHandler(nativeView);
var key = nativeView.Superview == null ? "subviews" : "superview";
_isLoadedObserverDisposable = nativeView.AddObserver(key, observingOptions, OnViewLoadedObserver);
nativeView.TouchDown += OnTouchDown;
nativeView.TouchMove += OnTouchMove;
nativeView.TouchUp += OnTouchUp;
}
protected override void DisconnectHandler(TouchNativeGraphicsView nativeView)
{
base.DisconnectHandler(nativeView);
_isLoadedObserverDisposable?.Dispose();
_isLoadedObserverDisposable = null;
nativeView.TouchDown -= OnTouchDown;
nativeView.TouchMove -= OnTouchMove;
nativeView.TouchUp -= OnTouchUp;
}
void OnViewLoadedObserver(NSObservedChange nSObservedChange)
{
if (!nSObservedChange?.NewValue?.Equals(NSNull.Null) ?? false)
{
VirtualView?.Load();
}
else if (!nSObservedChange?.OldValue?.Equals(NSNull.Null) ?? false)
{
VirtualView?.Unload();
_isLoadedObserverDisposable?.Dispose();
_isLoadedObserverDisposable = null;
}
}
void OnTouchDown(object? sender, TouchEventArgs e)
{
VirtualView?.OnTouchDown(e.Point);
}
void OnTouchMove(object? sender, TouchEventArgs e)
{
VirtualView?.OnTouchMove(e.Point);
}
void OnTouchUp(object? sender, TouchEventArgs e)
{
VirtualView?.OnTouchUp(e.Point);
}
}
}

Просмотреть файл

@ -0,0 +1,15 @@
namespace Microsoft.Maui.Graphics.Controls
{
public interface IGraphicsLayerManager
{
int GetLayerIndex(string layerName);
void AddLayer(string layer);
void AddLayer(int index, string layer);
void RemoveLayer(string layer);
void RemoveLayer(int index);
}
}

Просмотреть файл

@ -0,0 +1,21 @@
using System;
namespace Microsoft.Maui.Graphics.Controls
{
public interface IGraphicsView : IView, IDrawable
{
event EventHandler Loaded;
event EventHandler Unloaded;
event EventHandler TouchDown;
event EventHandler TouchMove;
event EventHandler TouchUp;
void Load();
void Unload();
void OnTouchDown(Point point);
void OnTouchMove(Point point);
void OnTouchUp(Point point);
}
}

Просмотреть файл

@ -6,10 +6,7 @@ namespace Microsoft.Maui.Graphics.Controls
{
public static PropertyMapper<IProgress> PropertyMapper = new PropertyMapper<IProgress>(ViewHandler.Mapper)
{
Actions =
{
[nameof(IProgress.Progress)] = ViewHandler.MapInvalidate
}
[nameof(IProgress.Progress)] = ViewHandler.MapInvalidate
};
public static DrawMapper<IProgressBarDrawable, IProgress> DrawMapper = new DrawMapper<IProgressBarDrawable, IProgress>(ViewHandler.DrawMapper)

Просмотреть файл

@ -8,14 +8,11 @@ namespace Microsoft.Maui.Graphics.Controls
public static PropertyMapper<ISlider> PropertyMapper = new PropertyMapper<ISlider>(ViewHandler.Mapper)
{
Actions =
{
[nameof(ISlider.Value)] = ViewHandler.MapInvalidate,
[nameof(ISlider.Value)] = ViewHandler.MapInvalidate,
[nameof(ISlider.ThumbColor)] = ViewHandler.MapInvalidate,
[nameof(ISlider.MaximumTrackColor)] = ViewHandler.MapInvalidate,
[nameof(ISlider.MinimumTrackColor)] = ViewHandler.MapInvalidate,
}
[nameof(ISlider.Value)] = ViewHandler.MapInvalidate,
[nameof(ISlider.Value)] = ViewHandler.MapInvalidate,
[nameof(ISlider.ThumbColor)] = ViewHandler.MapInvalidate,
[nameof(ISlider.MaximumTrackColor)] = ViewHandler.MapInvalidate,
[nameof(ISlider.MinimumTrackColor)] = ViewHandler.MapInvalidate,
};
public static DrawMapper<ISliderDrawable, ISlider> DrawMapper = new DrawMapper<ISliderDrawable, ISlider>(ViewHandler.DrawMapper)

Просмотреть файл

@ -10,13 +10,10 @@ namespace Microsoft.Maui.Graphics.Controls
public static PropertyMapper<IStepper> PropertyMapper = new PropertyMapper<IStepper>(ViewHandler.Mapper)
{
Actions =
{
[nameof(IStepper.Minimum)] = ViewHandler.MapInvalidate,
[nameof(IStepper.Maximum)] = ViewHandler.MapInvalidate,
[nameof(IStepper.Interval)] = ViewHandler.MapInvalidate,
[nameof(IStepper.Value)] = ViewHandler.MapInvalidate
}
[nameof(IStepper.Minimum)] = ViewHandler.MapInvalidate,
[nameof(IStepper.Maximum)] = ViewHandler.MapInvalidate,
[nameof(IStepper.Interval)] = ViewHandler.MapInvalidate,
[nameof(IStepper.Value)] = ViewHandler.MapInvalidate
};
public static DrawMapper<IStepperDrawable, IStepper> DrawMapper = new DrawMapper<IStepperDrawable, IStepper>(ViewHandler.DrawMapper)

Просмотреть файл

@ -13,14 +13,15 @@ namespace Microsoft.Maui.Graphics.Controls
else
canvas.FillColor = timePicker.IsEnabled ? Material.Color.Gray5.ToColor() : Material.Color.Gray3.ToColor();
const float cornerRadius = 4.0f;
var x = dirtyRect.X;
var y = dirtyRect.Y;
var height = dirtyRect.Height;
var width = dirtyRect.Width;
var vBuilder = new PathBuilder();
var path =
vBuilder.BuildPath(
$"M0 4C0 1.79086 1.79086 0 4 0H{width - 4}C{width - 2}.209 0 {width} 1.79086 {width} 4V56H0V4Z");
canvas.FillPath(path);
canvas.FillRoundedRectangle(x, y, width, height, cornerRadius, cornerRadius, 0, 0);
canvas.RestoreState();
}

Просмотреть файл

@ -33,8 +33,8 @@
return;
canvas.FontColor = text.TextColor ?? Colors.Black;
canvas.FontName = text.Font.FontFamily;
canvas.FontSize = (float)text.Font.FontSize;
canvas.FontName = text.Font.Family;
canvas.FontSize = (float)text.Font.Size;
var horizontal =
((text as ITextAlignment)?.HorizontalTextAlignment ?? TextAlignment.Center) switch

Просмотреть файл

@ -48,7 +48,7 @@ namespace Microsoft.Maui.Graphics.Controls
public static void DrawOverlay(ICanvas canvas, RectangleF dirtyRect, IViewDrawable drawable, IView view) =>
drawable.DrawOverlay(canvas, dirtyRect, view);
public static readonly PropertyMapper<IView> Mapper = new PropertyMapper<IView>(Handlers.ViewHandler.ViewMapper)
public static readonly PropertyMapper<IView, IElementHandler> Mapper = new PropertyMapper<IView, IElementHandler>(Handlers.ViewHandler.ViewMapper)
{
[nameof(IView.AutomationId)] = MapAutomationId,
[nameof(IView.Background)] = MapInvalidate,

Просмотреть файл

@ -1,27 +1,40 @@
using Microsoft.Maui.Controls;
using Microsoft.Maui.Hosting;
#if __ANDROID__ || __IOS__ || MACCATALYST
using Microsoft.Maui.Graphics.Native;
#elif WINDOWS
using Microsoft.Maui.Graphics.Win2D;
#endif
namespace Microsoft.Maui.Graphics.Controls.Hosting
{
public static class AppHostBuilderExtensions
{
public static IAppHostBuilder ConfigureGraphicsControls(this IAppHostBuilder builder)
public static MauiAppBuilder ConfigureGraphicsControls(this MauiAppBuilder builder)
{
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(Button), typeof(ButtonHandler));
handlers.AddHandler(typeof(CheckBox), typeof(CheckBoxHandler));
handlers.AddHandler(typeof(DatePicker), typeof(DatePickerHandler));
handlers.AddHandler(typeof(Editor), typeof(EditorHandler));
handlers.AddHandler(typeof(Entry), typeof(EntryHandler));
handlers.AddHandler(typeof(ProgressBar), typeof(ProgressBarHandler));
handlers.AddHandler(typeof(Slider), typeof(SliderHandler));
handlers.AddHandler(typeof(Stepper), typeof(StepperHandler));
handlers.AddHandler(typeof(Switch), typeof(SwitchHandler));
handlers.AddHandler(typeof(TimePicker), typeof(TimePickerHandler));
});
#if __ANDROID__ || __IOS__ || __MACCATALYST__
GraphicsPlatform.RegisterGlobalService(NativeGraphicsService.Instance);
#elif WINDOWS
GraphicsPlatform.RegisterGlobalService(W2DGraphicsService.Instance);
#endif
builder.ConfigureMauiHandlers(handlers =>
{
handlers.AddHandler(typeof(Button), typeof(ButtonHandler));
handlers.AddHandler(typeof(CheckBox), typeof(CheckBoxHandler));
handlers.AddHandler(typeof(DatePicker), typeof(DatePickerHandler));
handlers.AddHandler(typeof(Editor), typeof(EditorHandler));
handlers.AddHandler(typeof(Entry), typeof(EntryHandler));
handlers.AddHandler(typeof(GraphicsView), typeof(GraphicsViewHandler));
handlers.AddHandler(typeof(ProgressBar), typeof(ProgressBarHandler));
handlers.AddHandler(typeof(Slider), typeof(SliderHandler));
handlers.AddHandler(typeof(Stepper), typeof(StepperHandler));
handlers.AddHandler(typeof(Switch), typeof(SwitchHandler));
handlers.AddHandler(typeof(TimePicker), typeof(TimePickerHandler));
});
return builder;
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,31 @@
using Android.Text;
using System;
namespace Microsoft.Maui.Graphics.Controls
{
public static class TextInputExtensions
{
public static void UpdateText(this ITextInput textInput, string? text)
{
// Even though <null> is technically different to "", it has no
// functional difference to apps. Thus, hide it.
var mauiText = textInput.Text ?? string.Empty;
var nativeText = text ?? string.Empty;
if (mauiText != nativeText)
textInput.Text = nativeText;
}
public static void UpdateText(this ITextInput textInput, TextChangedEventArgs e)
{
if (e.BeforeCount == 0 && e.AfterCount == 0)
return;
if (e.Text is Java.Lang.ICharSequence cs)
textInput.UpdateText(cs.ToString());
else if (e.Text != null)
textInput.UpdateText(String.Concat(e.Text));
else
textInput.UpdateText((string?)null);
}
}
}