Merge pull request #43 from jsuarezruiz/button
Implement Button (Cupertino, Material and Fluent) on AlohaKit UI
This commit is contained in:
Коммит
33f9302814
|
@ -67,5 +67,12 @@
|
|||
X="100" Y="200"
|
||||
Data="M 10,100 L 100,100 100,50Z"
|
||||
Stroke="Black" />
|
||||
<alohakit:Button
|
||||
X="250" Y="200"
|
||||
Background="Blue"
|
||||
WidthRequest="150"
|
||||
Text="Button"
|
||||
TextColor="White"
|
||||
Clicked="OnButtonClicked"/>
|
||||
</alohakit:CanvasView>
|
||||
</ContentPage>
|
||||
|
|
|
@ -9,7 +9,12 @@
|
|||
|
||||
void OnEllipseTapped(object sender, EventArgs e)
|
||||
{
|
||||
DisplayAlert("Gestures", "Ellipse tapped.", "Ok");
|
||||
DisplayAlert("Gestures", "Ellipse Tapped.", "Ok");
|
||||
}
|
||||
|
||||
void OnButtonClicked(object sender, EventArgs e)
|
||||
{
|
||||
DisplayAlert("Button", "Button Clicked.", "Ok");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
using Microsoft.Maui;
|
||||
using Microsoft.Maui.Graphics.Text;
|
||||
|
||||
namespace AlohaKit.UI
|
||||
{
|
||||
public abstract class ButtonBase : View
|
||||
{
|
||||
public static readonly BindableProperty TextProperty =
|
||||
BindableProperty.Create(nameof(Text), typeof(string), typeof(ButtonBase), string.Empty,
|
||||
propertyChanged: InvalidatePropertyChanged);
|
||||
|
||||
public static readonly BindableProperty TextColorProperty =
|
||||
BindableProperty.Create(nameof(TextColor), typeof(Color), typeof(ButtonBase), null,
|
||||
propertyChanged: InvalidatePropertyChanged);
|
||||
|
||||
public static readonly BindableProperty FontSizeProperty =
|
||||
BindableProperty.Create(nameof(FontSize), typeof(double), typeof(ButtonBase), 14.0d,
|
||||
propertyChanged: InvalidatePropertyChanged);
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set => SetValue(TextProperty, value);
|
||||
}
|
||||
|
||||
public Color TextColor
|
||||
{
|
||||
get => (Color)GetValue(TextColorProperty);
|
||||
set => SetValue(TextColorProperty, value);
|
||||
}
|
||||
|
||||
public double FontSize
|
||||
{
|
||||
get => (double)GetValue(FontSizeProperty);
|
||||
set => SetValue(FontSizeProperty, value);
|
||||
}
|
||||
|
||||
public event EventHandler Clicked;
|
||||
public event EventHandler Pressed;
|
||||
public event EventHandler Released;
|
||||
|
||||
public override void StartInteraction(PointF[] points)
|
||||
{
|
||||
base.StartInteraction(points);
|
||||
|
||||
Pressed?.Invoke(this, EventArgs.Empty);
|
||||
Clicked?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
public override void EndInteraction(PointF[] points, bool isInsideBounds)
|
||||
{
|
||||
base.EndInteraction(points, isInsideBounds);
|
||||
|
||||
Released?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
public class Button :
|
||||
#if ANDROID
|
||||
Material.Button
|
||||
#elif IOS || MACCATALYST
|
||||
Cupertino.Button
|
||||
#elif WINDOWS
|
||||
Fluent.Button
|
||||
#else
|
||||
Material.Button
|
||||
#endif
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -21,19 +21,27 @@ namespace AlohaKit.UI
|
|||
}
|
||||
}
|
||||
|
||||
public interface ICanvasView
|
||||
{
|
||||
void Draw(ICanvas canvas, RectF bounds);
|
||||
void Invalidate();
|
||||
}
|
||||
|
||||
[ContentProperty(nameof(Children))]
|
||||
public class CanvasView : GraphicsView
|
||||
public class CanvasView : GraphicsView, ICanvasView, IDisposable
|
||||
{
|
||||
public CanvasView()
|
||||
{
|
||||
Children = new ElementsCollection();
|
||||
Children = new ElementsCollection(this);
|
||||
|
||||
Drawable = new CanvasViewDrawable(this);
|
||||
|
||||
StartInteraction += OnCanvasViewStartInteraction;
|
||||
}
|
||||
EndInteraction += OnCanvasViewEndInteraction;
|
||||
CancelInteraction += OnCanvasViewCancelInteraction;
|
||||
}
|
||||
|
||||
public ElementsCollection Children { get; internal set; }
|
||||
public ElementsCollection Children { get; internal set; }
|
||||
|
||||
internal void DrawCore(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
|
@ -51,14 +59,23 @@ namespace AlohaKit.UI
|
|||
}
|
||||
}
|
||||
|
||||
void IDisposable.Dispose()
|
||||
{
|
||||
StartInteraction -= OnCanvasViewStartInteraction;
|
||||
EndInteraction -= OnCanvasViewEndInteraction;
|
||||
CancelInteraction -= OnCanvasViewCancelInteraction;
|
||||
}
|
||||
|
||||
void OnCanvasViewStartInteraction(object sender, TouchEventArgs e)
|
||||
{
|
||||
var touchPoint = e.Touches[0];
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child.IsVisible && child is View view && view.TouchInside(touchPoint))
|
||||
if (child.IsVisible && child is View view && view.IsInsideBounds(touchPoint))
|
||||
{
|
||||
view.StartInteraction(e.Touches);
|
||||
|
||||
foreach (var gesture in view.GestureRecognizers)
|
||||
{
|
||||
if (gesture is TapGestureRecognizer tapGestureRecognizer)
|
||||
|
@ -67,5 +84,29 @@ namespace AlohaKit.UI
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCanvasViewEndInteraction(object sender, TouchEventArgs e)
|
||||
{
|
||||
var touchPoint = e.Touches[0];
|
||||
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child.IsVisible && child is View view && view.IsInsideBounds(touchPoint))
|
||||
{
|
||||
view.EndInteraction(e.Touches, e.IsInsideBounds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCanvasViewCancelInteraction(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var child in Children)
|
||||
{
|
||||
if (child.IsVisible && child is View view)
|
||||
{
|
||||
view.CancelInteraction();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
namespace AlohaKit.UI.Cupertino
|
||||
{
|
||||
public class Button : ButtonBase
|
||||
{
|
||||
const string BackgroundColor = "#007AFF";
|
||||
const float CornerRadius = 2.0f;
|
||||
const float MinimumHeight = 44f;
|
||||
|
||||
public override void Draw(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
base.Draw(canvas, bounds);
|
||||
|
||||
DrawBackground(canvas, bounds);
|
||||
DrawText(canvas, bounds);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
public virtual void DrawBackground(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
if (Background is SolidColorBrush solidColorBrush)
|
||||
{
|
||||
if (solidColorBrush.Color != null)
|
||||
canvas.FillColor = solidColorBrush.Color;
|
||||
else
|
||||
canvas.FillColor = Color.FromArgb(BackgroundColor);
|
||||
}
|
||||
else
|
||||
canvas.SetFillPaint(Background, bounds);
|
||||
|
||||
float height = MinimumHeight;
|
||||
|
||||
if (!float.IsNaN(HeightRequest))
|
||||
height = HeightRequest;
|
||||
|
||||
canvas.FillRoundedRectangle(X, Y, WidthRequest, height, CornerRadius);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
public virtual void DrawText(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
canvas.FontColor = TextColor;
|
||||
canvas.FontSize = (float)FontSize;
|
||||
|
||||
float height = MinimumHeight;
|
||||
|
||||
if (!float.IsNaN(HeightRequest))
|
||||
height = HeightRequest;
|
||||
|
||||
canvas.DrawString(Text, X, Y, WidthRequest, height, HorizontalAlignment.Center, VerticalAlignment.Center);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,8 +12,6 @@
|
|||
public class Element : VisualElement, IElement
|
||||
{
|
||||
IElement _parent;
|
||||
RectF _childrenBounds;
|
||||
|
||||
|
||||
public Element()
|
||||
{
|
||||
|
|
|
@ -6,6 +6,7 @@ namespace AlohaKit.UI
|
|||
public class ElementsCollection : ObservableCollection<IElement>
|
||||
{
|
||||
readonly IElement _parent;
|
||||
readonly ICanvasView _canvasView;
|
||||
|
||||
public ElementsCollection()
|
||||
{
|
||||
|
@ -15,9 +16,14 @@ namespace AlohaKit.UI
|
|||
internal ElementsCollection(IElement parent)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
internal ElementsCollection(ICanvasView canvasView)
|
||||
{
|
||||
_canvasView = canvasView;
|
||||
}
|
||||
|
||||
protected override void ClearItems()
|
||||
{
|
||||
base.ClearItems();
|
||||
}
|
||||
|
@ -47,6 +53,7 @@ namespace AlohaKit.UI
|
|||
|
||||
void Invalidate()
|
||||
{
|
||||
_canvasView?.Invalidate();
|
||||
_parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
using AlohaKit.UI.Extensions;
|
||||
|
||||
namespace AlohaKit.UI.Fluent
|
||||
{
|
||||
public class Button : ButtonBase
|
||||
{
|
||||
const string BackgroundColor = "#2A2A2A";
|
||||
const float CornerRadius = 4.0f;
|
||||
const float MinimumHeight = 32f;
|
||||
|
||||
public override void Draw(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
base.Draw(canvas, bounds);
|
||||
|
||||
DrawBackground(canvas, bounds);
|
||||
DrawText(canvas, bounds);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
public virtual void DrawBackground(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
var x = X;
|
||||
var y = Y;
|
||||
|
||||
var width = WidthRequest;
|
||||
var height = MinimumHeight;
|
||||
|
||||
if (!float.IsNaN(HeightRequest))
|
||||
height = HeightRequest;
|
||||
|
||||
var backgroundColor = Color.FromArgb(BackgroundColor);
|
||||
|
||||
if (Background is SolidColorBrush backgroundBrush)
|
||||
{
|
||||
if (backgroundBrush.Color != null)
|
||||
backgroundColor = backgroundBrush.Color;
|
||||
}
|
||||
|
||||
var border = new LinearGradientPaint
|
||||
{
|
||||
GradientStops = new PaintGradientStop[]
|
||||
{
|
||||
new PaintGradientStop(0.0f, backgroundColor.Lighter()),
|
||||
new PaintGradientStop(0.9f, backgroundColor.Darker())
|
||||
},
|
||||
StartPoint = new Point(0, 0),
|
||||
EndPoint = new Point(0, 1)
|
||||
};
|
||||
|
||||
canvas.SetFillPaint(border, bounds);
|
||||
|
||||
canvas.FillRoundedRectangle(x, y, width, height, CornerRadius);
|
||||
|
||||
canvas.RestoreState();
|
||||
|
||||
canvas.SaveState();
|
||||
|
||||
canvas.StrokeColor = Colors.Black;
|
||||
|
||||
if (Background is SolidColorBrush borderBrush)
|
||||
{
|
||||
if (borderBrush.Color != null)
|
||||
canvas.FillColor = borderBrush.Color;
|
||||
else
|
||||
canvas.FillColor = backgroundColor;
|
||||
}
|
||||
else
|
||||
canvas.SetFillPaint(Background, bounds);
|
||||
|
||||
var strokeWidth = 1;
|
||||
float margin = strokeWidth * 2;
|
||||
canvas.FillRoundedRectangle(x + strokeWidth, y + strokeWidth, width - margin, height - margin, CornerRadius);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
public virtual void DrawText(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
canvas.FontColor = TextColor;
|
||||
canvas.FontSize = (float)FontSize;
|
||||
|
||||
float height = MinimumHeight;
|
||||
|
||||
if (!float.IsNaN(HeightRequest))
|
||||
height = HeightRequest;
|
||||
|
||||
canvas.DrawString(Text, X, Y, WidthRequest, height, HorizontalAlignment.Center, VerticalAlignment.Center);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
namespace AlohaKit.UI.Material
|
||||
{
|
||||
public class Button : ButtonBase
|
||||
{
|
||||
const string BackgroundColor = "#2196f3";
|
||||
const float MinimumHeight = 36f;
|
||||
const float CornerRadius = 2.0f;
|
||||
|
||||
public override void Draw(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
base.Draw(canvas, bounds);
|
||||
|
||||
DrawBackground(canvas, bounds);
|
||||
DrawText(canvas, bounds);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
public void DrawBackground(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
if (Background is SolidColorBrush solidColorBrush)
|
||||
{
|
||||
if (solidColorBrush.Color != null)
|
||||
canvas.FillColor = solidColorBrush.Color;
|
||||
else
|
||||
canvas.FillColor = Color.FromArgb(BackgroundColor);
|
||||
}
|
||||
else
|
||||
canvas.SetFillPaint(Background, bounds);
|
||||
|
||||
float height = MinimumHeight;
|
||||
|
||||
if (!float.IsNaN(HeightRequest))
|
||||
height = HeightRequest;
|
||||
|
||||
canvas.FillRoundedRectangle(X, Y, WidthRequest, height, CornerRadius);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
|
||||
public void DrawText(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
canvas.SaveState();
|
||||
|
||||
canvas.FontColor = TextColor;
|
||||
canvas.FontSize = (float)FontSize;
|
||||
|
||||
float height = MinimumHeight;
|
||||
|
||||
if (!float.IsNaN(HeightRequest))
|
||||
height = HeightRequest;
|
||||
|
||||
canvas.DrawString(Text.ToUpper(), X, Y, WidthRequest, height, HorizontalAlignment.Center, VerticalAlignment.Center);
|
||||
|
||||
canvas.RestoreState();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -9,7 +9,15 @@ namespace AlohaKit.UI
|
|||
public interface IView : IElement
|
||||
{
|
||||
Brush Background { get; set; }
|
||||
}
|
||||
|
||||
void StartHoverInteraction(PointF[] points);
|
||||
void MoveHoverInteraction(PointF[] points);
|
||||
void EndHoverInteraction();
|
||||
void StartInteraction(PointF[] points);
|
||||
void DragInteraction(PointF[] points);
|
||||
void EndInteraction(PointF[] points, bool isInsideBounds);
|
||||
void CancelInteraction();
|
||||
}
|
||||
|
||||
public class View : Element, IView
|
||||
{
|
||||
|
@ -58,7 +66,8 @@ namespace AlohaKit.UI
|
|||
}
|
||||
|
||||
public static readonly BindableProperty BackgroundProperty =
|
||||
BindableProperty.Create(nameof(Background), typeof(Brush), typeof(View), null, propertyChanged: BackgroundPropertyChanged);
|
||||
BindableProperty.Create(nameof(Background), typeof(Brush), typeof(View), null,
|
||||
propertyChanged: BackgroundPropertyChanged);
|
||||
|
||||
public static void BackgroundPropertyChanged(BindableObject bindableObject, object oldValue, object newValue)
|
||||
{
|
||||
|
@ -93,7 +102,21 @@ namespace AlohaKit.UI
|
|||
}
|
||||
}
|
||||
|
||||
void DrawBackground(ICanvas canvas, RectF bounds)
|
||||
public virtual void CancelInteraction() { }
|
||||
|
||||
public virtual void DragInteraction(PointF[] points) { }
|
||||
|
||||
public virtual void EndHoverInteraction() { }
|
||||
|
||||
public virtual void EndInteraction(PointF[] points, bool isInsideBounds) { }
|
||||
|
||||
public virtual void StartHoverInteraction(PointF[] points) { }
|
||||
|
||||
public virtual void MoveHoverInteraction(PointF[] points) { }
|
||||
|
||||
public virtual void StartInteraction(PointF[] points) { }
|
||||
|
||||
void DrawBackground(ICanvas canvas, RectF bounds)
|
||||
{
|
||||
if (Background is SolidColorBrush solidColorBrush)
|
||||
canvas.FillColor = solidColorBrush.Color;
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
using System;
|
||||
|
||||
namespace AlohaKit.UI.Extensions
|
||||
{
|
||||
public static class ColorExtensions
|
||||
{
|
||||
const float LighterFactor = 1.1f;
|
||||
const float DarkerFactor = 0.9f;
|
||||
|
||||
public static Color Lighter(this Color color)
|
||||
{
|
||||
return new Color(
|
||||
color.Red * LighterFactor,
|
||||
color.Green * LighterFactor,
|
||||
color.Blue * LighterFactor,
|
||||
color.Alpha);
|
||||
}
|
||||
|
||||
public static Color Darker(this Color color)
|
||||
{
|
||||
return new Color(
|
||||
color.Red * DarkerFactor,
|
||||
color.Green * DarkerFactor,
|
||||
color.Blue * DarkerFactor,
|
||||
color.Alpha);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,9 +2,22 @@
|
|||
{
|
||||
public static class GestureExtensions
|
||||
{
|
||||
public static bool TouchInside<T>(this T view, PointF touchPoint) where T : View
|
||||
public static bool IsInsideBounds<T>(this T view, PointF touchPoint) where T : View
|
||||
{
|
||||
var bounds = new RectF(view.X, view.Y, view.WidthRequest, view.HeightRequest);
|
||||
if (view == null)
|
||||
return false;
|
||||
|
||||
var minimumTouchSize = 24f;
|
||||
|
||||
var width = view.WidthRequest;
|
||||
if (float.IsNaN(width))
|
||||
width = minimumTouchSize;
|
||||
|
||||
var height = view.HeightRequest;
|
||||
if (float.IsNaN(height))
|
||||
height = minimumTouchSize;
|
||||
|
||||
var bounds = new RectF(view.X, view.Y, width, height);
|
||||
|
||||
if (bounds.Contains(touchPoint))
|
||||
return true;
|
||||
|
|
Загрузка…
Ссылка в новой задаче