Added samples to showcase how to customize existing controls and create new ones
This commit is contained in:
Родитель
24212c1e87
Коммит
fcad11ceca
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче