From 1a6bb390f5861be71d860a9200b51f6d1e6aa5c6 Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Mon, 27 Feb 2017 15:29:17 -0700 Subject: [PATCH 01/34] Obsolete IVisualElementRenderer.ViewGroup in favor of .View --- .../Xamarin.Forms.ControlGallery.iOS.csproj | 24 +++++----- .../AppCompat/CarouselPageRenderer.cs | 2 +- .../AppCompat/FragmentContainer.cs | 4 +- .../AppCompat/FrameRenderer.cs | 2 + .../AppCompat/MasterDetailPageRenderer.cs | 3 ++ .../AppCompat/NavigationPageRenderer.cs | 4 +- .../AppCompat/Platform.cs | 6 +-- .../AppCompat/TabbedPageRenderer.cs | 2 +- .../Cells/ViewCellRenderer.cs | 8 ++-- .../IVisualElementRenderer.cs | 3 ++ Xamarin.Forms.Platform.Android/Platform.cs | 20 ++++----- .../RendererPool.cs | 11 +++-- .../Renderers/CarouselPageAdapter.cs | 6 +-- .../Renderers/ConditionalFocusLayout.cs | 10 ++++- .../Renderers/ListViewRenderer.cs | 10 ++--- .../Renderers/MasterDetailContainer.cs | 10 ++--- .../Renderers/MasterDetailRenderer.cs | 6 +-- .../Renderers/NavigationRenderer.cs | 8 ++-- .../Renderers/PageContainer.cs | 6 +-- .../Renderers/ScrollViewContainer.cs | 6 +-- .../Renderers/ScrollViewRenderer.cs | 8 ++-- .../Renderers/TabbedRenderer.cs | 2 +- .../VisualElementPackager.cs | 7 +-- .../VisualElementRenderer.cs | 1 + .../VisualElementTracker.cs | 44 +++++++++---------- 25 files changed, 117 insertions(+), 96 deletions(-) diff --git a/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj b/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj index 3b8b47e30e6..5924a6d5bac 100644 --- a/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj +++ b/Xamarin.Forms.ControlGallery.iOS/Xamarin.Forms.ControlGallery.iOS.csproj @@ -2,7 +2,7 @@ Debug - iPhoneSimulator + AnyCPU {C7131F14-274F-4B55-ACA9-E81731AD012F} {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} Exe @@ -160,7 +160,6 @@ - @@ -170,6 +169,10 @@ + + {39b3457f-01d8-43d0-8e84-d8c4f73cf48d} + Xamarin.Forms.Platform.iOS %28Forwarders%29 + {cb9c96ce-125c-4a68-b6a1-c3ff1fbf93e1} Xamarin.Forms.Controls @@ -192,10 +195,6 @@ Xamarin.Forms.Platform.iOS false - - {39B3457F-01D8-43D0-8E84-D8C4F73CF48D} - Xamarin.Forms.Platform.iOS (Forwarders) - @@ -295,6 +294,9 @@ + + ..\Components\advancedcolorpicker-2.0\lib\ios-unified\AdvancedColorPicker.dll + @@ -308,9 +310,6 @@ ..\packages\Xamarin.TestCloud.Agent.0.20.3\lib\Xamarin.iOS10\Calabash.dll - - ..\packages\AdvancedColorPicker.2.0.1\lib\Xamarin.iOS\AdvancedColorPicker.dll - @@ -320,8 +319,13 @@ + - + + 2.0 + False + + \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs index f7a48d9b43a..766ee225680 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/CarouselPageRenderer.cs @@ -42,7 +42,7 @@ protected override void Dispose(bool disposing) 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/FragmentContainer.cs b/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs index 6cc493a18b4..e6c1b0cebc3 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/FragmentContainer.cs @@ -83,9 +83,9 @@ public override void OnDestroyView() { 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 16ee0473030..f77e1dd2711 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs @@ -159,6 +159,8 @@ void IVisualElementRenderer.UpdateLayout() ViewGroup IVisualElementRenderer.ViewGroup => this; + AView IVisualElementRenderer.View => this; + protected override void Dispose(bool disposing) { if (disposing && !_disposed) diff --git a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs index 85ab6b73820..8651750c1d5 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs @@ -4,6 +4,7 @@ using Android.Support.V4.Widget; using Android.Views; using Android.Support.V4.App; +using AView = Android.Views.View; namespace Xamarin.Forms.Platform.Android.AppCompat { @@ -178,6 +179,8 @@ void IVisualElementRenderer.UpdateLayout() ViewGroup IVisualElementRenderer.ViewGroup => this; + AView IVisualElementRenderer.View => this; + protected override void Dispose(bool disposing) { if (disposing && !_disposed) diff --git a/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs index 7fe1f1e865c..d405b42bc11 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/NavigationPageRenderer.cs @@ -534,7 +534,7 @@ void RegisterToolbar() 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 @@ void RemovePage(Page page) 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 69365c63300..0416ae3a8ec 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/Platform.cs @@ -88,7 +88,7 @@ Task INavigation.PopModalAsync(bool animated) 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 @@ void AddChild(Page page, bool layout = false) 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 @@ public ModalContainer(Context context, Page modal) : base(context) _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 b1aed05dd3d..bb14100df42 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/TabbedPageRenderer.cs @@ -97,7 +97,7 @@ protected override void Dispose(bool disposing) 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 8134a9c1e45..48abb49b222 100644 --- a/Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Cells/ViewCellRenderer.cs @@ -61,7 +61,7 @@ public ViewCellContainer(Context context, IVisualElementRenderer view, ViewCell _unevenRows = unevenRows; _rowHeight = rowHeight; _viewCell = viewCell; - AddView(view.ViewGroup); + AddView(view.View); UpdateIsEnabled(); } @@ -123,16 +123,16 @@ public void Update(ViewCell cell) 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/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs index da565ce262b..861d78adf61 100644 --- a/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs @@ -10,8 +10,11 @@ public interface IVisualElementRenderer : IRegisterable, IDisposable VisualElementTracker Tracker { get; } + [Obsolete("Use View instead")] ViewGroup ViewGroup { get; } + AView View { get; } + event EventHandler ElementChanged; SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint); diff --git a/Xamarin.Forms.Platform.Android/Platform.cs b/Xamarin.Forms.Platform.Android/Platform.cs index 004531a152d..3f96909195e 100644 --- a/Xamarin.Forms.Platform.Android/Platform.cs +++ b/Xamarin.Forms.Platform.Android/Platform.cs @@ -206,11 +206,11 @@ Task INavigation.PopModalAsync(bool animated) { 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 @@ Task INavigation.PopModalAsync(bool animated) } else { - modalRenderer.ViewGroup.RemoveFromParent(); + modalRenderer.View.RemoveFromParent(); modalRenderer.Dispose(); source.TrySetResult(modal); CurrentPageController?.SendAppearing(); @@ -534,7 +534,7 @@ void AddChild(VisualElement view, bool layout = false) 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 @@ Task PresentModal(Page modal, bool animated) 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(); 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/RendererPool.cs b/Xamarin.Forms.Platform.Android/RendererPool.cs index 48665c81e07..51913f6147d 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 @@ void ClearChildrenRenderers(VisualElement view) 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/CarouselPageAdapter.cs b/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs index efee571ddfd..c31e8e698e1 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/CarouselPageAdapter.cs @@ -55,7 +55,7 @@ public override void DestroyItem(ViewGroup p0, int p1, Object p2) Page destroyedPage = holder.Instance.Item2; IVisualElementRenderer renderer = Platform.GetRenderer(destroyedPage); - renderer.ViewGroup.RemoveFromParent(); + renderer.View.RemoveFromParent(); holder.Instance.Item1.RemoveFromParent(); } @@ -90,7 +90,7 @@ public override Object InstantiateItem(ViewGroup container, int position) 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 @@ protected override void Dispose(bool disposing) 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 311db6b85d0..cc8037fec57 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs @@ -30,7 +30,7 @@ internal void ApplyTouchListenersToSpecialCells(Cell item) 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 @@ internal void ApplyTouchListenersToSpecialCells(Cell item) 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/ListViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs index a09069156c6..bd241c1a29f 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ListViewRenderer.cs @@ -45,14 +45,14 @@ protected override void Dispose(bool disposing) 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 @@ public IVisualElementRenderer Child 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 @@ protected override void OnMeasure(int widthMeasureSpec, int heightMeasureSpec) 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 a7bebf1e12c..fd028df180d 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailContainer.cs @@ -54,12 +54,12 @@ protected virtual void AddChildView(VisualElement childView) 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 @@ protected void SetDefaultBackgroundColor(IVisualElementRenderer renderer) 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 d18781a7111..88cecb96ed6 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs @@ -142,10 +142,8 @@ public void UpdateLayout() Tracker.UpdateLayout(); } - public ViewGroup ViewGroup - { - get { return this; } - } + public ViewGroup ViewGroup => this; + AView IVisualElementRenderer.View => this; protected override void Dispose(bool disposing) { diff --git a/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs index bf6540b93f1..5d67828783b 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/NavigationRenderer.cs @@ -183,13 +183,13 @@ void OnRemovePageRequested(object sender, NavigationRequestedEventArgs e) 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 @@ Task SwitchContentAsync(Page view, bool animated, bool removed = false) 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 06e33e18674..a4e773615a1 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/PageContainer.cs @@ -7,7 +7,7 @@ internal class PageContainer : ViewGroup { 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 @@ protected override void OnLayout(bool changed, int l, int t, int r, int b) 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 c79e6137bc9..c9354ce2d90 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewContainer.cs @@ -32,10 +32,10 @@ public View ChildView 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 b796141195f..bb53d10b819 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs @@ -7,6 +7,7 @@ using Android.Widget; using Xamarin.Forms.Internals; using AScrollView = Android.Widget.ScrollView; +using AView = Android.Views.View; namespace Xamarin.Forms.Platform.Android { @@ -90,10 +91,9 @@ public void UpdateLayout() Tracker.UpdateLayout(); } - public ViewGroup ViewGroup - { - get { return this; } - } + public ViewGroup ViewGroup => this; + + AView IVisualElementRenderer.View => this; public override void Draw(Canvas canvas) { diff --git a/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs index f2878a80753..2d5f3b02e64 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/TabbedRenderer.cs @@ -71,7 +71,7 @@ protected virtual void SwitchContent(Page view) 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 0e08cfedbf7..129ac33d53f 100644 --- a/Xamarin.Forms.Platform.Android/VisualElementPackager.cs +++ b/Xamarin.Forms.Platform.Android/VisualElementPackager.cs @@ -2,6 +2,7 @@ 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 @@ void AddChild(VisualElement view, IVisualElementRenderer oldRenderer = null, Ren 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 @@ void EnsureChildOrder() if (element != null) { IVisualElementRenderer r = Platform.GetRenderer(element); - _renderer.ViewGroup.BringChildToFront(r.ViewGroup); + (_renderer.View as ViewGroup)?.BringChildToFront(r.View); } } } @@ -150,7 +151,7 @@ void RemoveChild(VisualElement view) { 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 8f6722c3de4..adf6235db4d 100644 --- a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs @@ -161,6 +161,7 @@ public void UpdateLayout() } public ViewGroup ViewGroup => this; + AView IVisualElementRenderer.View => this; public event EventHandler> ElementChanged; diff --git a/Xamarin.Forms.Platform.Android/VisualElementTracker.cs b/Xamarin.Forms.Platform.Android/VisualElementTracker.cs index 77404da88d5..fbf67d3f5ff 100644 --- a/Xamarin.Forms.Platform.Android/VisualElementTracker.cs +++ b/Xamarin.Forms.Platform.Android/VisualElementTracker.cs @@ -33,15 +33,15 @@ public VisualElementTracker(IVisualElementRenderer renderer) _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 @@ protected virtual void Dispose(bool disposing) if (_renderer != null) { _renderer.ElementChanged -= RendererOnElementChanged; - _renderer.ViewGroup.RemoveOnAttachStateChangeListener(AttachTracker.Instance); + _renderer.View.RemoveOnAttachStateChangeListener(AttachTracker.Instance); _renderer = null; _context = null; } @@ -76,7 +76,7 @@ public void UpdateLayout() 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); @@ -183,10 +183,10 @@ void MaybeRequestLayout() { 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 +208,11 @@ void SetElement(VisualElement oldElement, VisualElement newElement) { 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 +243,7 @@ void SetElement(VisualElement oldElement, VisualElement newElement) 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 +254,7 @@ void UpdateAnchorX() 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 +265,7 @@ void UpdateAnchorY() 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 +282,7 @@ void UpdateClipToBounds() 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 +295,7 @@ void UpdateNativeView(object sender, EventArgs e) Performance.Start(); VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; if (aview is FormsViewGroup) { @@ -330,7 +330,7 @@ void UpdateOpacity() Performance.Start(); VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; aview.Alpha = (float)view.Opacity; @@ -340,7 +340,7 @@ void UpdateOpacity() void UpdateRotation() { VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; aview.Rotation = (float)view.Rotation; } @@ -348,7 +348,7 @@ void UpdateRotation() void UpdateRotationX() { VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; aview.RotationX = (float)view.RotationX; } @@ -356,7 +356,7 @@ void UpdateRotationX() void UpdateRotationY() { VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; aview.RotationY = (float)view.RotationY; } @@ -364,7 +364,7 @@ void UpdateRotationY() 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 +373,7 @@ void UpdateScale() void UpdateTranslationX() { VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; aview.TranslationX = _context.ToPixels(view.TranslationX); } @@ -381,7 +381,7 @@ void UpdateTranslationX() void UpdateTranslationY() { VisualElement view = _renderer.Element; - AView aview = _renderer.ViewGroup; + AView aview = _renderer.View; aview.TranslationY = _context.ToPixels(view.TranslationY); } From 9a1279f6481cba511e33251ebe0f66d4475ca934 Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Mon, 27 Feb 2017 15:45:27 -0700 Subject: [PATCH 02/34] Fix NRE --- .../Renderers/ConditionalFocusLayout.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs b/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs index cc8037fec57..5b3002ced8d 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ConditionalFocusLayout.cs @@ -44,7 +44,7 @@ internal void ApplyTouchListenersToSpecialCells(Cell item) internal EditText GetEditText(IVisualElementRenderer renderer) { - var viewGroup = renderer.View as ViewGroup; + var viewGroup = renderer?.View as ViewGroup; return viewGroup?.GetChildAt(0) as EditText; } } From f2f8f1b906b877f1de9d68bd5a729a12782f0bde Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Mon, 27 Feb 2017 17:36:37 -0700 Subject: [PATCH 03/34] Changing TContainer in PlatformEffect to View --- Xamarin.Forms.Platform.Android/PlatformEffect.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Xamarin.Forms.Platform.Android/PlatformEffect.cs b/Xamarin.Forms.Platform.Android/PlatformEffect.cs index 6830b722663..5ba08c5bad1 100644 --- a/Xamarin.Forms.Platform.Android/PlatformEffect.cs +++ b/Xamarin.Forms.Platform.Android/PlatformEffect.cs @@ -1,9 +1,10 @@ +using System; using Android.Views; using AView = Android.Views.View; namespace Xamarin.Forms.Platform.Android { - public abstract class PlatformEffect : PlatformEffect + public abstract class PlatformEffect : PlatformEffect { } } \ No newline at end of file From 685e5f2b4bb6831ed67ff767b664fbc9b2d6b006 Mon Sep 17 00:00:00 2001 From: "E.Z. Hart" Date: Mon, 27 Feb 2017 17:38:40 -0700 Subject: [PATCH 04/34] Fix "View" type --- Xamarin.Forms.Platform.Android/PlatformEffect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Xamarin.Forms.Platform.Android/PlatformEffect.cs b/Xamarin.Forms.Platform.Android/PlatformEffect.cs index 5ba08c5bad1..040bf24703b 100644 --- a/Xamarin.Forms.Platform.Android/PlatformEffect.cs +++ b/Xamarin.Forms.Platform.Android/PlatformEffect.cs @@ -4,7 +4,7 @@ namespace Xamarin.Forms.Platform.Android { - public abstract class PlatformEffect : PlatformEffect + public abstract class PlatformEffect : PlatformEffect { } } \ No newline at end of file From 99fbac149522894617655cb838668be72b5493b0 Mon Sep 17 00:00:00 2001 From: Samantha Houts Date: Wed, 1 Mar 2017 11:06:38 -0800 Subject: [PATCH 05/34] new VisualElementRenderer --- .../AppCompat/FrameRenderer.cs | 3 + .../AppCompat/MasterDetailPageRenderer.cs | 8 + .../FastRenderers/VisualElementRenderer.cs | 308 ++++++++++++++++++ .../IVisualElementRenderer.cs | 3 + .../Renderers/MasterDetailRenderer.cs | 8 + .../Renderers/ScrollViewRenderer.cs | 9 + .../VisualElementRenderer.cs | 3 + .../Xamarin.Forms.Platform.Android.csproj | 1 + 8 files changed, 343 insertions(+) create mode 100644 Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs diff --git a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs index f77e1dd2711..a6a271b1d8f 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/FrameRenderer.cs @@ -123,6 +123,7 @@ bool IOnTouchListener.OnTouch(AView v, MotionEvent e) VisualElement IVisualElementRenderer.Element => Element; public event EventHandler ElementChanged; + public event EventHandler ElementPropertyChanged; SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint) { @@ -262,6 +263,8 @@ void HandleGestureRecognizerCollectionChanged(object sender, NotifyCollectionCha void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) { + ElementPropertyChanged?.Invoke(this, e); + if (e.PropertyName == Frame.HasShadowProperty.PropertyName) UpdateShadow(); else if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) diff --git a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs index 8651750c1d5..a1c4092e258 100644 --- a/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs +++ b/Xamarin.Forms.Platform.Android/AppCompat/MasterDetailPageRenderer.cs @@ -88,6 +88,12 @@ void IManageFragments.SetFragmentManager(FragmentManager fragmentManager) remove { ElementChanged -= value; } } + event EventHandler IVisualElementRenderer.ElementPropertyChanged + { + add { ElementPropertyChanged += value; } + remove { ElementPropertyChanged -= value; } + } + SizeRequest IVisualElementRenderer.GetDesiredSize(int widthConstraint, int heightConstraint) { Measure(widthConstraint, heightConstraint); @@ -269,6 +275,7 @@ async void DeviceInfoPropertyChanged(object sender, PropertyChangedEventArgs e) } event EventHandler ElementChanged; + event EventHandler ElementPropertyChanged; bool HasAncestorNavigationPage(Element element) { @@ -286,6 +293,7 @@ void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e) 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/FastRenderers/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs new file mode 100644 index 00000000000..0ca6118e0be --- /dev/null +++ b/Xamarin.Forms.Platform.Android/FastRenderers/VisualElementRenderer.cs @@ -0,0 +1,308 @@ +using System; +using System.Collections.ObjectModel; +using System.Collections.Specialized; +using System.ComponentModel; +using Android.Runtime; +using Android.Support.V4.View; +using Android.Views; +using AView = Android.Views.View; + +namespace Xamarin.Forms.Platform.Android.FastRenderers +{ + public class VisualElementRenderer : IDisposable, AView.IOnClickListener, AView.IOnTouchListener, IEffectControlProvider + { + const string GetFromElement = "GetValueFromElement"; + + readonly Lazy _gestureDetector; + readonly PanGestureHandler _panGestureHandler; + readonly PinchGestureHandler _pinchGestureHandler; + readonly Lazy _scaleDetector; + readonly TapGestureHandler _tapGestureHandler; + + bool _clickable; + NotifyCollectionChangedEventHandler _collectionChangeHandler; + string _defaultContentDescription; + bool? _defaultFocusable; + string _defaultHint; + bool _disposed; + InnerGestureListener _gestureListener; + IVisualElementRenderer _renderer; + + public VisualElementRenderer(IVisualElementRenderer renderer) + { + _renderer = renderer; + _renderer.ElementPropertyChanged += OnElementPropertyChanged; + _renderer.ElementChanged += OnElementChanged; + + _tapGestureHandler = new TapGestureHandler(() => View); + _panGestureHandler = new PanGestureHandler(() => View, Control.Context.FromPixels); + _pinchGestureHandler = new PinchGestureHandler(() => View); + + _gestureDetector = + new Lazy( + () => + new GestureDetector( + _gestureListener = + new InnerGestureListener(_tapGestureHandler.OnTap, _tapGestureHandler.TapGestureRecognizers, _panGestureHandler.OnPan, _panGestureHandler.OnPanStarted, _panGestureHandler.OnPanComplete))); + + _scaleDetector = + new Lazy( + () => new ScaleGestureDetector(Control.Context, new InnerScaleListener(_pinchGestureHandler.OnPinch, _pinchGestureHandler.OnPinchStarted, _pinchGestureHandler.OnPinchEnded), Control.Handler)); + } + + VisualElement Element => _renderer?.Element; + + IntPtr IJavaObject.Handle => Control.Handle; + + View View => _renderer?.Element as View; + + AView Control => _renderer?.View; + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + void IDisposable.Dispose() + { + throw new NotImplementedException(); + } + + void AView.IOnClickListener.OnClick(AView v) + { + _tapGestureHandler.OnSingleClick(); + } + + public void OnRegisterEffect(PlatformEffect effect) + { + effect.Control = Control; + //TODO: is this crazy? + effect.Container = Control; + } + + bool AView.IOnTouchListener.OnTouch(AView v, MotionEvent e) + { + var handled = false; + if (_pinchGestureHandler.IsPinchSupported) + { + if (!_scaleDetector.IsValueCreated) + ScaleGestureDetectorCompat.SetQuickScaleEnabled(_scaleDetector.Value, true); + handled = _scaleDetector.Value.OnTouchEvent(e); + } + return _gestureDetector.Value.OnTouchEvent(e) || handled; + } + + void IEffectControlProvider.RegisterEffect(Effect effect) + { + var platformEffect = effect as PlatformEffect; + if (platformEffect != null) + OnRegisterEffect(platformEffect); + } + + public void SetAutomationId(string id = GetFromElement) + { + if (Element == null || Control == null) + return; + + var value = id; + if (value == GetFromElement) + value = Element.AutomationId; + + if (!string.IsNullOrEmpty(value)) + Control.ContentDescription = value; + } + + public void SetContentDescription(string contentDescription = GetFromElement) + { + if (Element == null || Control == null) + return; + + if (SetHint()) + return; + + if (_defaultContentDescription == null) + _defaultContentDescription = Control.ContentDescription; + + var 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; + } + + public 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); + } + + public bool SetHint(string hint = GetFromElement) + { + if (Element == null || Control == null) + return false; + + var textView = Control as global::Android.Widget.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; + + var value = hint; + if (value == GetFromElement) + value = string.Join(". ", (string)Element.GetValue(Accessibility.NameProperty), (string)Element.GetValue(Accessibility.HintProperty)); + + if (!string.IsNullOrWhiteSpace(value)) + textView.Hint = value; + else + textView.Hint = _defaultHint; + + return true; + } + + public void UpdateBackgroundColor(Color? color = null) + { + if (Element == null || Control == null) + return; + + Control.SetBackgroundColor((color ?? Element.BackgroundColor).ToAndroid()); + } + + public void UpdateInputTransparent(bool? inputTransparent = null) + { + if (Element == null || Control == null) + return; + + //TODO: InputTransparent is on FormsViewGroup + //InputTransparent = Element.InputTransparent; + } + + protected virtual void Dispose(bool disposing) + { + if (_disposed) + return; + + _disposed = true; + + if (_gestureListener != null) + { + _gestureListener.Dispose(); + _gestureListener = null; + } + + if (_renderer != null) + { + if (_renderer.Element != null) + { + UnsubscribeGestureRecognizers(Element); + + } + _renderer = null; + } + } + + void HandleGestureRecognizerCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs) + { + UpdateGestureRecognizers(); + } + + void OnElementChanged(object sender, VisualElementChangedEventArgs e) + { + if (e.OldElement != null) + { + e.OldElement.PropertyChanged -= OnElementPropertyChanged; + UnsubscribeGestureRecognizers(e.OldElement); + } + + if (e.NewElement != null) + { + Control.SetOnClickListener(this); + Control.SetOnTouchListener(this); + + UpdateGestureRecognizers(true); + + e.NewElement.PropertyChanged += OnElementPropertyChanged; + UpdateBackgroundColor(); + SubscribeGestureRecognizers(e.NewElement); + } + } + + void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == VisualElement.BackgroundColorProperty.PropertyName) + UpdateBackgroundColor(); + else if (e.PropertyName == VisualElement.InputTransparentProperty.PropertyName) + UpdateInputTransparent(); + else if (e.PropertyName == Accessibility.HintProperty.PropertyName) + SetContentDescription(); + else if (e.PropertyName == Accessibility.NameProperty.PropertyName) + SetContentDescription(); + else if (e.PropertyName == Accessibility.IsInAccessibleTreeProperty.PropertyName) + SetFocusable(); + } + + void SubscribeGestureRecognizers(VisualElement element) + { + var view = element as View; + if (view == null) + return; + + if (_collectionChangeHandler == null) + _collectionChangeHandler = HandleGestureRecognizerCollectionChanged; + + var observableCollection = (ObservableCollection)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)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); + } + } +} \ No newline at end of file diff --git a/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/IVisualElementRenderer.cs index 861d78adf61..71817db264d 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; @@ -17,6 +18,8 @@ public interface IVisualElementRenderer : IRegisterable, IDisposable event EventHandler ElementChanged; + event EventHandler ElementPropertyChanged; + SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint); void SetElement(VisualElement element); diff --git a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs index 88cecb96ed6..7e744bc76dd 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/MasterDetailRenderer.cs @@ -73,6 +73,13 @@ public VisualElement Element public event EventHandler ElementChanged; + event EventHandler ElementPropertyChanged; + event EventHandler IVisualElementRenderer.ElementPropertyChanged + { + add { ElementPropertyChanged += value; } + remove { ElementPropertyChanged -= value; } + } + public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint) { Measure(widthConstraint, heightConstraint); @@ -235,6 +242,7 @@ void HandleMasterPropertyChanged(object sender, PropertyChangedEventArgs e) 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/ScrollViewRenderer.cs b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs index bb53d10b819..69020de65b1 100644 --- a/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs +++ b/Xamarin.Forms.Platform.Android/Renderers/ScrollViewRenderer.cs @@ -40,6 +40,13 @@ public VisualElement Element public event EventHandler ElementChanged; + event EventHandler ElementPropertyChanged; + event EventHandler IVisualElementRenderer.ElementPropertyChanged + { + add { ElementPropertyChanged += value; } + remove { ElementPropertyChanged -= value; } + } + public SizeRequest GetDesiredSize(int widthConstraint, int heightConstraint) { Measure(widthConstraint, heightConstraint); @@ -239,6 +246,8 @@ static int GetDistance(double start, double position, double v) 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/VisualElementRenderer.cs b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs index adf6235db4d..fc0d043612c 100644 --- a/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs +++ b/Xamarin.Forms.Platform.Android/VisualElementRenderer.cs @@ -164,6 +164,7 @@ public void UpdateLayout() AView IVisualElementRenderer.View => this; public event EventHandler> ElementChanged; + public event EventHandler ElementPropertyChanged; public void SetElement(TElement element) { @@ -323,6 +324,8 @@ protected virtual void OnElementPropertyChanged(object sender, PropertyChangedEv 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/Xamarin.Forms.Platform.Android.csproj b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj index fd894e47070..ae926fe8616 100644 --- a/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj +++ b/Xamarin.Forms.Platform.Android/Xamarin.Forms.Platform.Android.csproj @@ -118,6 +118,7 @@ + From d8aa8d7c5f52646bd39b20702ec38400bab99715 Mon Sep 17 00:00:00 2001 From: Samantha Houts Date: Wed, 1 Mar 2017 11:11:13 -0800 Subject: [PATCH 06/34] Fast Label Renderer --- Stubs/Xamarin.Forms.Platform.cs | 2 +- .../FastRenderers/LabelRenderer.cs | 314 ++++++++++++++++++ .../Xamarin.Forms.Platform.Android.csproj | 1 + 3 files changed, 316 insertions(+), 1 deletion(-) create mode 100644 Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs diff --git a/Stubs/Xamarin.Forms.Platform.cs b/Stubs/Xamarin.Forms.Platform.cs index 70e8084f89a..3b856bdc84d 100644 --- a/Stubs/Xamarin.Forms.Platform.cs +++ b/Stubs/Xamarin.Forms.Platform.cs @@ -35,7 +35,7 @@ internal class _EntryRenderer { } [RenderWith (typeof (EditorRenderer))] internal class _EditorRenderer { } - [RenderWith (typeof (LabelRenderer))] + [RenderWith (typeof (FastLabelRenderer))] internal class _LabelRenderer { } [RenderWith (typeof (ImageRenderer))] diff --git a/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs b/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs new file mode 100644 index 00000000000..2ff41acd479 --- /dev/null +++ b/Xamarin.Forms.Platform.Android/FastRenderers/LabelRenderer.cs @@ -0,0 +1,314 @@ +using System; +using System.ComponentModel; +using Android.Content.Res; +using Android.Graphics; +using Android.Text; +using Android.Util; +using Android.Views; +using Android.Widget; +using Xamarin.Forms.Platform.Android.FastRenderers; +using AView = Android.Views.View; + +namespace Xamarin.Forms.Platform.Android +{ + public class FastLabelRenderer : TextView, IVisualElementRenderer + { + int? _defaultLabelFor; + bool _disposed; + Label _element; + ColorStateList _labelTextColorDefault; + int _lastConstraintHeight; + int _lastConstraintWidth; + SizeRequest? _lastSizeRequest; + float _lastTextSize = -1f; + Typeface _lastTypeface; + Color _lastUpdateColor = Color.Default; + VisualElementPackager _visualElementPackager; + VisualElementTracker _visualElementTracker; + VisualElementRenderer _visualElementRenderer; + bool _wasFormatted; + + public FastLabelRenderer() : base(Forms.Context) + { + _labelTextColorDefault = TextColors; + } + + public event EventHandler ElementChanged; + public event EventHandler ElementPropertyChanged; + + VisualElement IVisualElementRenderer.Element => Element; + + VisualElementTracker IVisualElementRenderer.Tracker => _visualElementTracker; + + AView IVisualElementRenderer.View => this; + + ViewGroup IVisualElementRenderer.ViewGroup => null; + + protected TextView Control => this; + + protected Label Element + { + get { return _element; } + set + { + if (_element == value) + return; + + Label oldElement = _element; + _element = value; + + OnElementChanged(new ElementChangedEventArgs