maui-linux/Xamarin.Forms.Material.iOS/MaterialButtonRenderer.cs

251 строка
7.3 KiB
C#

using System;
using System.ComponentModel;
using CoreGraphics;
using MaterialComponents;
using UIKit;
using Xamarin.Forms.Platform.iOS;
using MButton = MaterialComponents.Button;
namespace Xamarin.Forms.Material.iOS
{
public class MaterialButtonRenderer : ViewRenderer<Button, MButton>, IImageVisualElementRenderer, IButtonLayoutRenderer
{
bool _isDisposed;
UIColor _defaultBorderColor;
nfloat _defaultBorderWidth = -1;
ButtonScheme _defaultButtonScheme;
ButtonScheme _buttonScheme;
ButtonLayoutManager _buttonLayoutManager;
public MaterialButtonRenderer()
{
_buttonLayoutManager = new ButtonLayoutManager(this,
preserveInitialPadding: true,
spacingAdjustsPadding: false,
borderAdjustsPadding: false,
collapseHorizontalPadding: true);
}
protected override void Dispose(bool disposing)
{
if (_isDisposed)
return;
if (Control != null)
{
Control.TouchUpInside -= OnButtonTouchUpInside;
Control.TouchDown -= OnButtonTouchDown;
_buttonLayoutManager?.Dispose();
_buttonLayoutManager = null;
}
_isDisposed = true;
base.Dispose(disposing);
}
public override CGSize SizeThatFits(CGSize size)
{
var measured = base.SizeThatFits(size);
return _buttonLayoutManager?.SizeThatFits(size, measured) ?? measured;
}
protected override void OnElementChanged(ElementChangedEventArgs<Button> e)
{
// recreate the scheme
_buttonScheme?.Dispose();
_buttonScheme = CreateButtonScheme();
base.OnElementChanged(e);
if (e.NewElement != null)
{
if (Control == null)
{
_defaultButtonScheme = CreateButtonScheme();
SetNativeControl(CreateNativeControl());
Control.TouchUpInside += OnButtonTouchUpInside;
Control.TouchDown += OnButtonTouchDown;
}
UpdateFont();
UpdateCornerRadius();
UpdateBorder();
UpdateTextColor();
_buttonLayoutManager?.Update();
ApplyTheme();
}
}
protected virtual ButtonScheme CreateButtonScheme()
{
return new ButtonScheme
{
ColorScheme = MaterialColors.Light.CreateColorScheme(),
ShapeScheme = new ShapeScheme(),
TypographyScheme = new TypographyScheme(),
};
}
protected virtual void ApplyTheme() => ContainedButtonThemer.ApplyScheme(_buttonScheme, Control);
protected override MButton CreateNativeControl() => new MButton();
protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
base.OnElementPropertyChanged(sender, e);
var updatedTheme = false;
if (e.PropertyName == Button.TextColorProperty.PropertyName)
{
UpdateTextColor();
updatedTheme = true;
}
else if (e.PropertyName == Button.FontProperty.PropertyName)
{
UpdateFont();
updatedTheme = true;
}
else if (e.PropertyName == Button.BorderWidthProperty.PropertyName || e.PropertyName == Button.BorderColorProperty.PropertyName)
{
UpdateBorder();
}
else if (e.PropertyName == Button.CornerRadiusProperty.PropertyName)
{
UpdateCornerRadius();
updatedTheme = true;
}
if (updatedTheme)
ApplyTheme();
}
protected override void SetAccessibilityLabel()
{
// If we have not specified an AccessibilityLabel and the AccessibilityLabel is currently bound to the Title,
// exit this method so we don't set the AccessibilityLabel value and break the binding.
// This may pose a problem for users who want to explicitly set the AccessibilityLabel to null, but this
// will prevent us from inadvertently breaking UI Tests that are using Query.Marked to get the dynamic Title
// of the Button.
var elemValue = (string)Element?.GetValue(AutomationProperties.NameProperty);
if (string.IsNullOrWhiteSpace(elemValue) && Control?.AccessibilityLabel == Control?.Title(UIControlState.Normal))
return;
base.SetAccessibilityLabel();
}
void OnButtonTouchUpInside(object sender, EventArgs eventArgs)
{
Element?.SendReleased();
Element?.SendClicked();
}
void OnButtonTouchDown(object sender, EventArgs eventArgs) => Element?.SendPressed();
protected override void SetBackgroundColor(Color color)
{
if (_buttonScheme?.ColorScheme is SemanticColorScheme colorScheme)
{
if (color.IsDefault)
{
colorScheme.PrimaryColor = _defaultButtonScheme.ColorScheme.PrimaryColor;
colorScheme.OnSurfaceColor = _defaultButtonScheme.ColorScheme.OnSurfaceColor;
}
else
{
UIColor uiColor = color.ToUIColor();
colorScheme.PrimaryColor = uiColor;
colorScheme.OnSurfaceColor = uiColor;
}
}
}
void UpdateBorder()
{
// NOTE: borders are not a "supported" style of the contained
// button, thus we don't use the themer here.
Color borderColor = Element.BorderColor;
if (_defaultBorderColor == null)
_defaultBorderColor = Control.GetBorderColor(UIControlState.Normal);
if (borderColor.IsDefault)
Control.SetBorderColor(_defaultBorderColor, UIControlState.Normal);
else
Control.SetBorderColor(borderColor.ToUIColor(), UIControlState.Normal);
double borderWidth = Element.BorderWidth;
if (_defaultBorderWidth == -1)
_defaultBorderWidth = Control.GetBorderWidth(UIControlState.Normal);
// TODO: The Material button does not support borders:
// https://github.com/xamarin/Xamarin.Forms/issues/4951
if (borderWidth > 1)
borderWidth = 1;
if (borderWidth == (double)Button.BorderWidthProperty.DefaultValue)
Control.SetBorderWidth(_defaultBorderWidth, UIControlState.Normal);
else
Control.SetBorderWidth((nfloat)borderWidth, UIControlState.Normal);
}
void UpdateCornerRadius()
{
int cornerRadius = Element.CornerRadius;
if (cornerRadius == (int)Button.CornerRadiusProperty.DefaultValue)
{
_buttonScheme.CornerRadius = _defaultButtonScheme.CornerRadius;
}
else
{
_buttonScheme.CornerRadius = cornerRadius;
if (_buttonScheme.ShapeScheme is ShapeScheme shapeScheme)
{
shapeScheme.SmallComponentShape = new ShapeCategory(ShapeCornerFamily.Rounded, cornerRadius);
shapeScheme.MediumComponentShape = new ShapeCategory(ShapeCornerFamily.Rounded, cornerRadius);
shapeScheme.LargeComponentShape = new ShapeCategory(ShapeCornerFamily.Rounded, cornerRadius);
}
}
}
void UpdateFont()
{
if (_buttonScheme.TypographyScheme is TypographyScheme typographyScheme)
{
if (Element.Font == (Font)Button.FontProperty.DefaultValue)
typographyScheme.Button = _defaultButtonScheme.TypographyScheme.Button;
else
typographyScheme.Button = Element.ToUIFont();
}
}
void UpdateTextColor()
{
if (_buttonScheme.ColorScheme is SemanticColorScheme colorScheme)
{
Color textColor = Element.TextColor;
if (textColor.IsDefault)
colorScheme.OnPrimaryColor = _defaultButtonScheme.ColorScheme.OnPrimaryColor;
else
colorScheme.OnPrimaryColor = textColor.ToUIColor();
}
}
// IImageVisualElementRenderer
bool IImageVisualElementRenderer.IsDisposed => _isDisposed;
void IImageVisualElementRenderer.SetImage(UIImage image) => _buttonLayoutManager.SetImage(image);
UIImageView IImageVisualElementRenderer.GetImage() => Control?.ImageView;
// IButtonLayoutRenderer
UIButton IButtonLayoutRenderer.Control => Control;
IImageVisualElementRenderer IButtonLayoutRenderer.ImageVisualElementRenderer => this;
nfloat IButtonLayoutRenderer.MinimumHeight => _buttonScheme?.MinimumHeight ?? -1;
}
}