|
using System;
using System.ComponentModel;
using Android.Content;
using Android.Content.Res;
using Android.Graphics;
using Android.Views;
using Android.Widget;
using AndroidX.AppCompat.Widget;
using AndroidX.Core.Widget;
using Microsoft.Maui.Controls.Compatibility.Platform.Android.FastRenderers;
using Microsoft.Maui.Controls.Internals;
using Microsoft.Maui.Controls.Platform;
using Microsoft.Maui.Graphics;
using AAttribute = Android.Resource.Attribute;
using AColor = Android.Graphics.Color;
using AView = Android.Views.View;
using Color = Microsoft.Maui.Graphics.Color;
namespace Microsoft.Maui.Controls.Compatibility.Platform.Android
{
[System.Obsolete(Compatibility.Hosting.MauiAppBuilderExtensions.UseMapperInstead)]
public class CheckBoxRendererBase :
AppCompatCheckBox,
IVisualElementRenderer,
AView.IOnFocusChangeListener,
CompoundButton.IOnCheckedChangeListener,
ITabStop
{
bool _disposed;
int? _defaultLabelFor;
VisualElementTracker _tracker;
VisualElementRenderer _visualElementRenderer;
IPlatformElementConfiguration<PlatformConfiguration.Android, CheckBox> _platformElementConfiguration;
CheckBox _checkBox;
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
public CheckBoxRendererBase(Context context) : base(context) => Init();
public CheckBoxRendererBase(Context context, int defStyleAttr) : base(context, null, defStyleAttr) => Init();
void Init()
{
SoundEffectsEnabled = false;
SetOnCheckedChangeListener(this);
Tag = this;
OnFocusChangeListener = this;
this.SetClipToOutline(true);
}
protected override void Dispose(bool disposing)
{
if (_disposed)
return;
_disposed = true;
if (disposing)
{
_disposed = true;
_tracker?.Dispose();
_tracker = null;
SetOnCheckedChangeListener(null);
OnFocusChangeListener = null;
if (Element != null)
{
Element.PropertyChanged -= OnElementPropertyChanged;
if (Platform.GetRenderer(Element) == this)
{
Element.ClearValue(Platform.RendererProperty);
}
Element = null;
}
}
base.Dispose(disposing);
}
Size MinimumSize()
{
return Size.Zero;
}
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
if (_disposed)
{
return new SizeRequest();
}
Measure(widthConstraint, heightConstraint);
return new SizeRequest(new Size(MeasuredWidth, MeasuredHeight), MinimumSize());
}
void IVisualElementRenderer.SetElement(VisualElement element)
{
if (element == null)
{
throw new ArgumentNullException(nameof(element));
}
if (!(element is CheckBox checkBox))
{
throw new ArgumentException("Element is not of type " + typeof(CheckBox), nameof(element));
}
CheckBox oldElement = Element;
Element = checkBox;
Performance.Start(out string reference);
if (oldElement != null)
{
oldElement.PropertyChanged -= OnElementPropertyChanged;
}
element.PropertyChanged += OnElementPropertyChanged;
if (_tracker == null)
{
_tracker = new VisualElementTracker(this);
}
if (_visualElementRenderer == null)
{
_visualElementRenderer = new VisualElementRenderer(this);
}
OnElementChanged(new ElementChangedEventArgs<CheckBox>(oldElement as CheckBox, Element));
Element?.SendViewInitialized(Control);
Performance.Stop(reference);
}
protected virtual void OnElementChanged(ElementChangedEventArgs<CheckBox> e)
{
if (e.NewElement != null && !_disposed)
{
this.EnsureId();
UpdateOnColor();
UpdateIsChecked();
UpdateBackgroundColor();
UpdateBackground();
}
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
}
protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (this.IsDisposed())
{
return;
}
if (e.PropertyName == CheckBox.ColorProperty.PropertyName)
{
UpdateOnColor();
}
else if (e.PropertyName == CheckBox.IsCheckedProperty.PropertyName)
{
UpdateIsChecked();
}
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
{
UpdateBackgroundColor();
}
else if (e.PropertyName == VisualElement.BackgroundProperty.PropertyName)
{
UpdateBackground();
}
ElementPropertyChanged?.Invoke(this, e);
}
void IOnCheckedChangeListener.OnCheckedChanged(CompoundButton buttonView, bool isChecked)
{
((IElementController)Element).SetValueFromRenderer(CheckBox.IsCheckedProperty, isChecked);
}
[PortHandler]
void UpdateIsChecked()
{
if (Element == null || Control == null)
return;
Checked = Element.IsChecked;
}
protected virtual ColorStateList GetColorStateList()
{
var tintColor = Element.Color == null ? Application.AccentColor.ToAndroid() : Element.Color.ToAndroid();
return ColorStateListExtensions.CreateCheckBox(tintColor);
}
[PortHandler]
void UpdateBackgroundColor()
{
if (Element.BackgroundColor == null)
SetBackgroundColor(AColor.Transparent);
else
SetBackgroundColor(Element.BackgroundColor.ToAndroid());
}
void UpdateBackground()
{
Brush background = Element.Background;
this.UpdateBackground(background);
}
[PortHandler]
void UpdateOnColor()
{
if (Element == null || Control == null)
return;
var mode = PorterDuff.Mode.SrcIn;
CompoundButtonCompat.SetButtonTintList(Control, GetColorStateList());
CompoundButtonCompat.SetButtonTintMode(Control, mode);
}
[PortHandler]
void IOnFocusChangeListener.OnFocusChange(AView v, bool hasFocus)
{
((IElementController)Element).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, hasFocus);
}
IPlatformElementConfiguration<PlatformConfiguration.Android, CheckBox> OnThisPlatform()
{
if (_platformElementConfiguration == null)
_platformElementConfiguration = Element.OnThisPlatform();
return _platformElementConfiguration;
}
public void SetLabelFor(int? id)
{
if (_defaultLabelFor == null)
_defaultLabelFor = LabelFor;
LabelFor = (int)(id ?? _defaultLabelFor);
}
void IVisualElementRenderer.UpdateLayout() => _tracker?.UpdateLayout();
VisualElement IVisualElementRenderer.Element => Element;
AView IVisualElementRenderer.View => this;
VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
protected CheckBox Element
{
get => _checkBox;
private set
{
_checkBox = value;
_platformElementConfiguration = null;
}
}
protected AppCompatCheckBox Control => this;
AView ITabStop.TabStop => this;
}
} |