* [Android] Add a button background tracker to handle background and border properties and be shared between button renderers
* [Android]Fix border radius dependency
* [Android] Make sure we always create or updated the background button tracker
using System;
using System.ComponentModel;
using Android.Content;
-using Android.Content.Res;
using Android.Graphics;
-using Android.Graphics.Drawables;
-using Android.Support.V4.Content;
using Android.Support.V7.Widget;
using Android.Util;
-using Xamarin.Forms.Internals;
-using GlobalResource = Android.Resource;
using Object = Java.Lang.Object;
using AView = Android.Views.View;
using AMotionEvent = Android.Views.MotionEvent;
{
public class ButtonRenderer : ViewRenderer<Button, AppCompatButton>, AView.IOnAttachStateChangeListener
{
+ ButtonBackgroundTracker _backgroundTracker;
TextColorSwitcher _textColorSwitcher;
float _defaultFontSize;
Typeface _defaultTypeface;
public ButtonRenderer()
{
+ System.Diagnostics.Debug.WriteLine("Slow Button!");
AutoPackage = false;
}
Control.Tag = null;
_textColorSwitcher = null;
}
+ _backgroundTracker?.Dispose();
}
base.Dispose(disposing);
button.AddOnAttachStateChangeListener(this);
}
+ if (_backgroundTracker == null)
+ _backgroundTracker = new ButtonBackgroundTracker(Element, Control);
+ else
+ _backgroundTracker.Button = e.NewElement;
+
UpdateAll();
- UpdateBackgroundColor();
}
}
if (Element == null || Control == null)
return;
- Color backgroundColor = Element.BackgroundColor;
- if (backgroundColor.IsDefault)
- {
- if (Control.SupportBackgroundTintList != null)
- {
- Context context = Context;
- int id = GlobalResource.Attribute.ButtonTint;
- unchecked
- {
- using (var value = new TypedValue())
- {
- try
- {
- Resources.Theme theme = context.Theme;
- if (theme != null && theme.ResolveAttribute(id, value, true))
-#pragma warning disable 618
- Control.SupportBackgroundTintList = Resources.GetColorStateList(value.Data);
-#pragma warning restore 618
- else
- Control.SupportBackgroundTintList = new ColorStateList(ColorExtensions.States, new[] { (int)0xffd7d6d6, 0x7fd7d6d6 });
- }
- catch (Exception ex)
- {
- Internals.Log.Warning("Xamarin.Forms.Platform.Android.ButtonRenderer", "Could not retrieve button background resource: {0}", ex);
- Control.SupportBackgroundTintList = new ColorStateList(ColorExtensions.States, new[] { (int)0xffd7d6d6, 0x7fd7d6d6 });
- }
- }
- }
- }
- }
- else
- {
- int intColor = backgroundColor.ToAndroid().ToArgb();
- int disableColor = backgroundColor.MultiplyAlpha(0.5).ToAndroid().ToArgb();
- Control.SupportBackgroundTintList = new ColorStateList(ColorExtensions.States, new[] { intColor, disableColor });
- }
+ _backgroundTracker.UpdateBackgroundColor();
}
void UpdateAll()
UpdateBitmap();
UpdateTextColor();
UpdateEnabled();
+ UpdateBackgroundColor();
+ UpdateDrawable();
+ }
+
+ void UpdateDrawable()
+ {
+ if (Element == null || Control == null)
+ return;
+
+ _backgroundTracker?.UpdateDrawable();
}
void UpdateBitmap()
--- /dev/null
+using System;
+using System.ComponentModel;
+using Android.Graphics.Drawables;
+using AButton = Android.Widget.Button;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ internal class ButtonBackgroundTracker : IDisposable
+ {
+ Drawable _defaultDrawable;
+ ButtonDrawable _backgroundDrawable;
+ Button _button;
+ AButton _nativeButton;
+ bool _drawableEnabled;
+ bool _disposed;
+
+ public ButtonBackgroundTracker(Button button, AButton nativeButton)
+ {
+ Button = button;
+ _nativeButton = nativeButton;
+ }
+
+ public Button Button
+ {
+ get { return _button; }
+ set
+ {
+ if (_button == value)
+ return;
+ if (_button != null)
+ _button.PropertyChanged -= ButtonPropertyChanged;
+ _button = value;
+ _button.PropertyChanged += ButtonPropertyChanged;
+ }
+ }
+
+ public void UpdateDrawable()
+ {
+ if (_button.BackgroundColor == Color.Default)
+ {
+ if (!_drawableEnabled)
+ return;
+
+ if (_defaultDrawable != null)
+ _nativeButton.SetBackground(_defaultDrawable);
+
+ _drawableEnabled = false;
+ }
+ else
+ {
+ if (_backgroundDrawable == null)
+ _backgroundDrawable = new ButtonDrawable();
+
+ _backgroundDrawable.Button = _button;
+
+ if (_drawableEnabled)
+ return;
+
+ if (_defaultDrawable == null)
+ _defaultDrawable = _nativeButton.Background;
+
+ _nativeButton.SetBackground(_backgroundDrawable);
+ _drawableEnabled = true;
+ }
+
+ _nativeButton.Invalidate();
+ }
+
+ public void Reset()
+ {
+ if (_drawableEnabled)
+ {
+ _drawableEnabled = false;
+ _backgroundDrawable.Reset();
+ _backgroundDrawable = null;
+ }
+ }
+
+ public void UpdateBackgroundColor()
+ {
+ if (_button == null)
+ return;
+ UpdateDrawable();
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (!_disposed)
+ {
+ if (disposing)
+ {
+ _backgroundDrawable?.Dispose();
+ _backgroundDrawable = null;
+ _defaultDrawable?.Dispose();
+ _defaultDrawable = null;
+ if (_button != null)
+ {
+ _button.PropertyChanged -= ButtonPropertyChanged;
+ _button = null;
+ }
+ _nativeButton = null;
+ }
+ _disposed = true;
+ }
+ }
+
+ void ButtonPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName.Equals(Button.BorderColorProperty.PropertyName) ||
+ e.PropertyName.Equals(Button.BorderWidthProperty.PropertyName) ||
+ e.PropertyName.Equals(Button.BorderRadiusProperty.PropertyName) ||
+ e.PropertyName.Equals(VisualElement.BackgroundColorProperty.PropertyName))
+ {
+ Reset();
+ UpdateDrawable();
+ }
+ }
+
+ }
+}
\ No newline at end of file
using System;
using System.ComponentModel;
using Android.Content;
-using Android.Content.Res;
using Android.Graphics;
using Android.Graphics.Drawables;
using Android.Support.V7.Widget;
using Android.Util;
using Android.Views;
using Xamarin.Forms.Internals;
-using GlobalResource = Android.Resource;
using AView = Android.Views.View;
-using AMotionEvent = Android.Views.MotionEvent;
using AMotionEventActions = Android.Views.MotionEventActions;
using static System.String;
-using Object = Java.Lang.Object;
namespace Xamarin.Forms.Platform.Android.FastRenderers
{
readonly AutomationPropertiesProvider _automationPropertiesProvider;
readonly EffectControlProvider _effectControlProvider;
VisualElementTracker _tracker;
+ ButtonBackgroundTracker _backgroundTracker;
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
oldElement.PropertyChanged -= OnElementPropertyChanged;
}
+ if (_backgroundTracker == null)
+ _backgroundTracker = new ButtonBackgroundTracker(Button, this);
+ else
+ _backgroundTracker.Button = Button;
+
Color currentColor = oldElement?.BackgroundColor ?? Color.Default;
if (element.BackgroundColor != currentColor)
{
_automationPropertiesProvider?.Dispose();
_tracker?.Dispose();
+ _backgroundTracker?.Dispose();
+
if (Element != null)
{
Element.PropertyChanged -= OnElementPropertyChanged;
protected virtual void OnElementChanged(ElementChangedEventArgs<Button> e)
{
+ if (e.OldElement != null)
+ {
+ _backgroundTracker?.Reset();
+ }
+
if (e.NewElement != null && !_isDisposed)
{
-
this.EnsureId();
-
UpdateFont();
UpdateText();
UpdateBitmap();
UpdateIsEnabled();
UpdateInputTransparent();
UpdateBackgroundColor();
+ UpdateDrawable();
}
ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
{
UpdateInputTransparent();
- }
- else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
- {
- UpdateBackgroundColor();
}
ElementPropertyChanged?.Invoke(this, e);
protected void UpdateBackgroundColor()
{
- if (Element == null)
- {
- return;
- }
-
- Color backgroundColor = Element.BackgroundColor;
- if (backgroundColor.IsDefault)
- {
- if (SupportBackgroundTintList != null)
- {
- Context context = Context;
- int id = GlobalResource.Attribute.ButtonTint;
- unchecked
- {
- using (var value = new TypedValue())
- {
- try
- {
- Resources.Theme theme = context.Theme;
- if (theme != null && theme.ResolveAttribute(id, value, true))
-#pragma warning disable 618
- {
- SupportBackgroundTintList = Resources.GetColorStateList(value.Data);
- }
-#pragma warning restore 618
- else
- {
- SupportBackgroundTintList = new ColorStateList(ColorExtensions.States,
- new[] { (int)0xffd7d6d6, 0x7fd7d6d6 });
- }
- }
- catch (Exception ex)
- {
- Internals.Log.Warning("Xamarin.Forms.Platform.Android.ButtonRenderer",
- "Could not retrieve button background resource: {0}", ex);
- SupportBackgroundTintList = new ColorStateList(ColorExtensions.States,
- new[] { (int)0xffd7d6d6, 0x7fd7d6d6 });
- }
- }
- }
- }
- }
- else
- {
- int intColor = backgroundColor.ToAndroid().ToArgb();
- int disableColor = backgroundColor.MultiplyAlpha(0.5).ToAndroid().ToArgb();
- SupportBackgroundTintList = new ColorStateList(ColorExtensions.States, new[] { intColor, disableColor });
- }
+ _backgroundTracker.UpdateBackgroundColor();
}
internal virtual void OnNativeFocusChanged(bool hasFocus)
_textColorSwitcher.Value.UpdateTextColor(this, Button.TextColor);
}
+
+ void UpdateDrawable()
+ {
+ _backgroundTracker.UpdateDrawable();
+ }
+
}
}
[assembly: ExportRenderer (typeof (Stepper), typeof (StepperRenderer))]
[assembly: ExportRenderer (typeof (ProgressBar), typeof (ProgressBarRenderer))]
[assembly: ExportRenderer (typeof (ScrollView), typeof (ScrollViewRenderer))]
-[assembly: ExportRenderer (typeof (Toolbar), typeof (ToolbarRenderer))]
[assembly: ExportRenderer (typeof (ActivityIndicator), typeof (ActivityIndicatorRenderer))]
[assembly: ExportRenderer (typeof (Frame), typeof (FrameRenderer))]
[assembly: ExportRenderer (typeof (NavigationMenu), typeof (NavigationMenuRenderer))]
using System.Linq;
using Android.Graphics;
using Android.Graphics.Drawables;
+using System;
namespace Xamarin.Forms.Platform.Android
{
float inset = borderWidth / 2;
// adjust border radius so outer edge of stroke is same radius as border radius of background
- float borderRadius = Forms.Context.ToPixels(Button.BorderRadius) - inset;
+ float borderRadius = Math.Max(Forms.Context.ToPixels(Button.BorderRadius) - inset, 0);
path.AddRoundRect(new RectF(inset, inset, width - inset, height - inset), borderRadius, borderRadius, Path.Direction.Cw);
paint.StrokeWidth = borderWidth;
using System;
using System.ComponentModel;
-using Android.Content.Res;
using Android.Graphics;
-using Android.Graphics.Drawables;
using Android.Util;
using static System.String;
using AButton = Android.Widget.Button;
{
public class ButtonRenderer : ViewRenderer<Button, AButton>, AView.IOnAttachStateChangeListener
{
- ButtonDrawable _backgroundDrawable;
+ ButtonBackgroundTracker _backgroundTracker;
TextColorSwitcher _textColorSwitcher;
- Drawable _defaultDrawable;
float _defaultFontSize;
Typeface _defaultTypeface;
- bool _drawableEnabled;
bool _isDisposed;
int _imageHeight = -1;
if (disposing)
{
- if (_backgroundDrawable != null)
- {
- _backgroundDrawable.Dispose();
- _backgroundDrawable = null;
- }
+ _backgroundTracker?.Dispose();
}
base.Dispose(disposing);
_textColorSwitcher = new TextColorSwitcher(button.TextColors);
button.AddOnAttachStateChangeListener(this);
}
+ if (_backgroundTracker == null)
+ _backgroundTracker = new ButtonBackgroundTracker(Element, Control);
}
else
{
- if (_drawableEnabled)
- {
- _drawableEnabled = false;
- _backgroundDrawable.Reset();
- _backgroundDrawable = null;
- }
+ _backgroundTracker.Button = e.NewElement;
}
UpdateAll();
UpdateEnabled();
else if (e.PropertyName == Button.FontProperty.PropertyName)
UpdateFont();
- else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
- UpdateDrawable();
else if (e.PropertyName == Button.ImageProperty.PropertyName)
UpdateBitmap();
else if (e.PropertyName == VisualElement.IsVisibleProperty.PropertyName)
UpdateText();
-
- if (_drawableEnabled &&
- (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName || e.PropertyName == Button.BorderColorProperty.PropertyName || e.PropertyName == Button.BorderRadiusProperty.PropertyName ||
- e.PropertyName == Button.BorderWidthProperty.PropertyName))
- {
- _backgroundDrawable.Reset();
- Control.Invalidate();
- }
-
+
base.OnElementPropertyChanged(sender, e);
}
protected override void UpdateBackgroundColor()
{
- // Do nothing, the drawable handles this now
+ _backgroundTracker.UpdateBackgroundColor();
}
void UpdateAll()
void UpdateDrawable()
{
- if (Element.BackgroundColor == Color.Default)
- {
- if (!_drawableEnabled)
- return;
-
- if (_defaultDrawable != null)
- Control.SetBackground(_defaultDrawable);
-
- _drawableEnabled = false;
- }
- else
- {
- if (_backgroundDrawable == null)
- _backgroundDrawable = new ButtonDrawable();
-
- _backgroundDrawable.Button = Element;
-
- if (_drawableEnabled)
- return;
-
- if (_defaultDrawable == null)
- _defaultDrawable = Control.Background;
-
- Control.SetBackground(_backgroundDrawable);
- _drawableEnabled = true;
- }
-
- Control.Invalidate();
+ _backgroundTracker.UpdateDrawable();
}
void UpdateEnabled()
<Compile Include="AndroidApplicationLifecycleState.cs" />
<Compile Include="AndroidTitleBarVisibility.cs" />
<Compile Include="AppCompat\FrameRenderer.cs" />
+ <Compile Include="ButtonBackgroundTracker.cs" />
<Compile Include="Extensions\JavaObjectExtensions.cs" />
<Compile Include="FastRenderers\AutomationPropertiesProvider.cs" />
<Compile Include="FastRenderers\ButtonRenderer.cs" />