summaryrefslogtreecommitdiff
path: root/Xamarin.Forms.Platform.Android
diff options
context:
space:
mode:
authorRui Marinho <me@ruimarinho.net>2017-04-06 14:19:52 +0100
committerGitHub <noreply@github.com>2017-04-06 14:19:52 +0100
commit425fafb05723a299a5eaa0f6d801f87bdf7141fa (patch)
treea9e38aa0a0252e6a6d2da6990303d82f2163a5a9 /Xamarin.Forms.Platform.Android
parent829a4bda76166ddffce5a0e84538183b9527a1bd (diff)
downloadxamarin-forms-425fafb05723a299a5eaa0f6d801f87bdf7141fa.tar.gz
xamarin-forms-425fafb05723a299a5eaa0f6d801f87bdf7141fa.tar.bz2
xamarin-forms-425fafb05723a299a5eaa0f6d801f87bdf7141fa.zip
Android fastrenderers (#845)
* Obsolete IVisualElementRenderer.ViewGroup in favor of .View * Fix NRE * Changing TContainer in PlatformEffect to View * Fix "View" type * new VisualElementRenderer * First attempt at a fast(er) button renderer * Fast Label Renderer * Let's try that again. Behold: Label Fast Renderer * Move FrameRenderer into Fast Renderers * Fix Disposable on VisualElementRenderer * Simplify touch and click handlers * Drop empty if clause * [Android] Add initial Image fast renderer * Split accessibility out to a separate helper class; fix tapgesture bug with label * [Android] Small fixes to VisualElementRenderer * Move accessiblity stuff to a separate class (which needs a good name) * Prevent query from looking to parent for fast renderers * [Android] ImageRenderer refactoring * Fix elevation/z-index bugs with Button (e.g., 40173) * Move SetLabeledBy to Accessibilitizer * Un-break automation IDs for Labels * Move gesture handling to its own class * Split gesture and effect management into separate classes * Remove unneeded packager from LabelRenderer * LabelRenderer inherits from FormsTextView * Batch updates to View * Fix isOnParentRenderer check for non-Android platforms * [Controls] Update Xamarin.Forms.ControlGallery.iOS.csproj * [Android,IOS] Small fixes to rebase and use of Internals * [Android] Ignroe warning for now * Fast renderers now passing InputTransparent and IsEnabled tests * Fast and legacy renderers now pass the Enabled and InputTransparent tests * Change PlatformEffect back, default container to null * Fix mangled using directives
Diffstat (limited to 'Xamarin.Forms.Platform.Android')
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs374
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs11
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/Platform.cs6
-rw-r--r--Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs8
-rw-r--r--Xamarin.Forms.Platform.Android/Extensions/ImageViewExtensions.cs61
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/AccessibilityProvider.cs214
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs490
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/EffectControlProvider.cs35
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs234
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/GestureManager.cs263
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs163
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs313
-rw-r--r--Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs98
-rw-r--r--Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs6
-rw-r--r--Xamarin.Forms.Platform.Android/Platform.cs20
-rw-r--r--Xamarin.Forms.Platform.Android/PlatformEffect.cs1
-rw-r--r--Xamarin.Forms.Platform.Android/RendererPool.cs11
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs1
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs6
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs10
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/FormsImageView.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/FormsTextView.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs82
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs10
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs10
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs14
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs8
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs6
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs6
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs17
-rw-r--r--Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs2
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementPackager.cs7
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementRenderer.cs4
-rw-r--r--Xamarin.Forms.Platform.Android/VisualElementTracker.cs68
-rw-r--r--Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj13
41 files changed, 2054 insertions, 540 deletions
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs
index 61552f54..394f3325 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/ButtonRenderer.cs
@@ -17,7 +17,7 @@ using static System.String;
namespace Xamarin.Forms.Platform.Android.AppCompat
{
- public class ButtonRenderer : ViewRenderer<Button, AppCompatButton>, AView.IOnAttachStateChangeListener
+ public class ButtonRenderer : ViewRenderer<Button, AppCompatButton>, AView.IOnAttachStateChangeListener
{
TextColorSwitcher _textColorSwitcher;
float _defaultFontSize;
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs
index f7a48d9b..766ee225 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs
@@ -42,7 +42,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
IVisualElementRenderer pageRenderer = Android.Platform.GetRenderer(pageToRemove);
if (pageRenderer != null)
{
- pageRenderer.ViewGroup.RemoveFromParent();
+ pageRenderer.View.RemoveFromParent();
pageRenderer.Dispose();
}
pageToRemove.ClearValue(Android.Platform.RendererProperty);
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs b/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs
index 4d588218..4ca0eab8 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/FormsAppCompatActivity.cs
@@ -115,8 +115,8 @@ namespace Xamarin.Forms.Platform.Android
RegisterHandlerForDefaultRenderer(typeof(NavigationPage), typeof(NavigationPageRenderer), typeof(NavigationRenderer));
RegisterHandlerForDefaultRenderer(typeof(TabbedPage), typeof(TabbedPageRenderer), typeof(TabbedRenderer));
RegisterHandlerForDefaultRenderer(typeof(MasterDetailPage), typeof(MasterDetailPageRenderer), typeof(MasterDetailRenderer));
- RegisterHandlerForDefaultRenderer(typeof(Button), typeof(AppCompat.ButtonRenderer), typeof(ButtonRenderer));
- RegisterHandlerForDefaultRenderer(typeof(Switch), typeof(AppCompat.SwitchRenderer), typeof(SwitchRenderer));
+ RegisterHandlerForDefaultRenderer(typeof(Button), typeof(FastRenderers.ButtonRenderer), typeof(ButtonRenderer));
+ RegisterHandlerForDefaultRenderer(typeof(Switch), typeof(AppCompat.SwitchRenderer), typeof(SwitchRenderer));
RegisterHandlerForDefaultRenderer(typeof(Picker), typeof(AppCompat.PickerRenderer), typeof(PickerRenderer));
RegisterHandlerForDefaultRenderer(typeof(Frame), typeof(AppCompat.FrameRenderer), typeof(FrameRenderer));
RegisterHandlerForDefaultRenderer(typeof(CarouselPage), typeof(AppCompat.CarouselPageRenderer), typeof(CarouselPageRenderer));
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs b/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs
index 6cc493a1..e6c1b0ce 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs
@@ -83,9 +83,9 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
{
if (_visualElementRenderer != null)
{
- if (_visualElementRenderer.ViewGroup.Handle != IntPtr.Zero)
+ if (_visualElementRenderer.View.Handle != IntPtr.Zero)
{
- _visualElementRenderer.ViewGroup.RemoveFromParent();
+ _visualElementRenderer.View.RemoveFromParent();
}
_visualElementRenderer.Dispose();
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
index 16ee0473..91ea94b9 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs
@@ -1,372 +1,8 @@
-using System;
-using System.Collections.ObjectModel;
-using System.Collections.Specialized;
-using System.ComponentModel;
-using Android.Content;
-using Android.Support.V4.View;
-using Android.Support.V7.Widget;
-using Android.Views;
-using AColor = Android.Graphics.Color;
-using AView = Android.Views.View;
-
namespace Xamarin.Forms.Platform.Android.AppCompat
{
- public class FrameRenderer : CardView, IVisualElementRenderer, AView.IOnClickListener, AView.IOnTouchListener
- {
- readonly Lazy<GestureDetector> _gestureDetector;
- readonly PanGestureHandler _panGestureHandler;
- readonly PinchGestureHandler _pinchGestureHandler;
- readonly Lazy<ScaleGestureDetector> _scaleDetector;
- readonly TapGestureHandler _tapGestureHandler;
- readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
-
- float _defaultElevation = -1f;
- float _defaultCornerRadius = -1f;
- int? _defaultLabelFor;
-
- bool _clickable;
- bool _disposed;
- Frame _element;
- InnerGestureListener _gestureListener;
- VisualElementPackager _visualElementPackager;
- VisualElementTracker _visualElementTracker;
- NotifyCollectionChangedEventHandler _collectionChangeHandler;
-
- bool _inputTransparent;
- bool _isEnabled;
-
- public FrameRenderer() : base(Forms.Context)
- {
- _tapGestureHandler = new TapGestureHandler(() => Element);
- _panGestureHandler = new PanGestureHandler(() => Element, Context.FromPixels);
- _pinchGestureHandler = new PinchGestureHandler(() => Element);
-
- _gestureDetector =
- new Lazy<GestureDetector>(
- () =>
- new GestureDetector(
- _gestureListener =
- new InnerGestureListener(_tapGestureHandler.OnTap, _tapGestureHandler.TapGestureRecognizers, _panGestureHandler.OnPan, _panGestureHandler.OnPanStarted, _panGestureHandler.OnPanComplete)));
-
- _scaleDetector =
- new Lazy<ScaleGestureDetector>(
- () => new ScaleGestureDetector(Context, new InnerScaleListener(_pinchGestureHandler.OnPinch, _pinchGestureHandler.OnPinchStarted, _pinchGestureHandler.OnPinchEnded), Handler));
- }
-
- protected CardView Control => this;
-
- protected Frame Element
- {
- get { return _element; }
- set
- {
- if (_element == value)
- return;
-
- Frame oldElement = _element;
- _element = value;
-
- OnElementChanged(new ElementChangedEventArgs<Frame>(oldElement, _element));
-
- if (_element != null)
- _element.SendViewInitialized(Control);
- }
- }
-
- public override bool OnTouchEvent(MotionEvent e)
- {
- if (_inputTransparent)
- {
- return false;
- }
-
- if (Element.GestureRecognizers.Count == 0)
- {
- return _motionEventHelper.HandleMotionEvent(Parent);
- }
-
- return base.OnTouchEvent(e);
- }
-
- void IOnClickListener.OnClick(AView v)
- {
- _tapGestureHandler.OnSingleClick();
- }
-
- bool IOnTouchListener.OnTouch(AView v, MotionEvent e)
- {
- if (!_isEnabled)
- return true;
-
- if (_inputTransparent)
- return false;
-
- var handled = false;
- if (_pinchGestureHandler.IsPinchSupported)
- {
- if (!_scaleDetector.IsValueCreated)
- ScaleGestureDetectorCompat.SetQuickScaleEnabled(_scaleDetector.Value, true);
- handled = _scaleDetector.Value.OnTouchEvent(e);
- }
-
- if (_gestureDetector.IsValueCreated && _gestureDetector.Value.Handle == IntPtr.Zero)
- {
- // This gesture detector has already been disposed, probably because it's on a cell which is going away
- return handled;
- }
-
- // It's very important that the gesture detection happen first here
- // if we check handled first, we might short-circuit and never check for tap/pan
- return _gestureDetector.Value.OnTouchEvent(e) || handled;
- }
-
- VisualElement IVisualElementRenderer.Element => Element;
-
- public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
-
- SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
- {
- Context context = Context;
- return new SizeRequest(new Size(context.ToPixels(20), context.ToPixels(20)));
- }
-
- void IVisualElementRenderer.SetElement(VisualElement element)
- {
- var frame = element as Frame;
- if (frame == null)
- throw new ArgumentException("Element must be of type Frame");
- Element = frame;
-
- if (!string.IsNullOrEmpty(Element.AutomationId))
- ContentDescription = Element.AutomationId;
- }
-
- void IVisualElementRenderer.SetLabelFor(int? id)
- {
- if (_defaultLabelFor == null)
- _defaultLabelFor = LabelFor;
-
- LabelFor = (int)(id ?? _defaultLabelFor);
- }
-
- VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker;
-
- void IVisualElementRenderer.UpdateLayout()
- {
- VisualElementTracker tracker = _visualElementTracker;
- tracker?.UpdateLayout();
- }
-
- ViewGroup IVisualElementRenderer.ViewGroup => this;
-
- protected override void Dispose(bool disposing)
- {
- if (disposing && !_disposed)
- {
- _disposed = true;
-
- if (_gestureListener != null)
- {
- _gestureListener.Dispose();
- _gestureListener = null;
- }
-
- if (_visualElementTracker != null)
- {
- _visualElementTracker.Dispose();
- _visualElementTracker = null;
- }
-
- if (_visualElementPackager != null)
- {
- _visualElementPackager.Dispose();
- _visualElementPackager = null;
- }
-
- int count = ChildCount;
- for (var i = 0; i < count; i++)
- {
- AView child = GetChildAt(i);
- child.Dispose();
- }
-
- if (Element != null)
- {
- Element.PropertyChanged -= OnElementPropertyChanged;
- UnsubscribeGestureRecognizers(Element);
- }
-
- }
-
- base.Dispose(disposing);
- }
-
- protected virtual void OnElementChanged(ElementChangedEventArgs<Frame> e)
- {
- ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
-
- if (e.OldElement != null)
- {
- e.OldElement.PropertyChanged -= OnElementPropertyChanged;
- UnsubscribeGestureRecognizers(e.OldElement);
- }
-
- if (e.NewElement != null)
- {
- if (_visualElementTracker == null)
- {
- SetOnClickListener(this);
- SetOnTouchListener(this);
-
- UpdateGestureRecognizers(true);
-
- _visualElementTracker = new VisualElementTracker(this);
- _visualElementPackager = new VisualElementPackager(this);
- _visualElementPackager.Load();
- }
-
- e.NewElement.PropertyChanged += OnElementPropertyChanged;
- UpdateShadow();
- UpdateBackgroundColor();
- UpdateCornerRadius();
- UpdateInputTransparent();
- UpdateIsEnabled();
- SubscribeGestureRecognizers(e.NewElement);
- }
-
- _motionEventHelper.UpdateElement(e.NewElement);
- }
-
- protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
- {
- if (Element == null)
- return;
-
- var children = ((IElementController)Element).LogicalChildren;
- for (var i = 0; i < children.Count; i++)
- {
- var visualElement = children[i] as VisualElement;
- if (visualElement == null)
- continue;
- IVisualElementRenderer renderer = Android.Platform.GetRenderer(visualElement);
- renderer?.UpdateLayout();
- }
- }
-
- void HandleGestureRecognizerCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
- {
- UpdateGestureRecognizers();
- }
-
- void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
- {
- if (e.PropertyName == Frame.HasShadowProperty.PropertyName)
- UpdateShadow();
- else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
- UpdateBackgroundColor();
- else if (e.PropertyName == Frame.CornerRadiusProperty.PropertyName)
- UpdateCornerRadius();
- else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
- UpdateInputTransparent();
- else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
- UpdateIsEnabled();
- }
-
- void UpdateIsEnabled()
- {
- _isEnabled = Element.IsEnabled;
- }
-
- void UpdateInputTransparent()
- {
- _inputTransparent = Element.InputTransparent;
- }
-
- void SubscribeGestureRecognizers(VisualElement element)
- {
- var view = element as View;
- if (view == null)
- return;
-
- if (_collectionChangeHandler == null)
- _collectionChangeHandler = HandleGestureRecognizerCollectionChanged;
-
- var observableCollection = (ObservableCollection<IGestureRecognizer>)view.GestureRecognizers;
- if (observableCollection != null)
- {
- observableCollection.CollectionChanged += _collectionChangeHandler;
- }
- }
-
- void UnsubscribeGestureRecognizers(VisualElement element)
- {
- var view = element as View;
- if (view == null || _collectionChangeHandler == null)
- return;
-
- var observableCollection = (ObservableCollection<IGestureRecognizer>)view.GestureRecognizers;
- if (observableCollection != null)
- {
- observableCollection.CollectionChanged -= _collectionChangeHandler;
- }
- }
-
- void UpdateBackgroundColor()
- {
- Color bgColor = Element.BackgroundColor;
- SetCardBackgroundColor(bgColor.IsDefault ? AColor.White : bgColor.ToAndroid());
- }
-
- void UpdateClickable(bool force = false)
- {
- var view = Element as View;
- if (view == null)
- return;
-
- bool newValue = view.ShouldBeMadeClickable();
- if (force || _clickable != newValue)
- {
- Clickable = newValue;
- _clickable = newValue;
- }
- }
-
- void UpdateGestureRecognizers(bool forceClick = false)
- {
- if (Element == null)
- return;
-
- UpdateClickable(forceClick);
- }
-
- void UpdateShadow()
- {
- float elevation = _defaultElevation;
-
- if (elevation == -1f)
- _defaultElevation = elevation = CardElevation;
-
- if (Element.HasShadow)
- CardElevation = elevation;
- else
- CardElevation = 0f;
- }
-
- void UpdateCornerRadius()
- {
- if (_defaultCornerRadius == -1f)
- {
- _defaultCornerRadius = Radius;
- }
-
- float cornerRadius = Element.CornerRadius;
-
- if (cornerRadius == -1f)
- cornerRadius = _defaultCornerRadius;
- else
- cornerRadius = Context.ToPixels(cornerRadius);
-
- Radius = cornerRadius;
- }
- }
+ // This version of FrameRenderer is here for backward compatibility with anyone referencing
+ // FrameRenderer from this namespace
+ public class FrameRenderer : FastRenderers.FrameRenderer
+ {
+ }
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
index 85ab6b73..a1c4092e 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs
@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Android.Support.V4.Widget;
using Android.Views;
using Android.Support.V4.App;
+using AView = Android.Views.View;
namespace Xamarin.Forms.Platform.Android.AppCompat
{
@@ -87,6 +88,12 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
remove { ElementChanged -= value; }
}
+ event EventHandler<PropertyChangedEventArgs> IVisualElementRenderer.ElementPropertyChanged
+ {
+ add { ElementPropertyChanged += value; }
+ remove { ElementPropertyChanged -= value; }
+ }
+
SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
{
Measure(widthConstraint, heightConstraint);
@@ -178,6 +185,8 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
ViewGroup IVisualElementRenderer.ViewGroup => this;
+ AView IVisualElementRenderer.View => this;
+
protected override void Dispose(bool disposing)
{
if (disposing && !_disposed)
@@ -266,6 +275,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
}
event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
bool HasAncestorNavigationPage(Element element)
{
@@ -283,6 +293,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
+ ElementPropertyChanged?.Invoke(this, e);
if (e.PropertyName == "Master")
UpdateMaster();
else if (e.PropertyName == "Detail")
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs
index 7fe1f1e8..d405b42b 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs
@@ -534,7 +534,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
void RemovePage(Page page)
{
IVisualElementRenderer rendererToRemove = Android.Platform.GetRenderer(page);
- var containerToRemove = (PageContainer)rendererToRemove?.ViewGroup.Parent;
+ var containerToRemove = (PageContainer)rendererToRemove?.View.Parent;
// Also remove this page from the fragmentStack
FilterPageFragment(page);
@@ -542,7 +542,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
containerToRemove.RemoveFromParent();
if (rendererToRemove != null)
{
- rendererToRemove.ViewGroup.RemoveFromParent();
+ rendererToRemove.View.RemoveFromParent();
rendererToRemove.Dispose();
}
containerToRemove?.Dispose();
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs b/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs
index 69365c63..0416ae3a 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs
@@ -88,7 +88,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
IVisualElementRenderer modalRenderer = Android.Platform.GetRenderer(modal);
if (modalRenderer != null)
{
- var modalContainer = modalRenderer.ViewGroup.Parent as ModalContainer;
+ var modalContainer = modalRenderer.View.Parent as ModalContainer;
if (animated)
{
modalContainer.Animate().TranslationY(_renderer.Height).SetInterpolator(new AccelerateInterpolator(1)).SetDuration(300).SetListener(new GenericAnimatorListener
@@ -254,7 +254,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
if (layout)
LayoutRootPage((FormsAppCompatActivity)_context, page, _renderer.Width, _renderer.Height);
- _renderer.AddView(renderView.ViewGroup);
+ _renderer.AddView(renderView.View);
}
bool HandleBackPressed(object sender, EventArgs e)
@@ -336,7 +336,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
_renderer = Android.Platform.CreateRenderer(modal);
Android.Platform.SetRenderer(modal, _renderer);
- AddView(_renderer.ViewGroup);
+ AddView(_renderer.View);
}
protected override void Dispose(bool disposing)
diff --git a/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs
index b1aed05d..bb14100d 100644
--- a/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs
@@ -97,7 +97,7 @@ namespace Xamarin.Forms.Platform.Android.AppCompat
IVisualElementRenderer pageRenderer = Android.Platform.GetRenderer(pageToRemove);
if (pageRenderer != null)
{
- pageRenderer.ViewGroup.RemoveFromParent();
+ pageRenderer.View.RemoveFromParent();
pageRenderer.Dispose();
}
pageToRemove.PropertyChanged -= OnPagePropertyChanged;
diff --git a/Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs b/Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs
index 8134a9c1..48abb49b 100644
--- a/Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs
@@ -61,7 +61,7 @@ namespace Xamarin.Forms.Platform.Android
_unevenRows = unevenRows;
_rowHeight = rowHeight;
_viewCell = viewCell;
- AddView(view.ViewGroup);
+ AddView(view.View);
UpdateIsEnabled();
}
@@ -123,16 +123,16 @@ namespace Xamarin.Forms.Platform.Android
return;
}
- RemoveView(_view.ViewGroup);
+ RemoveView(_view.View);
Platform.SetRenderer(_viewCell.View, null);
_viewCell.View.IsPlatformEnabled = false;
- _view.ViewGroup.Dispose();
+ _view.View.Dispose();
_viewCell = cell;
_view = Platform.CreateRenderer(_viewCell.View);
Platform.SetRenderer(_viewCell.View, _view);
- AddView(_view.ViewGroup);
+ AddView(_view.View);
UpdateIsEnabled();
diff --git a/Xamarin.Forms.Platform.Android/Extensions/ImageViewExtensions.cs b/Xamarin.Forms.Platform.Android/Extensions/ImageViewExtensions.cs
new file mode 100644
index 00000000..f60acb7e
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/Extensions/ImageViewExtensions.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Threading.Tasks;
+using Android.Graphics;
+using Java.IO;
+using AImageView = Android.Widget.ImageView;
+
+namespace Xamarin.Forms.Platform.Android
+{
+ internal static class ImageViewExtensions
+ {
+ public static async void UpdateBitmap(this AImageView imageView, Image newImage, Image previousImage = null)
+ {
+ if (Device.IsInvokeRequired)
+ throw new InvalidOperationException("Image Bitmap must not be updated from background thread");
+
+ if (previousImage != null && Equals(previousImage.Source, newImage.Source))
+ return;
+
+ ((IImageController)newImage).SetIsLoading(true);
+
+ (imageView as IImageRendererController).SkipInvalidate();
+
+ imageView.SetImageResource(global::Android.Resource.Color.Transparent);
+
+ ImageSource source = newImage.Source;
+ Bitmap bitmap = null;
+ IImageSourceHandler handler;
+
+ if (source != null && (handler = Internals.Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null)
+ {
+ try
+ {
+ bitmap = await handler.LoadImageAsync(source, imageView.Context);
+ }
+ catch (TaskCanceledException)
+ {
+ }
+ catch (IOException ex)
+ {
+ Internals.Log.Warning("Xamarin.Forms.Platform.Android.ImageRenderer", "Error updating bitmap: {0}", ex);
+ }
+ }
+
+ if (newImage == null || !Equals(newImage.Source, source))
+ {
+ bitmap?.Dispose();
+ return;
+ }
+
+ if (bitmap == null && source is FileImageSource)
+ imageView.SetImageResource(ResourceManager.GetDrawableByName(((FileImageSource)source).File));
+ else
+ imageView.SetImageBitmap(bitmap);
+
+ bitmap?.Dispose();
+
+ ((IImageController)newImage).SetIsLoading(false);
+ ((IVisualElementController)newImage).NativeSizeChanged();
+ }
+ }
+}
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/AccessibilityProvider.cs b/Xamarin.Forms.Platform.Android/FastRenderers/AccessibilityProvider.cs
new file mode 100644
index 00000000..29327dcd
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/AccessibilityProvider.cs
@@ -0,0 +1,214 @@
+using System;
+using System.ComponentModel;
+using Android.Widget;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ internal class AccessibilityProvider : IDisposable
+ {
+ const string GetFromElement = "GetValueFromElement";
+ string _defaultContentDescription;
+ bool? _defaultFocusable;
+ string _defaultHint;
+ bool _disposed;
+
+ IVisualElementRenderer _renderer;
+
+ public AccessibilityProvider(IVisualElementRenderer renderer)
+ {
+ _renderer = renderer;
+ _renderer.ElementPropertyChanged += OnElementPropertyChanged;
+ _renderer.ElementChanged += OnElementChanged;
+ }
+
+ global::Android.Views.View Control => _renderer?.View;
+
+ VisualElement Element => _renderer?.Element;
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _disposed = true;
+
+ if (_renderer != null)
+ {
+ _renderer.ElementChanged -= OnElementChanged;
+ _renderer.ElementPropertyChanged -= OnElementPropertyChanged;
+
+ _renderer = null;
+ }
+ }
+
+ void SetAutomationId(string id = GetFromElement)
+ {
+ if (Element == null || Control == null)
+ {
+ return;
+ }
+
+ string value = id;
+ if (value == GetFromElement)
+ {
+ value = Element.AutomationId;
+ }
+
+ if (!string.IsNullOrEmpty(value))
+ {
+ Control.ContentDescription = value;
+ }
+ }
+
+ void SetContentDescription(string contentDescription = GetFromElement)
+ {
+ if (Element == null || Control == null)
+ {
+ return;
+ }
+
+ if (SetHint())
+ {
+ return;
+ }
+
+ if (_defaultContentDescription == null)
+ {
+ _defaultContentDescription = Control.ContentDescription;
+ }
+
+ string value = contentDescription;
+ if (value == GetFromElement)
+ {
+ value = string.Join(" ", (string)Element.GetValue(Accessibility.NameProperty),
+ (string)Element.GetValue(Accessibility.HintProperty));
+ }
+
+ if (!string.IsNullOrWhiteSpace(value))
+ {
+ Control.ContentDescription = value;
+ }
+ else
+ {
+ Control.ContentDescription = _defaultContentDescription;
+ }
+ }
+
+ void SetFocusable(bool? value = null)
+ {
+ if (Element == null || Control == null)
+ {
+ return;
+ }
+
+ if (!_defaultFocusable.HasValue)
+ {
+ _defaultFocusable = Control.Focusable;
+ }
+
+ Control.Focusable =
+ (bool)(value ?? (bool?)Element.GetValue(Accessibility.IsInAccessibleTreeProperty) ?? _defaultFocusable);
+ }
+
+ bool SetHint(string hint = GetFromElement)
+ {
+ if (Element == null || Control == null)
+ {
+ return false;
+ }
+
+ var textView = Control as TextView;
+ if (textView == null)
+ {
+ return false;
+ }
+
+ // Let the specified Title/Placeholder take precedence, but don't set the ContentDescription (won't work anyway)
+ if (((Element as Picker)?.Title ?? (Element as Entry)?.Placeholder) != null)
+ {
+ return true;
+ }
+
+ if (_defaultHint == null)
+ {
+ _defaultHint = textView.Hint;
+ }
+
+ string value = hint;
+ if (value == GetFromElement)
+ {
+ value = string.Join(". ", (string)Element.GetValue(Accessibility.NameProperty),
+ (string)Element.GetValue(Accessibility.HintProperty));
+ }
+
+ textView.Hint = !string.IsNullOrWhiteSpace(value) ? value : _defaultHint;
+
+ return true;
+ }
+
+ void SetLabeledBy()
+ {
+ if (Element == null || Control == null)
+ return;
+
+ var elemValue = (VisualElement)Element.GetValue(Accessibility.LabeledByProperty);
+
+ if (elemValue != null)
+ {
+ var id = Control.Id;
+ if (id == -1)
+ id = Control.Id = FormsAppCompatActivity.GetUniqueId();
+
+ var renderer = elemValue?.GetRenderer();
+ renderer?.SetLabelFor(id);
+ }
+ }
+
+ void OnElementChanged(object sender, VisualElementChangedEventArgs e)
+ {
+ if (e.OldElement != null)
+ {
+ e.OldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ if (e.NewElement != null)
+ {
+ e.NewElement.PropertyChanged += OnElementPropertyChanged;
+ }
+
+ SetHint();
+ SetAutomationId();
+ SetContentDescription();
+ SetFocusable();
+ SetLabeledBy();
+ }
+
+ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == Accessibility.HintProperty.PropertyName)
+ {
+ SetContentDescription();
+ }
+ else if (e.PropertyName == Accessibility.NameProperty.PropertyName)
+ {
+ SetContentDescription();
+ }
+ else if (e.PropertyName == Accessibility.IsInAccessibleTreeProperty.PropertyName)
+ {
+ SetFocusable();
+ }
+ else if (e.PropertyName == Accessibility.LabeledByProperty.PropertyName)
+ {
+ SetLabeledBy();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs
new file mode 100644
index 00000000..ae550a64
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/ButtonRenderer.cs
@@ -0,0 +1,490 @@
+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
+{
+ public class ButtonRenderer : AppCompatButton, IVisualElementRenderer, AView.IOnAttachStateChangeListener,
+ AView.IOnFocusChangeListener, IEffectControlProvider, AView.IOnClickListener, AView.IOnTouchListener
+ {
+ float _defaultFontSize;
+ int? _defaultLabelFor;
+ Typeface _defaultTypeface;
+ int _imageHeight = -1;
+ bool _isDisposed;
+ bool _inputTransparent;
+ readonly Lazy<TextColorSwitcher> _textColorSwitcher;
+ readonly AccessibilityProvider _accessibilityProvider;
+ readonly EffectControlProvider _effectControlProvider;
+ VisualElementTracker _tracker;
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+
+ public ButtonRenderer() : base(Forms.Context)
+ {
+ _accessibilityProvider = new AccessibilityProvider(this);
+ _effectControlProvider = new EffectControlProvider(this);
+ _textColorSwitcher = new Lazy<TextColorSwitcher>(() => new TextColorSwitcher(TextColors));
+
+ Initialize();
+ }
+
+ public VisualElement Element => Button;
+ AView IVisualElementRenderer.View => this;
+ ViewGroup IVisualElementRenderer.ViewGroup => null;
+ VisualElementTracker IVisualElementRenderer.Tracker => _tracker;
+
+ Button Button { get; set; }
+
+ public void OnClick(AView v)
+ {
+ ((IButtonController)Button)?.SendClicked();
+ }
+
+ public bool OnTouch(AView v, MotionEvent e)
+ {
+ var buttonController = Element as IButtonController;
+ switch (e.Action)
+ {
+ case AMotionEventActions.Down:
+ buttonController?.SendPressed();
+ break;
+ case AMotionEventActions.Up:
+ buttonController?.SendReleased();
+ break;
+ }
+
+ return false;
+ }
+
+ void IEffectControlProvider.RegisterEffect(Effect effect)
+ {
+ _effectControlProvider.RegisterEffect(effect);
+ }
+
+ void IOnAttachStateChangeListener.OnViewAttachedToWindow(AView attachedView)
+ {
+ UpdateText();
+ }
+
+ void IOnAttachStateChangeListener.OnViewDetachedFromWindow(AView detachedView)
+ {
+ }
+
+ void IOnFocusChangeListener.OnFocusChange(AView v, bool hasFocus)
+ {
+ OnNativeFocusChanged(hasFocus);
+
+ ((IElementController)Button).SetValueFromRenderer(VisualElement.IsFocusedPropertyKey, hasFocus);
+ }
+
+ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
+ {
+ UpdateText();
+
+ AView view = this;
+ view.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 Button))
+ {
+ throw new ArgumentException($"{nameof(element)} must be of type {nameof(Button)}");
+ }
+
+ VisualElement oldElement = Button;
+ Button = (Button)element;
+
+ Performance.Start();
+
+ if (oldElement != null)
+ {
+ oldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ Color currentColor = oldElement?.BackgroundColor ?? Color.Default;
+ if (element.BackgroundColor != currentColor)
+ {
+ UpdateBackgroundColor();
+ }
+
+ element.PropertyChanged += OnElementPropertyChanged;
+
+ if (_tracker == null)
+ {
+ // Can't set up the tracker in the constructor because it access the Element (for now)
+ SetTracker(new VisualElementTracker(this));
+ }
+
+ OnElementChanged(new ElementChangedEventArgs<Button>(oldElement as Button, Button));
+
+ SendVisualElementInitialized(element, this);
+
+ EffectUtilities.RegisterEffectControlProvider(this, oldElement, element);
+
+ Performance.Stop();
+ }
+
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ if (_defaultLabelFor == null)
+ {
+ _defaultLabelFor = LabelFor;
+ }
+
+ LabelFor = (int)(id ?? _defaultLabelFor);
+ }
+
+ void IVisualElementRenderer.UpdateLayout()
+ {
+ Performance.Start();
+ _tracker?.UpdateLayout();
+ Performance.Stop();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_isDisposed)
+ {
+ return;
+ }
+
+ _isDisposed = true;
+
+ if (disposing)
+ {
+ SetOnClickListener(null);
+ SetOnTouchListener(null);
+ RemoveOnAttachStateChangeListener(this);
+
+ _accessibilityProvider?.Dispose();
+ _tracker?.Dispose();
+
+ if (Element != null)
+ {
+ Element.PropertyChanged -= OnElementPropertyChanged;
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ if (!Enabled || (_inputTransparent && Enabled))
+ return false;
+
+ return base.OnTouchEvent(e);
+ }
+
+ protected virtual Size MinimumSize()
+ {
+ return new Size();
+ }
+
+ protected virtual void OnElementChanged(ElementChangedEventArgs<Button> e)
+ {
+ if (e.NewElement != null)
+ {
+ UpdateFont();
+ UpdateText();
+ UpdateBitmap();
+ UpdateTextColor();
+ UpdateIsEnabled();
+ UpdateInputTransparent();
+ UpdateBackgroundColor();
+ }
+
+ ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
+ }
+
+ protected void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == Button.TextProperty.PropertyName)
+ {
+ UpdateText();
+ }
+ else if (e.PropertyName == Button.TextColorProperty.PropertyName)
+ {
+ UpdateTextColor();
+ }
+ else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
+ {
+ UpdateIsEnabled();
+ }
+ else if (e.PropertyName == Button.FontProperty.PropertyName)
+ {
+ UpdateFont();
+ }
+ else if (e.PropertyName == Button.ImageProperty.PropertyName)
+ {
+ UpdateBitmap();
+ }
+ else if (e.PropertyName == VisualElement.IsVisibleProperty.PropertyName)
+ {
+ UpdateText();
+ }
+ else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
+ {
+ UpdateInputTransparent();
+ }
+ else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
+ {
+ UpdateBackgroundColor();
+ }
+
+ ElementPropertyChanged?.Invoke(this, e);
+ }
+
+ protected override void OnLayout(bool changed, int l, int t, int r, int b)
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ if (_imageHeight > -1)
+ {
+ // We've got an image (and no text); it's already centered horizontally,
+ // we just need to adjust the padding so it centers vertically
+ int diff = (b - t - _imageHeight) / 2;
+ diff = Math.Max(diff, 0);
+ SetPadding(0, diff, 0, -diff);
+ }
+
+ base.OnLayout(changed, l, t, r, b);
+ }
+
+ protected void SetTracker(VisualElementTracker tracker)
+ {
+ _tracker = tracker;
+ }
+
+ 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 });
+ }
+ }
+
+ internal virtual void OnNativeFocusChanged(bool hasFocus)
+ {
+ }
+
+ internal virtual void SendVisualElementInitialized(VisualElement element, AView nativeView)
+ {
+ element.SendViewInitialized(nativeView);
+ }
+
+ void Initialize()
+ {
+ // Fixes issues with AppCompatButton elevation (z-index)
+ StateListAnimator = null;
+
+ SoundEffectsEnabled = false;
+ SetOnClickListener(this);
+ SetOnTouchListener(this);
+ AddOnAttachStateChangeListener(this);
+ OnFocusChangeListener = this;
+
+ Tag = this;
+ }
+
+ void UpdateBitmap()
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ FileImageSource elementImage = Button.Image;
+ string imageFile = elementImage?.File;
+ _imageHeight = -1;
+
+ if (elementImage == null || IsNullOrEmpty(imageFile))
+ {
+ SetCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+ return;
+ }
+
+ Drawable image = Context.Resources.GetDrawable(imageFile);
+
+ if (IsNullOrEmpty(Button.Text))
+ {
+ // No text, so no need for relative position; just center the image
+ // There's no option for just plain-old centering, so we'll use Top
+ // (which handles the horizontal centering) and some tricksy padding (in OnLayout)
+ // to handle the vertical centering
+
+ // Clear any previous padding and set the image as top/center
+ SetPadding(0, 0, 0, 0);
+ SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+
+ // Keep track of the image height so we can use it in OnLayout
+ _imageHeight = image.IntrinsicHeight;
+
+ image.Dispose();
+ return;
+ }
+
+ Button.ButtonContentLayout layout = Button.ContentLayout;
+
+ CompoundDrawablePadding = (int)layout.Spacing;
+
+ switch (layout.Position)
+ {
+ case Button.ButtonContentLayout.ImagePosition.Top:
+ SetCompoundDrawablesWithIntrinsicBounds(null, image, null, null);
+ break;
+ case Button.ButtonContentLayout.ImagePosition.Bottom:
+ SetCompoundDrawablesWithIntrinsicBounds(null, null, null, image);
+ break;
+ case Button.ButtonContentLayout.ImagePosition.Right:
+ SetCompoundDrawablesWithIntrinsicBounds(null, null, image, null);
+ break;
+ default:
+ // Defaults to image on the left
+ SetCompoundDrawablesWithIntrinsicBounds(image, null, null, null);
+ break;
+ }
+
+ image?.Dispose();
+ }
+
+ void UpdateFont()
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ Font font = Button.Font;
+
+ if (font == Font.Default && _defaultFontSize == 0f)
+ {
+ return;
+ }
+
+ if (_defaultFontSize == 0f)
+ {
+ _defaultTypeface = Typeface;
+ _defaultFontSize = TextSize;
+ }
+
+ if (font == Font.Default)
+ {
+ Typeface = _defaultTypeface;
+ SetTextSize(ComplexUnitType.Px, _defaultFontSize);
+ }
+ else
+ {
+ Typeface = font.ToTypeface();
+ SetTextSize(ComplexUnitType.Sp, font.ToScaledPixel());
+ }
+ }
+
+ void UpdateIsEnabled()
+ {
+ Enabled = Element.IsEnabled;
+ }
+
+ void UpdateInputTransparent()
+ {
+ _inputTransparent = Element.InputTransparent;
+ }
+
+ void UpdateText()
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ string oldText = Text;
+ Text = Button.Text;
+
+ // If we went from or to having no text, we need to update the image position
+ if (IsNullOrEmpty(oldText) != IsNullOrEmpty(Text))
+ {
+ UpdateBitmap();
+ }
+ }
+
+ void UpdateTextColor()
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ _textColorSwitcher.Value.UpdateTextColor(this, Button.TextColor);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/EffectControlProvider.cs b/Xamarin.Forms.Platform.Android/FastRenderers/EffectControlProvider.cs
new file mode 100644
index 00000000..ebb9fa95
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/EffectControlProvider.cs
@@ -0,0 +1,35 @@
+using Android.Views;
+using AView = Android.Views.View;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ internal class EffectControlProvider : IEffectControlProvider
+ {
+ readonly AView _control;
+ readonly ViewGroup _container;
+
+ public EffectControlProvider(AView control)
+ {
+ _control = control;
+ _container = null;
+ }
+
+ public EffectControlProvider(AView control, ViewGroup container)
+ {
+ _control = control;
+ _container = container;
+ }
+
+ public void RegisterEffect(Effect effect)
+ {
+ var platformEffect = effect as PlatformEffect;
+ if (platformEffect == null)
+ {
+ return;
+ }
+
+ platformEffect.SetControl(_control);
+ platformEffect.SetContainer(_container);
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs
new file mode 100644
index 00000000..14b48812
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/FrameRenderer.cs
@@ -0,0 +1,234 @@
+using System;
+using System.ComponentModel;
+using Android.Content;
+using Android.Support.V7.Widget;
+using Android.Views;
+using Xamarin.Forms.Platform.Android.FastRenderers;
+using AColor = Android.Graphics.Color;
+using AView = Android.Views.View;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ public class FrameRenderer : CardView, IVisualElementRenderer, IEffectControlProvider
+ {
+ float _defaultElevation = -1f;
+ float _defaultCornerRadius = -1f;
+ int? _defaultLabelFor;
+
+ bool _disposed;
+ Frame _element;
+
+ VisualElementPackager _visualElementPackager;
+ VisualElementTracker _visualElementTracker;
+
+ readonly GestureManager _gestureManager;
+ readonly EffectControlProvider _effectControlProvider;
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+
+ public FrameRenderer() : base(Forms.Context)
+ {
+ _gestureManager = new GestureManager(this);
+ _effectControlProvider = new EffectControlProvider(this);
+ }
+
+ protected CardView Control => this;
+
+ protected Frame Element
+ {
+ get { return _element; }
+ set
+ {
+ if (_element == value)
+ return;
+
+ Frame oldElement = _element;
+ _element = value;
+
+ OnElementChanged(new ElementChangedEventArgs<Frame>(oldElement, _element));
+
+ _element?.SendViewInitialized(Control);
+ }
+ }
+
+ VisualElement IVisualElementRenderer.Element => Element;
+ ViewGroup IVisualElementRenderer.ViewGroup => this;
+ AView IVisualElementRenderer.View => this;
+
+ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
+ {
+ Context context = Context;
+ return new SizeRequest(new Size(context.ToPixels(20), context.ToPixels(20)));
+ }
+
+ void IVisualElementRenderer.SetElement(VisualElement element)
+ {
+ var frame = element as Frame;
+ if (frame == null)
+ throw new ArgumentException("Element must be of type Frame");
+ Element = frame;
+
+ if (!string.IsNullOrEmpty(Element.AutomationId))
+ ContentDescription = Element.AutomationId;
+ }
+
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ if (_defaultLabelFor == null)
+ _defaultLabelFor = LabelFor;
+
+ LabelFor = (int)(id ?? _defaultLabelFor);
+ }
+
+ VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker;
+
+ void IVisualElementRenderer.UpdateLayout()
+ {
+ VisualElementTracker tracker = _visualElementTracker;
+ tracker?.UpdateLayout();
+ }
+
+ void IEffectControlProvider.RegisterEffect(Effect effect)
+ {
+ _effectControlProvider.RegisterEffect(effect);
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+
+ if (disposing)
+ {
+ _gestureManager?.Dispose();
+
+ if (_visualElementTracker != null)
+ {
+ _visualElementTracker.Dispose();
+ _visualElementTracker = null;
+ }
+
+ if (_visualElementPackager != null)
+ {
+ _visualElementPackager.Dispose();
+ _visualElementPackager = null;
+ }
+
+ int count = ChildCount;
+ for (var i = 0; i < count; i++)
+ {
+ AView child = GetChildAt(i);
+ child.Dispose();
+ }
+
+ if (Element != null)
+ {
+ Element.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ }
+
+ base.Dispose(disposing);
+ }
+
+ protected virtual void OnElementChanged(ElementChangedEventArgs<Frame> e)
+ {
+ ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
+
+ if (e.OldElement != null)
+ {
+ e.OldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ if (e.NewElement != null)
+ {
+ if (_visualElementTracker == null)
+ {
+ _visualElementTracker = new VisualElementTracker(this);
+ _visualElementPackager = new VisualElementPackager(this);
+ _visualElementPackager.Load();
+ }
+
+ e.NewElement.PropertyChanged += OnElementPropertyChanged;
+ UpdateShadow();
+ UpdateBackgroundColor();
+ UpdateCornerRadius();
+ }
+ }
+
+ protected override void OnLayout(bool changed, int left, int top, int right, int bottom)
+ {
+ if (Element == null)
+ return;
+
+ var children = ((IElementController)Element).LogicalChildren;
+ for (var i = 0; i < children.Count; i++)
+ {
+ var visualElement = children[i] as VisualElement;
+ if (visualElement == null)
+ continue;
+ IVisualElementRenderer renderer = Android.Platform.GetRenderer(visualElement);
+ renderer?.UpdateLayout();
+ }
+ }
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ bool handled;
+ var result = _gestureManager.OnTouchEvent(e, Parent, out handled);
+
+ return handled ? result : base.OnTouchEvent(e);
+ }
+
+ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ ElementPropertyChanged?.Invoke(this, e);
+
+ if (e.PropertyName == Frame.HasShadowProperty.PropertyName)
+ UpdateShadow();
+ else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
+ UpdateBackgroundColor();
+ else if (e.PropertyName == Frame.CornerRadiusProperty.PropertyName)
+ UpdateCornerRadius();
+ }
+
+ void UpdateBackgroundColor()
+ {
+ Color bgColor = Element.BackgroundColor;
+ SetCardBackgroundColor(bgColor.IsDefault ? AColor.White : bgColor.ToAndroid());
+ }
+
+ void UpdateShadow()
+ {
+ float elevation = _defaultElevation;
+
+ if (elevation == -1f)
+ _defaultElevation = elevation = CardElevation;
+
+ if (Element.HasShadow)
+ CardElevation = elevation;
+ else
+ CardElevation = 0f;
+ }
+
+ void UpdateCornerRadius()
+ {
+ if (_defaultCornerRadius == -1f)
+ {
+ _defaultCornerRadius = Radius;
+ }
+
+ float cornerRadius = Element.CornerRadius;
+
+ if (cornerRadius == -1f)
+ cornerRadius = _defaultCornerRadius;
+ else
+ cornerRadius = Context.ToPixels(cornerRadius);
+
+ Radius = cornerRadius;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/GestureManager.cs b/Xamarin.Forms.Platform.Android/FastRenderers/GestureManager.cs
new file mode 100644
index 00000000..8335b9d7
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/GestureManager.cs
@@ -0,0 +1,263 @@
+using System;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
+using System.ComponentModel;
+using Android.Support.V4.View;
+using Android.Views;
+using Object = Java.Lang.Object;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ public class GestureManager : Object, global::Android.Views.View.IOnClickListener, global::Android.Views.View.IOnTouchListener
+ {
+ IVisualElementRenderer _renderer;
+ readonly Lazy<GestureDetector> _gestureDetector;
+ readonly PanGestureHandler _panGestureHandler;
+ readonly PinchGestureHandler _pinchGestureHandler;
+ readonly Lazy<ScaleGestureDetector> _scaleDetector;
+ readonly TapGestureHandler _tapGestureHandler;
+ readonly MotionEventHelper _motionEventHelper = new MotionEventHelper();
+ InnerGestureListener _gestureListener;
+
+ bool _clickable;
+ bool _disposed;
+ bool _inputTransparent;
+ bool _isEnabled;
+
+ NotifyCollectionChangedEventHandler _collectionChangeHandler;
+
+ VisualElement Element => _renderer?.Element;
+
+ View View => _renderer?.Element as View;
+
+ global::Android.Views.View Control => _renderer?.View;
+
+ public GestureManager(IVisualElementRenderer renderer)
+ {
+ _renderer = renderer;
+ _renderer.ElementChanged += OnElementChanged;
+
+ _tapGestureHandler = new TapGestureHandler(() => View);
+ _panGestureHandler = new PanGestureHandler(() => View, Control.Context.FromPixels);
+ _pinchGestureHandler = new PinchGestureHandler(() => View);
+ _gestureDetector =
+ new Lazy<GestureDetector>(
+ () =>
+ new GestureDetector(
+ _gestureListener =
+ new InnerGestureListener(_tapGestureHandler.OnTap, _tapGestureHandler.TapGestureRecognizers,
+ _panGestureHandler.OnPan, _panGestureHandler.OnPanStarted, _panGestureHandler.OnPanComplete)));
+
+ _scaleDetector =
+ new Lazy<ScaleGestureDetector>(
+ () =>
+ new ScaleGestureDetector(Control.Context,
+ new InnerScaleListener(_pinchGestureHandler.OnPinch, _pinchGestureHandler.OnPinchStarted,
+ _pinchGestureHandler.OnPinchEnded), Control.Handler));
+
+ Control.SetOnClickListener(this);
+ Control.SetOnTouchListener(this);
+ }
+
+ public bool OnTouchEvent(MotionEvent e, IViewParent parent, out bool handled)
+ {
+ if (_inputTransparent)
+ {
+ handled = true;
+ return false;
+ }
+
+ if (View.GestureRecognizers.Count == 0)
+ {
+ handled = true;
+ return _motionEventHelper.HandleMotionEvent(parent);
+ }
+
+ handled = false;
+ return false;
+ }
+
+ void OnElementChanged(object sender, VisualElementChangedEventArgs e)
+ {
+ if (e.OldElement != null)
+ {
+ UnsubscribeGestureRecognizers(e.OldElement);
+ e.OldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ if (e.NewElement != null)
+ {
+ UpdateGestureRecognizers(true);
+ SubscribeGestureRecognizers(e.NewElement);
+ _motionEventHelper.UpdateElement(e.NewElement);
+ e.NewElement.PropertyChanged += OnElementPropertyChanged;
+ }
+
+ UpdateInputTransparent();
+ UpdateIsEnabled();
+ }
+
+ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
+ UpdateInputTransparent();
+ else if (e.PropertyName == VisualElement.IsEnabledProperty.PropertyName)
+ UpdateIsEnabled();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_disposed)
+ {
+ return;
+ }
+
+ _disposed = true;
+
+ if (disposing)
+ {
+ if (Element != null)
+ {
+ Element.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ Control.SetOnClickListener(null);
+ Control.SetOnTouchListener(null);
+
+ if (_gestureListener != null)
+ {
+ _gestureListener.Dispose();
+ _gestureListener = null;
+ }
+
+ if (_renderer?.Element != null)
+ {
+ UnsubscribeGestureRecognizers(Element);
+ }
+
+ _renderer = null;
+ }
+
+ base.Dispose(disposing);
+ }
+
+ void global::Android.Views.View.IOnClickListener.OnClick(global::Android.Views.View v)
+ {
+ _tapGestureHandler.OnSingleClick();
+ }
+
+ bool global::Android.Views.View.IOnTouchListener.OnTouch(global::Android.Views.View v, MotionEvent e)
+ {
+ if (!_isEnabled)
+ return true;
+
+ if (_inputTransparent)
+ return false;
+
+ var handled = false;
+ if (_pinchGestureHandler.IsPinchSupported)
+ {
+ if (!_scaleDetector.IsValueCreated)
+ ScaleGestureDetectorCompat.SetQuickScaleEnabled(_scaleDetector.Value, true);
+ handled = _scaleDetector.Value.OnTouchEvent(e);
+ }
+
+ if (_gestureDetector.IsValueCreated && _gestureDetector.Value.Handle == IntPtr.Zero)
+ {
+ // This gesture detector has already been disposed, probably because it's on a cell which is going away
+ return handled;
+ }
+
+ // It's very important that the gesture detection happen first here
+ // if we check handled first, we might short-circuit and never check for tap/pan
+ return _gestureDetector.Value.OnTouchEvent(e) || handled;
+ }
+
+ void HandleGestureRecognizerCollectionChanged(object sender,
+ NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
+ {
+ UpdateGestureRecognizers();
+ }
+
+ void SubscribeGestureRecognizers(VisualElement element)
+ {
+ var view = element as View;
+ if (view == null)
+ {
+ return;
+ }
+
+ if (_collectionChangeHandler == null)
+ {
+ _collectionChangeHandler = HandleGestureRecognizerCollectionChanged;
+ }
+
+ var observableCollection = (ObservableCollection<IGestureRecognizer>)view.GestureRecognizers;
+ if (observableCollection != null)
+ {
+ observableCollection.CollectionChanged += _collectionChangeHandler;
+ }
+ }
+
+ void UnsubscribeGestureRecognizers(VisualElement element)
+ {
+ var view = element as View;
+ if (view == null || _collectionChangeHandler == null)
+ {
+ return;
+ }
+
+ var observableCollection = (ObservableCollection<IGestureRecognizer>)view.GestureRecognizers;
+ if (observableCollection != null)
+ {
+ observableCollection.CollectionChanged -= _collectionChangeHandler;
+ }
+ }
+
+ void UpdateClickable(bool force = false)
+ {
+ var view = Element as View;
+ if (view == null)
+ {
+ return;
+ }
+
+ bool newValue = view.ShouldBeMadeClickable();
+ if (force || _clickable != newValue)
+ {
+ Control.Clickable = newValue;
+ _clickable = newValue;
+ }
+ }
+
+ void UpdateGestureRecognizers(bool forceClick = false)
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ UpdateClickable(forceClick);
+ }
+
+ void UpdateInputTransparent()
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ _inputTransparent = Element.InputTransparent;
+ }
+
+ void UpdateIsEnabled()
+ {
+ if (Element == null)
+ {
+ return;
+ }
+
+ _isEnabled = Element.IsEnabled;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs
new file mode 100644
index 00000000..6a43d193
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/ImageRenderer.cs
@@ -0,0 +1,163 @@
+using System;
+using System.ComponentModel;
+using AImageView = Android.Widget.ImageView;
+using AView = Android.Views.View;
+using Android.Views;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ public class ImageRenderer : AImageView, IVisualElementRenderer, IImageRendererController
+ {
+ bool _disposed;
+ Image _element;
+ bool _skipInvalidate;
+ int? _defaultLabelFor;
+ VisualElementTracker _visualElementTracker;
+ VisualElementRenderer _visualElementRenderer;
+
+ protected override void Dispose(bool disposing)
+ {
+ base.Dispose(disposing);
+
+ if (_disposed)
+ return;
+
+ _disposed = true;
+
+ if (!disposing)
+ return;
+
+ if (_visualElementTracker != null)
+ {
+ _visualElementTracker.Dispose();
+ _visualElementTracker = null;
+ }
+
+ if (_visualElementRenderer != null)
+ {
+ _visualElementRenderer.Dispose();
+ _visualElementRenderer = null;
+ }
+
+ if (_element != null)
+ _element.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ public override void Invalidate()
+ {
+ if (_skipInvalidate)
+ {
+ _skipInvalidate = false;
+ return;
+ }
+
+ base.Invalidate();
+ }
+
+ protected virtual void OnElementChanged(ElementChangedEventArgs<Image> e)
+ {
+ this.UpdateBitmap(e.NewElement, e.OldElement);
+ UpdateAspect();
+
+ ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
+ }
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ bool handled;
+ var result = _visualElementRenderer.OnTouchEvent(e, Parent, out handled);
+
+ return handled ? result : base.OnTouchEvent(e);
+ }
+
+ protected virtual Size MinimumSize()
+ {
+ return new Size();
+ }
+
+ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
+ {
+ Measure(widthConstraint, heightConstraint);
+ return new SizeRequest(new Size(MeasuredWidth, MeasuredHeight), MinimumSize());
+ }
+
+ void IVisualElementRenderer.SetElement(VisualElement element)
+ {
+ if (element == null)
+ throw new ArgumentNullException(nameof(element));
+
+ var image = element as Image;
+ if (image == null)
+ throw new ArgumentException("Element is not of type " + typeof(Image), nameof(element));
+
+ Image oldElement = _element;
+ _element = image;
+
+ Internals.Performance.Start();
+
+ if (oldElement != null)
+ oldElement.PropertyChanged -= OnElementPropertyChanged;
+
+ element.PropertyChanged += OnElementPropertyChanged;
+
+ if (_visualElementTracker == null)
+ _visualElementTracker = new VisualElementTracker(this);
+
+ if (_visualElementRenderer == null)
+ {
+ _visualElementRenderer = new VisualElementRenderer(this);
+ }
+
+ Internals.Performance.Stop();
+
+ OnElementChanged(new ElementChangedEventArgs<Image>(oldElement, _element));
+
+ _element?.SendViewInitialized(Control);
+ }
+
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ if (_defaultLabelFor == null)
+ _defaultLabelFor = LabelFor;
+
+ LabelFor = (int)(id ?? _defaultLabelFor);
+ }
+
+ void IVisualElementRenderer.UpdateLayout() => _visualElementTracker?.UpdateLayout();
+
+ VisualElement IVisualElementRenderer.Element => _element;
+
+ VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker;
+
+ AView IVisualElementRenderer.View => this;
+
+ ViewGroup IVisualElementRenderer.ViewGroup => null;
+
+ void IImageRendererController.SkipInvalidate() => _skipInvalidate = true;
+
+ protected AImageView Control => this;
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+
+ public ImageRenderer() : base(Forms.Context)
+ {
+ }
+
+ protected void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == Image.SourceProperty.PropertyName)
+ this.UpdateBitmap(_element);
+ else if (e.PropertyName == Image.AspectProperty.PropertyName)
+ UpdateAspect();
+
+ ElementPropertyChanged?.Invoke(this, e);
+ }
+
+ void UpdateAspect()
+ {
+ ScaleType type = _element.Aspect.ToScaleType();
+ SetScaleType(type);
+ }
+ }
+}
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs
new file mode 100644
index 00000000..b2f2d827
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs
@@ -0,0 +1,313 @@
+using System;
+using System.ComponentModel;
+using Android.Content.Res;
+using Android.Graphics;
+using Android.Text;
+using Android.Util;
+using Android.Views;
+using AView = Android.Views.View;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ public class LabelRenderer : FormsTextView, IVisualElementRenderer
+ {
+ int? _defaultLabelFor;
+ bool _disposed;
+ Label _element;
+ readonly ColorStateList _labelTextColorDefault;
+ int _lastConstraintHeight;
+ int _lastConstraintWidth;
+ SizeRequest? _lastSizeRequest;
+ float _lastTextSize = -1f;
+ Typeface _lastTypeface;
+ Color _lastUpdateColor = Color.Default;
+ VisualElementTracker _visualElementTracker;
+ VisualElementRenderer _visualElementRenderer;
+
+ bool _wasFormatted;
+
+ public LabelRenderer() : base(Forms.Context)
+ {
+ _labelTextColorDefault = TextColors;
+ _visualElementRenderer = new VisualElementRenderer(this);
+ }
+
+ public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+
+ VisualElement IVisualElementRenderer.Element => Element;
+
+ VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker;
+
+ AView IVisualElementRenderer.View => this;
+
+ ViewGroup IVisualElementRenderer.ViewGroup => null;
+
+ protected Label Element
+ {
+ get { return _element; }
+ set
+ {
+ if (_element == value)
+ return;
+
+ Label oldElement = _element;
+ _element = value;
+
+ OnElementChanged(new ElementChangedEventArgs<Label>(oldElement, _element));
+
+ _element?.SendViewInitialized(this);
+ }
+ }
+
+ SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint)
+ {
+ if (_lastSizeRequest.HasValue)
+ {
+ // if we are measuring the same thing, no need to waste the time
+ bool canRecycleLast = widthConstraint == _lastConstraintWidth && heightConstraint == _lastConstraintHeight;
+
+ if (!canRecycleLast)
+ {
+ // if the last time we measured the returned size was all around smaller than the passed constraint
+ // and the constraint is bigger than the last size request, we can assume the newly measured size request
+ // will not change either.
+ int lastConstraintWidthSize = MeasureSpecFactory.GetSize(_lastConstraintWidth);
+ int lastConstraintHeightSize = MeasureSpecFactory.GetSize(_lastConstraintHeight);
+
+ int currentConstraintWidthSize = MeasureSpecFactory.GetSize(widthConstraint);
+ int currentConstraintHeightSize = MeasureSpecFactory.GetSize(heightConstraint);
+
+ bool lastWasSmallerThanConstraints = _lastSizeRequest.Value.Request.Width < lastConstraintWidthSize && _lastSizeRequest.Value.Request.Height < lastConstraintHeightSize;
+
+ bool currentConstraintsBiggerThanLastRequest = currentConstraintWidthSize >= _lastSizeRequest.Value.Request.Width && currentConstraintHeightSize >= _lastSizeRequest.Value.Request.Height;
+
+ canRecycleLast = lastWasSmallerThanConstraints && currentConstraintsBiggerThanLastRequest;
+ }
+
+ if (canRecycleLast)
+ return _lastSizeRequest.Value;
+ }
+
+ Measure(widthConstraint, heightConstraint);
+ SizeRequest result = new SizeRequest(new Size(MeasuredWidth, MeasuredHeight), new Size());
+ result.Minimum = new Size(Math.Min(Context.ToPixels(10), result.Request.Width), result.Request.Height);
+
+ _lastConstraintWidth = widthConstraint;
+ _lastConstraintHeight = heightConstraint;
+ _lastSizeRequest = result;
+
+ return result;
+ }
+
+ void IVisualElementRenderer.SetElement(VisualElement element)
+ {
+ var label = element as Label;
+ if (label == null)
+ throw new ArgumentException("Element must be of type Label");
+
+ Element = label;
+ }
+
+ void IVisualElementRenderer.SetLabelFor(int? id)
+ {
+ if (_defaultLabelFor == null)
+ _defaultLabelFor = LabelFor;
+
+ LabelFor = (int)(id ?? _defaultLabelFor);
+ }
+
+ void IVisualElementRenderer.UpdateLayout()
+ {
+ VisualElementTracker tracker = _visualElementTracker;
+ tracker?.UpdateLayout();
+ }
+
+ protected override void Dispose(bool disposing)
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+
+ if (disposing)
+ {
+ _disposed = true;
+
+ if (_visualElementTracker != null)
+ {
+ _visualElementTracker.Dispose();
+ _visualElementTracker = null;
+ }
+
+ if (_visualElementRenderer != null)
+ {
+ _visualElementRenderer.Dispose();
+ _visualElementRenderer = null;
+ }
+
+ if (Element != null)
+ {
+ Element.PropertyChanged -= OnElementPropertyChanged;
+ }
+ }
+
+ base.Dispose(disposing);
+ }
+
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ bool handled;
+ var result = _visualElementRenderer.OnTouchEvent(e, Parent, out handled);
+
+ return handled ? result : base.OnTouchEvent(e);
+ }
+
+ protected virtual void OnElementChanged(ElementChangedEventArgs<Label> e)
+ {
+ ElementChanged?.Invoke(this, new VisualElementChangedEventArgs(e.OldElement, e.NewElement));
+
+ if (e.OldElement != null)
+ {
+ e.OldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ if (e.NewElement != null)
+ {
+ if (_visualElementTracker == null)
+ {
+ _visualElementTracker = new VisualElementTracker(this);
+ }
+
+ e.NewElement.PropertyChanged += OnElementPropertyChanged;
+
+ SkipNextInvalidate();
+ UpdateText();
+ if (e.OldElement?.LineBreakMode != e.NewElement.LineBreakMode)
+ UpdateLineBreakMode();
+ if (e.OldElement?.HorizontalTextAlignment != e.NewElement.HorizontalTextAlignment
+ || e.OldElement?.VerticalTextAlignment != e.NewElement.VerticalTextAlignment)
+ UpdateGravity();
+ }
+ }
+
+ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ ElementPropertyChanged?.Invoke(this, e);
+
+ if (e.PropertyName == Label.HorizontalTextAlignmentProperty.PropertyName || e.PropertyName == Label.VerticalTextAlignmentProperty.PropertyName)
+ UpdateGravity();
+ else if (e.PropertyName == Label.TextColorProperty.PropertyName)
+ UpdateText();
+ else if (e.PropertyName == Label.FontProperty.PropertyName)
+ UpdateText();
+ else if (e.PropertyName == Label.LineBreakModeProperty.PropertyName)
+ UpdateLineBreakMode();
+ else if (e.PropertyName == Label.TextProperty.PropertyName || e.PropertyName == Label.FormattedTextProperty.PropertyName)
+ UpdateText();
+ }
+
+ void UpdateColor()
+ {
+ Color c = Element.TextColor;
+ if (c == _lastUpdateColor)
+ return;
+ _lastUpdateColor = c;
+
+ if (c.IsDefault)
+ SetTextColor(_labelTextColorDefault);
+ else
+ SetTextColor(c.ToAndroid());
+ }
+
+ void UpdateFont()
+ {
+#pragma warning disable 618 // We will need to update this when .Font goes away
+ Font f = Element.Font;
+#pragma warning restore 618
+
+ Typeface newTypeface = f.ToTypeface();
+ if (newTypeface != _lastTypeface)
+ {
+ Typeface = newTypeface;
+ _lastTypeface = newTypeface;
+ }
+
+ float newTextSize = f.ToScaledPixel();
+ if (newTextSize != _lastTextSize)
+ {
+ SetTextSize(ComplexUnitType.Sp, newTextSize);
+ _lastTextSize = newTextSize;
+ }
+ }
+
+ void UpdateGravity()
+ {
+ Label label = Element;
+
+ Gravity = label.HorizontalTextAlignment.ToHorizontalGravityFlags() | label.VerticalTextAlignment.ToVerticalGravityFlags();
+
+ _lastSizeRequest = null;
+ }
+
+ void UpdateLineBreakMode()
+ {
+ SetSingleLine(false);
+ switch (Element.LineBreakMode)
+ {
+ case LineBreakMode.NoWrap:
+ SetMaxLines(1);
+ Ellipsize = null;
+ break;
+ case LineBreakMode.WordWrap:
+ Ellipsize = null;
+ SetMaxLines(100);
+ break;
+ case LineBreakMode.CharacterWrap:
+ Ellipsize = null;
+ SetMaxLines(100);
+ break;
+ case LineBreakMode.HeadTruncation:
+ SetMaxLines(1);
+ Ellipsize = TextUtils.TruncateAt.Start;
+ break;
+ case LineBreakMode.TailTruncation:
+ SetMaxLines(1);
+ Ellipsize = TextUtils.TruncateAt.End;
+ break;
+ case LineBreakMode.MiddleTruncation:
+ SetMaxLines(1);
+ Ellipsize = TextUtils.TruncateAt.Middle;
+ break;
+ }
+ _lastSizeRequest = null;
+ }
+
+ void UpdateText()
+ {
+ if (Element.FormattedText != null)
+ {
+ FormattedString formattedText = Element.FormattedText ?? Element.Text;
+#pragma warning disable 618 // We will need to update this when .Font goes away
+ TextFormatted = formattedText.ToAttributed(Element.Font, Element.TextColor, this);
+#pragma warning restore 618
+ _wasFormatted = true;
+ }
+ else
+ {
+ if (_wasFormatted)
+ {
+ SetTextColor(_labelTextColorDefault);
+ _lastUpdateColor = Color.Default;
+ }
+ Text = Element.Text;
+ UpdateColor();
+ UpdateFont();
+
+ _wasFormatted = false;
+ }
+
+ _lastSizeRequest = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs
new file mode 100644
index 00000000..d94cfd01
--- /dev/null
+++ b/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs
@@ -0,0 +1,98 @@
+using System;
+using System.ComponentModel;
+using Android.Views;
+using AView = Android.Views.View;
+using Object = Java.Lang.Object;
+
+namespace Xamarin.Forms.Platform.Android.FastRenderers
+{
+ // TODO hartez 2017/03/03 14:11:17 It's weird that this class is called VisualElementRenderer but it doesn't implement that interface. The name should probably be different.
+ public class VisualElementRenderer : IDisposable, IEffectControlProvider
+ {
+ bool _disposed;
+
+ IVisualElementRenderer _renderer;
+ readonly GestureManager _gestureManager;
+ readonly AccessibilityProvider _accessibilityProvider;
+ readonly EffectControlProvider _effectControlProvider;
+
+ public VisualElementRenderer(IVisualElementRenderer renderer)
+ {
+ _renderer = renderer;
+ _renderer.ElementPropertyChanged += OnElementPropertyChanged;
+ _renderer.ElementChanged += OnElementChanged;
+ _gestureManager = new GestureManager(_renderer);
+ _accessibilityProvider = new AccessibilityProvider(_renderer);
+ _effectControlProvider = new EffectControlProvider(_renderer?.View);
+ }
+
+ VisualElement Element => _renderer?.Element;
+
+ AView Control => _renderer?.View;
+
+ void IEffectControlProvider.RegisterEffect(Effect effect)
+ {
+ _effectControlProvider.RegisterEffect(effect);
+ }
+
+ public void UpdateBackgroundColor(Color? color = null)
+ {
+ if (Element == null || Control == null)
+ return;
+
+ Control.SetBackgroundColor((color ?? Element.BackgroundColor).ToAndroid());
+ }
+
+ public bool OnTouchEvent(MotionEvent e, IViewParent parent, out bool handled)
+ {
+ return _gestureManager.OnTouchEvent(e, parent, out handled);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+
+ protected void Dispose(bool disposing)
+ {
+ if (_disposed)
+ return;
+
+ _disposed = true;
+
+ if (disposing)
+ {
+ _gestureManager?.Dispose();
+ _accessibilityProvider?.Dispose();
+
+ if (_renderer != null)
+ {
+ _renderer.ElementChanged -= OnElementChanged;
+ _renderer.ElementPropertyChanged -= OnElementPropertyChanged;
+ _renderer = null;
+ }
+ }
+ }
+
+ void OnElementChanged(object sender, VisualElementChangedEventArgs e)
+ {
+ if (e.OldElement != null)
+ {
+ e.OldElement.PropertyChanged -= OnElementPropertyChanged;
+ }
+
+ if (e.NewElement != null)
+ {
+ e.NewElement.PropertyChanged += OnElementPropertyChanged;
+ UpdateBackgroundColor();
+ }
+ }
+
+ void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
+ {
+ if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
+ UpdateBackgroundColor();
+ }
+ }
+} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs
index da565ce2..71817db2 100644
--- a/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs
@@ -1,4 +1,5 @@
using System;
+using System.ComponentModel;
using Android.Views;
using AView = Android.Views.View;
@@ -10,10 +11,15 @@ namespace Xamarin.Forms.Platform.Android
VisualElementTracker Tracker { get; }
+ [Obsolete("Use View instead")]
ViewGroup ViewGroup { get; }
+ AView View { get; }
+
event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+
SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint);
void SetElement(VisualElement element);
diff --git a/Xamarin.Forms.Platform.Android/Platform.cs b/Xamarin.Forms.Platform.Android/Platform.cs
index 004531a1..3f969091 100644
--- a/Xamarin.Forms.Platform.Android/Platform.cs
+++ b/Xamarin.Forms.Platform.Android/Platform.cs
@@ -206,11 +206,11 @@ namespace Xamarin.Forms.Platform.Android
{
if (animated)
{
- modalRenderer.ViewGroup.Animate().Alpha(0).ScaleX(0.8f).ScaleY(0.8f).SetDuration(250).SetListener(new GenericAnimatorListener
+ modalRenderer.View.Animate().Alpha(0).ScaleX(0.8f).ScaleY(0.8f).SetDuration(250).SetListener(new GenericAnimatorListener
{
OnEnd = a =>
{
- modalRenderer.ViewGroup.RemoveFromParent();
+ modalRenderer.View.RemoveFromParent();
modalRenderer.Dispose();
source.TrySetResult(modal);
CurrentPageController?.SendAppearing();
@@ -219,7 +219,7 @@ namespace Xamarin.Forms.Platform.Android
}
else
{
- modalRenderer.ViewGroup.RemoveFromParent();
+ modalRenderer.View.RemoveFromParent();
modalRenderer.Dispose();
source.TrySetResult(modal);
CurrentPageController?.SendAppearing();
@@ -534,7 +534,7 @@ namespace Xamarin.Forms.Platform.Android
if (layout)
view.Layout(new Rectangle(0, 0, _context.FromPixels(_renderer.Width), _context.FromPixels(_renderer.Height)));
- _renderer.AddView(renderView.ViewGroup);
+ _renderer.AddView(renderView.View);
}
#pragma warning disable 618 // This may need to be updated to work with TabLayout/AppCompat
@@ -767,19 +767,19 @@ namespace Xamarin.Forms.Platform.Android
SetRenderer(modal, modalRenderer);
if (modal.BackgroundColor == Color.Default && modal.BackgroundImage == null)
- modalRenderer.ViewGroup.SetWindowBackground();
+ modalRenderer.View.SetWindowBackground();
}
modalRenderer.Element.Layout(new Rectangle(0, 0, _context.FromPixels(_renderer.Width), _context.FromPixels(_renderer.Height)));
- _renderer.AddView(modalRenderer.ViewGroup);
+ _renderer.AddView(modalRenderer.View);
var source = new TaskCompletionSource<bool>();
NavAnimationInProgress = true;
if (animated)
{
- modalRenderer.ViewGroup.Alpha = 0;
- modalRenderer.ViewGroup.ScaleX = 0.8f;
- modalRenderer.ViewGroup.ScaleY = 0.8f;
- modalRenderer.ViewGroup.Animate().Alpha(1).ScaleX(1).ScaleY(1).SetDuration(250).SetListener(new GenericAnimatorListener
+ modalRenderer.View.Alpha = 0;
+ modalRenderer.View.ScaleX = 0.8f;
+ modalRenderer.View.ScaleY = 0.8f;
+ modalRenderer.View.Animate().Alpha(1).ScaleX(1).ScaleY(1).SetDuration(250).SetListener(new GenericAnimatorListener
{
OnEnd = a =>
{
diff --git a/Xamarin.Forms.Platform.Android/PlatformEffect.cs b/Xamarin.Forms.Platform.Android/PlatformEffect.cs
index 6830b722..716fce7f 100644
--- a/Xamarin.Forms.Platform.Android/PlatformEffect.cs
+++ b/Xamarin.Forms.Platform.Android/PlatformEffect.cs
@@ -1,3 +1,4 @@
+using System;
using Android.Views;
using AView = Android.Views.View;
diff --git a/Xamarin.Forms.Platform.Android/RendererPool.cs b/Xamarin.Forms.Platform.Android/RendererPool.cs
index 48665c81..51913f61 100644
--- a/Xamarin.Forms.Platform.Android/RendererPool.cs
+++ b/Xamarin.Forms.Platform.Android/RendererPool.cs
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
+using Android.Views;
namespace Xamarin.Forms.Platform.Android
{
@@ -60,18 +61,20 @@ namespace Xamarin.Forms.Platform.Android
if (renderer == null)
continue;
- if (renderer.ViewGroup.Parent != _parent.ViewGroup)
+ if (renderer.View.Parent != _parent.View)
continue;
- renderer.ViewGroup.RemoveFromParent();
+ renderer.View.RemoveFromParent();
Platform.SetRenderer(child, null);
PushRenderer(renderer);
}
}
- if (_parent.ViewGroup.ChildCount != 0)
- _parent.ViewGroup.RemoveAllViews();
+ var viewGroup = _parent.View as ViewGroup;
+
+ if (viewGroup != null && viewGroup.ChildCount != 0)
+ viewGroup.RemoveAllViews();
}
void PushRenderer(IVisualElementRenderer renderer)
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs
index e07a2be5..7bb97945 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ButtonRenderer.cs
@@ -26,6 +26,7 @@ namespace Xamarin.Forms.Platform.Android
public ButtonRenderer()
{
+ System.Diagnostics.Debug.WriteLine("Slow Button!");
AutoPackage = false;
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs b/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs
index efee571d..c31e8e69 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs
@@ -55,7 +55,7 @@ namespace Xamarin.Forms.Platform.Android
Page destroyedPage = holder.Instance.Item2;
IVisualElementRenderer renderer = Platform.GetRenderer(destroyedPage);
- renderer.ViewGroup.RemoveFromParent();
+ renderer.View.RemoveFromParent();
holder.Instance.Item1.RemoveFromParent();
}
@@ -90,7 +90,7 @@ namespace Xamarin.Forms.Platform.Android
Platform.SetRenderer(child, Platform.CreateRenderer(child));
IVisualElementRenderer renderer = Platform.GetRenderer(child);
- renderer.ViewGroup.RemoveFromParent();
+ renderer.View.RemoveFromParent();
ViewGroup frame = new PageContainer(_context, renderer);
@@ -130,7 +130,7 @@ namespace Xamarin.Forms.Platform.Android
IVisualElementRenderer childPageRenderer = Platform.GetRenderer(childPage);
if (childPageRenderer != null)
{
- childPageRenderer.ViewGroup.RemoveFromParent();
+ childPageRenderer.View.RemoveFromParent();
childPageRenderer.Dispose();
Platform.SetRenderer(childPage, null);
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs b/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs
index 311db6b8..5b3002ce 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs
@@ -30,7 +30,7 @@ namespace Xamarin.Forms.Platform.Android
return;
IVisualElementRenderer renderer = Platform.GetRenderer(viewCell.View);
- (renderer?.ViewGroup?.GetChildAt(0) as EditText)?.SetOnTouchListener(this);
+ GetEditText(renderer)?.SetOnTouchListener(this);
foreach (Element descendant in viewCell.View.Descendants())
{
@@ -38,8 +38,14 @@ namespace Xamarin.Forms.Platform.Android
if (element == null)
continue;
renderer = Platform.GetRenderer(element);
- (renderer?.ViewGroup?.GetChildAt(0) as EditText)?.SetOnTouchListener(this);
+ GetEditText(renderer)?.SetOnTouchListener(this);
}
}
+
+ internal EditText GetEditText(IVisualElementRenderer renderer)
+ {
+ var viewGroup = renderer?.View as ViewGroup;
+ return viewGroup?.GetChildAt(0) as EditText;
+ }
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/FormsImageView.cs b/Xamarin.Forms.Platform.Android/Renderers/FormsImageView.cs
index ae32e16c..dc0bd2fc 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/FormsImageView.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/FormsImageView.cs
@@ -5,7 +5,7 @@ using Android.Widget;
namespace Xamarin.Forms.Platform.Android
{
- internal class FormsImageView : ImageView
+ internal class FormsImageView : ImageView, IImageRendererController
{
bool _skipInvalidate;
diff --git a/Xamarin.Forms.Platform.Android/Renderers/FormsTextView.cs b/Xamarin.Forms.Platform.Android/Renderers/FormsTextView.cs
index 1dc25ea9..2b2bcb7a 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/FormsTextView.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/FormsTextView.cs
@@ -6,7 +6,7 @@ using Android.Widget;
namespace Xamarin.Forms.Platform.Android
{
- internal class FormsTextView : TextView
+ public class FormsTextView : TextView
{
bool _skip;
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs
index fee05f1b..57937d89 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ImageRenderer.cs
@@ -1,14 +1,18 @@
using System;
using System.ComponentModel;
-using System.IO;
-using System.Threading.Tasks;
using Android.Graphics;
using Android.Views;
using AImageView = Android.Widget.ImageView;
using Xamarin.Forms.Internals;
+using static Xamarin.Forms.Platform.Android.ImageViewExtensions;
namespace Xamarin.Forms.Platform.Android
{
+ internal interface IImageRendererController
+ {
+ void SkipInvalidate();
+ }
+
public class ImageRenderer : ViewRenderer<Image, AImageView>
{
bool _isDisposed;
@@ -16,6 +20,7 @@ namespace Xamarin.Forms.Platform.Android
public ImageRenderer()
{
+ System.Diagnostics.Debug.WriteLine(">>>>> Old Image Renderer");
AutoPackage = false;
}
@@ -45,8 +50,9 @@ namespace Xamarin.Forms.Platform.Android
}
_motionEventHelper.UpdateElement(e.NewElement);
+
+ Control.UpdateBitmap(e.NewElement, e.OldElement);
- UpdateBitmap(e.OldElement);
UpdateAspect();
}
@@ -55,7 +61,7 @@ namespace Xamarin.Forms.Platform.Android
base.OnElementPropertyChanged(sender, e);
if (e.PropertyName == Image.SourceProperty.PropertyName)
- UpdateBitmap();
+ Control.UpdateBitmap(Element);
else if (e.PropertyName == Image.AspectProperty.PropertyName)
UpdateAspect();
}
@@ -66,66 +72,12 @@ namespace Xamarin.Forms.Platform.Android
Control.SetScaleType(type);
}
- async void UpdateBitmap(Image previous = null)
- {
- if (Device.IsInvokeRequired)
- throw new InvalidOperationException("Image Bitmap must not be updated from background thread");
-
- if (previous != null && Equals(previous.Source, Element.Source))
- return;
-
- ((IImageController)Element).SetIsLoading(true);
+ public override bool OnTouchEvent(MotionEvent e)
+ {
+ if (base.OnTouchEvent(e))
+ return true;
- var formsImageView = Control as FormsImageView;
- formsImageView?.SkipInvalidate();
-
- Control.SetImageResource(global::Android.Resource.Color.Transparent);
-
- ImageSource source = Element.Source;
- Bitmap bitmap = null;
- IImageSourceHandler handler;
-
- if (source != null && (handler = Internals.Registrar.Registered.GetHandler<IImageSourceHandler>(source.GetType())) != null)
- {
- try
- {
- bitmap = await handler.LoadImageAsync(source, Context);
- }
- catch (TaskCanceledException)
- {
- }
- catch (IOException ex)
- {
- Log.Warning("Xamarin.Forms.Platform.Android.ImageRenderer", "Error updating bitmap: {0}", ex);
- }
- }
-
- if (Element == null || !Equals(Element.Source, source))
- {
- bitmap?.Dispose();
- return;
- }
-
- if (!_isDisposed)
- {
- if (bitmap == null && source is FileImageSource)
- Control.SetImageResource(ResourceManager.GetDrawableByName(((FileImageSource)source).File));
- else
- Control.SetImageBitmap(bitmap);
-
- bitmap?.Dispose();
-
- ((IImageController)Element).SetIsLoading(false);
- ((IVisualElementController)Element).NativeSizeChanged();
- }
- }
-
- public override bool OnTouchEvent(MotionEvent e)
- {
- if (base.OnTouchEvent(e))
- return true;
-
- return _motionEventHelper.HandleMotionEvent(Parent);
- }
- }
+ return _motionEventHelper.HandleMotionEvent(Parent);
+ }
+ }
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs
index a0906915..bd241c1a 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs
@@ -45,14 +45,14 @@ namespace Xamarin.Forms.Platform.Android
if (_headerRenderer != null)
{
- _headerRenderer.ViewGroup.RemoveAllViews();
+ (_headerRenderer.View as ViewGroup)?.RemoveAllViews();
_headerRenderer.Dispose();
_headerRenderer = null;
}
if (_footerRenderer != null)
{
- _footerRenderer.ViewGroup.RemoveAllViews();
+ (_footerRenderer.View as ViewGroup)?.RemoveAllViews();
_footerRenderer.Dispose();
_footerRenderer = null;
}
@@ -352,12 +352,12 @@ namespace Xamarin.Forms.Platform.Android
set
{
if (_child != null)
- RemoveView(_child.ViewGroup);
+ RemoveView(_child.View);
_child = value;
if (value != null)
- AddView(value.ViewGroup);
+ AddView(value.View);
}
}
@@ -389,7 +389,7 @@ namespace Xamarin.Forms.Platform.Android
int widthSpec = MeasureSpecFactory.MakeMeasureSpec((int)ctx.ToPixels(width), MeasureSpecMode.Exactly);
int heightSpec = MeasureSpecFactory.MakeMeasureSpec((int)ctx.ToPixels(request.Request.Height), MeasureSpecMode.Exactly);
- _child.ViewGroup.Measure(widthMeasureSpec, heightMeasureSpec);
+ _child.View.Measure(widthMeasureSpec, heightMeasureSpec);
SetMeasuredDimension(widthSpec, heightSpec);
}
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs
index a7bebf1e..fd028df1 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs
@@ -54,12 +54,12 @@ namespace Xamarin.Forms.Platform.Android
if (renderer == null)
Platform.SetRenderer(childView, renderer = Platform.CreateRenderer(childView));
- if (renderer.ViewGroup.Parent != this)
+ if (renderer.View.Parent != this)
{
- if (renderer.ViewGroup.Parent != null)
- renderer.ViewGroup.RemoveFromParent();
+ if (renderer.View.Parent != null)
+ renderer.View.RemoveFromParent();
SetDefaultBackgroundColor(renderer);
- AddView(renderer.ViewGroup);
+ AddView(renderer.View);
renderer.UpdateLayout();
}
}
@@ -148,7 +148,7 @@ namespace Xamarin.Forms.Platform.Android
if (ChildView.BackgroundColor == Color.Default)
{
TypedArray colors = Context.Theme.ObtainStyledAttributes(new[] { global::Android.Resource.Attribute.ColorBackground });
- renderer.ViewGroup.SetBackgroundColor(new global::Android.Graphics.Color(colors.GetColor(0, 0)));
+ renderer.View.SetBackgroundColor(new global::Android.Graphics.Color(colors.GetColor(0, 0)));
}
}
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
index d18781a7..7e744bc7 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs
@@ -73,6 +73,13 @@ namespace Xamarin.Forms.Platform.Android
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+ event EventHandler<PropertyChangedEventArgs> IVisualElementRenderer.ElementPropertyChanged
+ {
+ add { ElementPropertyChanged += value; }
+ remove { ElementPropertyChanged -= value; }
+ }
+
public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
{
Measure(widthConstraint, heightConstraint);
@@ -142,10 +149,8 @@ namespace Xamarin.Forms.Platform.Android
Tracker.UpdateLayout();
}
- public ViewGroup ViewGroup
- {
- get { return this; }
- }
+ public ViewGroup ViewGroup => this;
+ AView IVisualElementRenderer.View => this;
protected override void Dispose(bool disposing)
{
@@ -237,6 +242,7 @@ namespace Xamarin.Forms.Platform.Android
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
+ ElementPropertyChanged?.Invoke(this, e);
if (e.PropertyName == "Master")
UpdateMaster();
else if (e.PropertyName == "Detail")
diff --git a/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs
index bf6540b9..5d678287 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs
@@ -183,13 +183,13 @@ namespace Xamarin.Forms.Platform.Android
void RemovePage(Page page)
{
IVisualElementRenderer rendererToRemove = Platform.GetRenderer(page);
- PageContainer containerToRemove = rendererToRemove == null ? null : (PageContainer)rendererToRemove.ViewGroup.Parent;
+ PageContainer containerToRemove = rendererToRemove == null ? null : (PageContainer)rendererToRemove.View.Parent;
containerToRemove.RemoveFromParent();
if (rendererToRemove != null)
{
- rendererToRemove.ViewGroup.RemoveFromParent();
+ rendererToRemove.View.RemoveFromParent();
rendererToRemove.Dispose();
}
@@ -213,8 +213,8 @@ namespace Xamarin.Forms.Platform.Android
Page pageToRemove = _current;
IVisualElementRenderer rendererToRemove = pageToRemove == null ? null : Platform.GetRenderer(pageToRemove);
- PageContainer containerToRemove = rendererToRemove == null ? null : (PageContainer)rendererToRemove.ViewGroup.Parent;
- PageContainer containerToAdd = (PageContainer)rendererToAdd.ViewGroup.Parent ?? new PageContainer(Context, rendererToAdd);
+ PageContainer containerToRemove = rendererToRemove == null ? null : (PageContainer)rendererToRemove.View.Parent;
+ PageContainer containerToAdd = (PageContainer)rendererToAdd.View.Parent ?? new PageContainer(Context, rendererToAdd);
containerToAdd.SetWindowBackground();
diff --git a/Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs b/Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs
index 06e33e18..a4e77361 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs
@@ -7,7 +7,7 @@ namespace Xamarin.Forms.Platform.Android
{
public PageContainer(Context context, IVisualElementRenderer child, bool inFragment = false) : base(context)
{
- AddView(child.ViewGroup);
+ AddView(child.View);
Child = child;
IsInFragment = inFragment;
}
@@ -23,8 +23,8 @@ namespace Xamarin.Forms.Platform.Android
protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
- Child.ViewGroup.Measure(widthMeasureSpec, heightMeasureSpec);
- SetMeasuredDimension(Child.ViewGroup.MeasuredWidth, Child.ViewGroup.MeasuredHeight);
+ Child.View.Measure(widthMeasureSpec, heightMeasureSpec);
+ SetMeasuredDimension(Child.View.MeasuredWidth, Child.View.MeasuredHeight);
}
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs
index c79e6137..c9354ce2 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs
@@ -32,10 +32,10 @@ namespace Xamarin.Forms.Platform.Android
if ((renderer = Platform.GetRenderer(_childView)) == null)
Platform.SetRenderer(_childView, renderer = Platform.CreateRenderer(_childView));
- if (renderer.ViewGroup.Parent != null)
- renderer.ViewGroup.RemoveFromParent();
+ if (renderer.View.Parent != null)
+ renderer.View.RemoveFromParent();
- AddView(renderer.ViewGroup);
+ AddView(renderer.View);
}
}
diff --git a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
index b7961411..69020de6 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs
@@ -7,6 +7,7 @@ using Android.Views;
using Android.Widget;
using Xamarin.Forms.Internals;
using AScrollView = Android.Widget.ScrollView;
+using AView = Android.Views.View;
namespace Xamarin.Forms.Platform.Android
{
@@ -39,6 +40,13 @@ namespace Xamarin.Forms.Platform.Android
public event EventHandler<VisualElementChangedEventArgs> ElementChanged;
+ event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
+ event EventHandler<PropertyChangedEventArgs> IVisualElementRenderer.ElementPropertyChanged
+ {
+ add { ElementPropertyChanged += value; }
+ remove { ElementPropertyChanged -= value; }
+ }
+
public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint)
{
Measure(widthConstraint, heightConstraint);
@@ -90,10 +98,9 @@ namespace Xamarin.Forms.Platform.Android
Tracker.UpdateLayout();
}
- public ViewGroup ViewGroup
- {
- get { return this; }
- }
+ public ViewGroup ViewGroup => this;
+
+ AView IVisualElementRenderer.View => this;
public override void Draw(Canvas canvas)
{
@@ -239,6 +246,8 @@ namespace Xamarin.Forms.Platform.Android
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
+ ElementPropertyChanged?.Invoke(this, e);
+
if (e.PropertyName == "Content")
LoadContent();
else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName)
diff --git a/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs
index f2878a80..2d5f3b02 100644
--- a/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs
@@ -71,7 +71,7 @@ namespace Xamarin.Forms.Platform.Android
if (Platform.GetRenderer(view) == null)
Platform.SetRenderer(view, Platform.CreateRenderer(view));
- AddView(Platform.GetRenderer(view).ViewGroup);
+ AddView(Platform.GetRenderer(view).View);
}
}
} \ No newline at end of file
diff --git a/Xamarin.Forms.Platform.Android/VisualElementPackager.cs b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs
index 0e08cfed..129ac33d 100644
--- a/Xamarin.Forms.Platform.Android/VisualElementPackager.cs
+++ b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs
@@ -2,6 +2,7 @@ using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using Xamarin.Forms.Internals;
+using Android.Views;
using AView = Android.Views.View;
namespace Xamarin.Forms.Platform.Android
@@ -99,7 +100,7 @@ namespace Xamarin.Forms.Platform.Android
Performance.Start("Add view");
if (!sameChildren)
{
- _renderer.ViewGroup.AddView(renderer.ViewGroup);
+ (_renderer.View as ViewGroup)?.AddView(renderer.View);
_childViews.Add(renderer);
}
Performance.Stop("Add view");
@@ -116,7 +117,7 @@ namespace Xamarin.Forms.Platform.Android
if (element != null)
{
IVisualElementRenderer r = Platform.GetRenderer(element);
- _renderer.ViewGroup.BringChildToFront(r.ViewGroup);
+ (_renderer.View as ViewGroup)?.BringChildToFront(r.View);
}
}
}
@@ -150,7 +151,7 @@ namespace Xamarin.Forms.Platform.Android
{
IVisualElementRenderer renderer = Platform.GetRenderer(view);
_childViews.Remove(renderer);
- renderer.ViewGroup.RemoveFromParent();
+ renderer.View.RemoveFromParent();
renderer.Dispose();
}
diff --git a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
index 8f6722c3..fc0d0436 100644
--- a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs
@@ -161,8 +161,10 @@ namespace Xamarin.Forms.Platform.Android
}
public ViewGroup ViewGroup => this;
+ AView IVisualElementRenderer.View => this;
public event EventHandler<ElementChangedEventArgs<TElement>> ElementChanged;
+ public event EventHandler<PropertyChangedEventArgs> ElementPropertyChanged;
public void SetElement(TElement element)
{
@@ -322,6 +324,8 @@ namespace Xamarin.Forms.Platform.Android
SetFocusable();
else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName)
UpdateInputTransparent();
+
+ ElementPropertyChanged?.Invoke(this, e);
}
protected override void OnLayout(bool changed, int l, int t, int r, int b)
diff --git a/Xamarin.Forms.Platform.Android/VisualElementTracker.cs b/Xamarin.Forms.Platform.Android/VisualElementTracker.cs
index 77404da8..b02fa0c4 100644
--- a/Xamarin.Forms.Platform.Android/VisualElementTracker.cs
+++ b/Xamarin.Forms.Platform.Android/VisualElementTracker.cs
@@ -33,15 +33,15 @@ namespace Xamarin.Forms.Platform.Android
_propertyChangedHandler = HandlePropertyChanged;
_renderer = renderer;
- _context = renderer.ViewGroup.Context;
+ _context = renderer.View.Context;
_renderer.ElementChanged += RendererOnElementChanged;
VisualElement view = renderer.Element;
SetElement(null, view);
- renderer.ViewGroup.SetCameraDistance(3600);
+ renderer.View.SetCameraDistance(3600);
- renderer.ViewGroup.AddOnAttachStateChangeListener(AttachTracker.Instance);
+ renderer.View.AddOnAttachStateChangeListener(AttachTracker.Instance);
}
public void Dispose()
@@ -64,7 +64,7 @@ namespace Xamarin.Forms.Platform.Android
if (_renderer != null)
{
_renderer.ElementChanged -= RendererOnElementChanged;
- _renderer.ViewGroup.RemoveOnAttachStateChangeListener(AttachTracker.Instance);
+ _renderer.View.RemoveOnAttachStateChangeListener(AttachTracker.Instance);
_renderer = null;
_context = null;
}
@@ -76,7 +76,7 @@ namespace Xamarin.Forms.Platform.Android
Performance.Start();
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
var x = (int)_context.ToPixels(view.X);
var y = (int)_context.ToPixels(view.Y);
@@ -110,6 +110,11 @@ namespace Xamarin.Forms.Platform.Android
void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
{
+ if (_renderer == null)
+ {
+ return;
+ }
+
if (e.PropertyName == Layout.IsClippedToBoundsProperty.PropertyName)
{
UpdateClipToBounds();
@@ -183,10 +188,10 @@ namespace Xamarin.Forms.Platform.Android
{
var isInLayout = false;
if ((int)Build.VERSION.SdkInt >= 18)
- isInLayout = _renderer.ViewGroup.IsInLayout;
+ isInLayout = _renderer.View.IsInLayout;
- if (!isInLayout && !_renderer.ViewGroup.IsLayoutRequested)
- _renderer.ViewGroup.RequestLayout();
+ if (!isInLayout && !_renderer.View.IsLayoutRequested)
+ _renderer.View.RequestLayout();
}
void RendererOnElementChanged(object sender, VisualElementChangedEventArgs args)
@@ -208,11 +213,11 @@ namespace Xamarin.Forms.Platform.Android
{
newElement.BatchCommitted += _batchCommittedHandler;
newElement.PropertyChanged += _propertyChangedHandler;
- _context = _renderer.ViewGroup.Context;
+ _context = _renderer.View.Context;
if (oldElement != null)
{
- AView view = _renderer.ViewGroup;
+ AView view = _renderer.View;
// ReSharper disable CompareOfFloatsByEqualityOperator
if (oldElement.AnchorX != newElement.AnchorX)
@@ -243,7 +248,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateAnchorX()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
float currentPivot = aview.PivotX;
var target = (float)(view.AnchorX * _context.ToPixels(view.Width));
@@ -254,7 +259,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateAnchorY()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
float currentPivot = aview.PivotY;
var target = (float)(view.AnchorY * _context.ToPixels(view.Height));
@@ -265,7 +270,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateClipToBounds()
{
var layout = _renderer.Element as Layout;
- var parent = _renderer.ViewGroup.Parent as ViewGroup;
+ var parent = _renderer.View.Parent as ViewGroup;
if (parent == null || layout == null)
return;
@@ -282,7 +287,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateIsVisible()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
if (view.IsVisible && aview.Visibility != ViewStates.Visible)
aview.Visibility = ViewStates.Visible;
@@ -295,7 +300,7 @@ namespace Xamarin.Forms.Platform.Android
Performance.Start();
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
if (aview is FormsViewGroup)
{
@@ -306,20 +311,11 @@ namespace Xamarin.Forms.Platform.Android
}
else
{
- UpdateAnchorX();
- UpdateAnchorY();
- UpdateIsVisible();
-
- if (view.IsEnabled != aview.Enabled)
- aview.Enabled = view.IsEnabled;
-
- UpdateOpacity();
- UpdateRotation();
- UpdateRotationX();
- UpdateRotationY();
- UpdateScale();
- UpdateTranslationX();
- UpdateTranslationY();
+ FormsViewGroup.SendViewBatchUpdate(aview, (float)(view.AnchorX * _context.ToPixels(view.Width)),
+ (float)(view.AnchorY * _context.ToPixels(view.Height)),
+ (int)(view.IsVisible ? ViewStates.Visible : ViewStates.Invisible), view.IsEnabled, (float)view.Opacity,
+ (float)view.Rotation, (float)view.RotationX, (float)view.RotationY, (float)view.Scale,
+ _context.ToPixels(view.TranslationX), _context.ToPixels(view.TranslationY));
}
Performance.Stop();
@@ -330,7 +326,7 @@ namespace Xamarin.Forms.Platform.Android
Performance.Start();
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.Alpha = (float)view.Opacity;
@@ -340,7 +336,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateRotation()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.Rotation = (float)view.Rotation;
}
@@ -348,7 +344,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateRotationX()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.RotationX = (float)view.RotationX;
}
@@ -356,7 +352,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateRotationY()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.RotationY = (float)view.RotationY;
}
@@ -364,7 +360,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateScale()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.ScaleX = (float)view.Scale;
aview.ScaleY = (float)view.Scale;
@@ -373,7 +369,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateTranslationX()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.TranslationX = _context.ToPixels(view.TranslationX);
}
@@ -381,7 +377,7 @@ namespace Xamarin.Forms.Platform.Android
void UpdateTranslationY()
{
VisualElement view = _renderer.Element;
- AView aview = _renderer.ViewGroup;
+ AView aview = _renderer.View;
aview.TranslationY = _context.ToPixels(view.TranslationY);
}
diff --git a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj
index fd894e47..e57a501d 100644
--- a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj
+++ b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj
@@ -20,6 +20,8 @@
<RestorePackages>true</RestorePackages>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
+ <AndroidTlsProvider>
+ </AndroidTlsProvider>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
@@ -100,9 +102,13 @@
</Compile>
<Compile Include="AndroidApplicationLifecycleState.cs" />
<Compile Include="AndroidTitleBarVisibility.cs" />
+ <Compile Include="AppCompat\FrameRenderer.cs" />
+ <Compile Include="FastRenderers\AccessibilityProvider.cs" />
+ <Compile Include="FastRenderers\ButtonRenderer.cs" />
<Compile Include="AppCompat\FormsViewPager.cs" />
<Compile Include="AppCompat\FragmentContainer.cs" />
- <Compile Include="AppCompat\FrameRenderer.cs" />
+ <Compile Include="FastRenderers\EffectControlProvider.cs" />
+ <Compile Include="FastRenderers\FrameRenderer.cs" />
<Compile Include="AppCompat\IManageFragments.cs" />
<Compile Include="AppCompat\MasterDetailContainer.cs" />
<Compile Include="AppCompat\Platform.cs" />
@@ -118,6 +124,9 @@
<Compile Include="ExportCellAttribute.cs" />
<Compile Include="ExportImageSourceHandlerAttribute.cs" />
<Compile Include="ExportRendererAttribute.cs" />
+ <Compile Include="FastRenderers\GestureManager.cs" />
+ <Compile Include="FastRenderers\LabelRenderer.cs" />
+ <Compile Include="FastRenderers\VisualElementRenderer.cs" />
<Compile Include="FormsApplicationActivity.cs" />
<Compile Include="AndroidActivity.cs" />
<Compile Include="AndroidTicker.cs" />
@@ -246,6 +255,8 @@
<Compile Include="Extensions\NativeBindingExtensions.cs" />
<Compile Include="NativeValueConverterService.cs" />
<Compile Include="NativeBindingservice.cs" />
+ <Compile Include="FastRenderers\ImageRenderer.cs" />
+ <Compile Include="Extensions\ImageViewExtensions.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath)\Xamarin\Android\Xamarin.Android.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.