From 41bb8c96490c137b8fcd19de281a0c1e69bc9ade Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20Su=C3=A1rez?= Date: Sat, 26 Mar 2022 02:37:12 +0100 Subject: [PATCH] Ported pending fixes from Xamarin.Forms (#5510) * Ported pending fixes from Xamarin.Forms * Fix build errors * - fix static get of accent color Co-authored-by: Shane Neuville --- .../Android/CollectionView/ItemContentView.cs | 1 + .../src/Android/Renderers/ListViewAdapter.cs | 4 +++ .../Core/src/Android/VisualElementTracker.cs | 9 +++-- .../Core/src/Windows/CellControl.cs | 23 +++---------- .../src/Windows/FontImageSourceHandler.cs | 6 ++-- .../iOS/CollectionView/ItemsViewController.cs | 13 +++++-- .../CollectionView/ObservableItemsSource.cs | 3 +- .../src/iOS/CollectionView/TemplatedCell.cs | 23 ++++++++----- .../src/iOS/Renderers/ImageAnimationHelper.cs | 5 +-- .../src/iOS/Renderers/ListViewRenderer.cs | 3 ++ src/Controls/src/Core/Application.cs | 34 +++++++++++++++++-- .../ListView/Android/ListViewAdapter.cs | 4 +++ .../ListView/Android/ListViewRenderer.cs | 17 ++++++++-- .../Handlers/ListView/Windows/CellControl.cs | 23 +++---------- .../Handlers/ListView/iOS/ListViewRenderer.cs | 3 ++ .../Shell/Android/ShellContentFragment.cs | 3 ++ .../Shell/Android/ShellToolbarTracker.cs | 3 ++ .../Handlers/Items/iOS/ItemsViewController.cs | 12 +++++-- .../Core/Handlers/Items/iOS/TemplatedCell.cs | 21 +++++++----- src/Controls/src/Core/ListView.cs | 2 +- .../src/Platform/Android/ContextExtensions.cs | 19 +++++++++++ .../Android/TransformationExtensions.cs | 14 ++++++-- 22 files changed, 172 insertions(+), 73 deletions(-) diff --git a/src/Compatibility/Core/src/Android/CollectionView/ItemContentView.cs b/src/Compatibility/Core/src/Android/CollectionView/ItemContentView.cs index 36fa4b48752d..8a53c4e06c7f 100644 --- a/src/Compatibility/Core/src/Android/CollectionView/ItemContentView.cs +++ b/src/Compatibility/Core/src/Android/CollectionView/ItemContentView.cs @@ -55,6 +55,7 @@ internal void Recycle() RemoveView(Content.View); } + Content?.Dispose(); Content = null; _size = null; } diff --git a/src/Compatibility/Core/src/Android/Renderers/ListViewAdapter.cs b/src/Compatibility/Core/src/Android/Renderers/ListViewAdapter.cs index 83054db16f4f..3a430d498bec 100644 --- a/src/Compatibility/Core/src/Android/Renderers/ListViewAdapter.cs +++ b/src/Compatibility/Core/src/Android/Renderers/ListViewAdapter.cs @@ -612,6 +612,10 @@ void OnDataChanged() // we need to reset the ListView's adapter to reflect the changes on page B // If there header and footer are present at the reset time of the adapter // they will be DOUBLE added to the ViewGround (the ListView) causing indexes to be off by one. + + if (_realListView.IsDisposed()) + return; + _realListView.RemoveHeaderView(HeaderView); _realListView.RemoveFooterView(FooterView); _realListView.Adapter = _realListView.Adapter; diff --git a/src/Compatibility/Core/src/Android/VisualElementTracker.cs b/src/Compatibility/Core/src/Android/VisualElementTracker.cs index 5962b609f6fd..7667d0f7db62 100644 --- a/src/Compatibility/Core/src/Android/VisualElementTracker.cs +++ b/src/Compatibility/Core/src/Android/VisualElementTracker.cs @@ -412,8 +412,13 @@ void UpdateScale() VisualElement view = _renderer.Element; AView aview = _renderer.View; - aview.ScaleX = (float)view.Scale * (float)view.ScaleX; - aview.ScaleY = (float)view.Scale * (float)view.ScaleY; + var scale = view.Scale; + + if (double.IsNaN(scale)) + return; + + aview.ScaleX = (float)scale * (float)view.ScaleX; + aview.ScaleY = (float)scale * (float)view.ScaleY; } [PortHandler] diff --git a/src/Compatibility/Core/src/Windows/CellControl.cs b/src/Compatibility/Core/src/Windows/CellControl.cs index e9b805ffd0dc..da97001e0b62 100644 --- a/src/Compatibility/Core/src/Windows/CellControl.cs +++ b/src/Compatibility/Core/src/Windows/CellControl.cs @@ -334,17 +334,10 @@ void SetCell(object newContext) // If there is a ListView, load the Cell content from the ItemTemplate. // Otherwise, the given Cell is already a templated Cell from a TableView. ListView lv = _listView.Value; + if (lv != null) { - // 🚀 If there is an old cell, check if it was a group header - // we need this later to know whether we can recycle this cell - bool? wasGroupHeader = null; - var oldCell = Cell; - if (oldCell != null) - { - wasGroupHeader = oldCell.GetIsGroupHeader, Cell>(); - } - + Cell oldCell = Cell; bool isGroupHeader = IsGroupHeader; DataTemplate template = isGroupHeader ? lv.GroupHeaderTemplate : lv.ItemTemplate; object bindingContext = newContext; @@ -362,15 +355,8 @@ void SetCell(object newContext) sameTemplate = oldTemplate == template; } } - // 🚀 if there is no datatemplateselector, we now verify if the old cell - // was a groupheader and whether the new one is as well. - // Again, this is only to verify we can reuse this cell - else if (wasGroupHeader.HasValue) - { - sameTemplate = wasGroupHeader == isGroupHeader; - } - // reuse cell + // Reuse cell var canReuseCell = Cell != null && sameTemplate; // 🚀 If we can reuse the cell, just reuse it... @@ -407,7 +393,8 @@ void SetCell(object newContext) if (Cell != cell) Cell = cell; - // 🚀 even if the cell did not change, we **must** call SendDisappearing() and SendAppearing() + + // 🚀 Even if the cell did not change, we **must** call SendDisappearing() and SendAppearing() // because frameworks such as Reactive UI rely on this! (this.WhenActivated()) else if (Cell != null) { diff --git a/src/Compatibility/Core/src/Windows/FontImageSourceHandler.cs b/src/Compatibility/Core/src/Windows/FontImageSourceHandler.cs index d9aae093bd71..6086478126e7 100644 --- a/src/Compatibility/Core/src/Windows/FontImageSourceHandler.cs +++ b/src/Compatibility/Core/src/Windows/FontImageSourceHandler.cs @@ -35,7 +35,7 @@ public sealed class FontImageSourceHandler : IImageSourceHandler, IIconElementHa { FontFamily = GetFontSource(fontsource), FontSize = (float)fontsource.Size, - HorizontalAlignment = CanvasHorizontalAlignment.Center, + HorizontalAlignment = CanvasHorizontalAlignment.Left, VerticalAlignment = CanvasVerticalAlignment.Center, Options = CanvasDrawTextOptions.Default }; @@ -51,9 +51,7 @@ public sealed class FontImageSourceHandler : IImageSourceHandler, IIconElementHa var iconcolor = (fontsource.Color != null ? fontsource.Color : Colors.White).ToWindowsColor(); // offset by 1 as we added a 1 inset - var x = (float)layout.DrawBounds.X * -1; - - ds.DrawTextLayout(layout, x, 1f, iconcolor); + ds.DrawTextLayout(layout, 1f, 1f, iconcolor); } return Task.FromResult((UI.Xaml.Media.ImageSource)imageSource); diff --git a/src/Compatibility/Core/src/iOS/CollectionView/ItemsViewController.cs b/src/Compatibility/Core/src/iOS/CollectionView/ItemsViewController.cs index 8c4e85981bf5..d32abfafd85b 100644 --- a/src/Compatibility/Core/src/iOS/CollectionView/ItemsViewController.cs +++ b/src/Compatibility/Core/src/iOS/CollectionView/ItemsViewController.cs @@ -19,7 +19,7 @@ public abstract class ItemsViewController : UICollectionViewControll public TItemsView ItemsView { get; } protected ItemsViewLayout ItemsViewLayout { get; set; } bool _initialized; - bool _isEmpty; + bool _isEmpty = true; bool _emptyViewDisplayed; bool _disposed; @@ -212,6 +212,7 @@ public virtual void UpdateItemsSource() { _measurementCells.Clear(); ItemsViewLayout?.ClearCellSizeCache(); + ItemsSource?.Dispose(); ItemsSource = CreateItemsViewSource(); CollectionView.ReloadData(); CollectionView.CollectionViewLayout.InvalidateLayout(); @@ -470,7 +471,14 @@ void AlignEmptyView() return; } - if (CollectionView.EffectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirection.RightToLeft) + bool isRtl; + + if (PlatformVersion.IsAtLeast(10)) + isRtl = CollectionView.EffectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirection.RightToLeft; + else + isRtl = CollectionView.SemanticContentAttribute == UISemanticContentAttribute.ForceRightToLeft; + + if (isRtl) { if (_emptyUIView.Transform.A == -1) { @@ -621,6 +629,7 @@ internal protected virtual void UpdateVisibility() { if (CollectionView.Hidden) { + CollectionView.ReloadData(); CollectionView.Hidden = false; Layout.InvalidateLayout(); CollectionView.LayoutIfNeeded(); diff --git a/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs b/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs index 8891ce0059f0..f67f1d3ca9c1 100644 --- a/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs +++ b/src/Compatibility/Core/src/iOS/CollectionView/ObservableItemsSource.cs @@ -106,7 +106,8 @@ void CollectionChanged(object sender, NotifyCollectionChangedEventArgs args) void CollectionChanged(NotifyCollectionChangedEventArgs args) { // Force UICollectionView to get the internal accounting straight - CollectionView.NumberOfItemsInSection(_section); + if (!CollectionView.Hidden) + CollectionView.NumberOfItemsInSection(_section); switch (args.Action) { diff --git a/src/Compatibility/Core/src/iOS/CollectionView/TemplatedCell.cs b/src/Compatibility/Core/src/iOS/CollectionView/TemplatedCell.cs index 6f41d6a31350..ad1bee71cbe2 100644 --- a/src/Compatibility/Core/src/iOS/CollectionView/TemplatedCell.cs +++ b/src/Compatibility/Core/src/iOS/CollectionView/TemplatedCell.cs @@ -172,6 +172,8 @@ void SetRenderer(IVisualElementRenderer renderer) InitializeContentConstraints(nativeView); + UpdateVisualStates(); + renderer.Element.MeasureInvalidated += MeasureInvalidated; } @@ -236,14 +238,7 @@ public override bool Selected { base.Selected = value; - var element = VisualElementRenderer?.Element; - - if (element != null) - { - VisualStateManager.GoToState(element, value - ? VisualStateManager.CommonStates.Selected - : VisualStateManager.CommonStates.Normal); - } + UpdateVisualStates(); } } @@ -293,5 +288,17 @@ bool SizesAreSame(CGSize preferredSize, Size elementSize) return true; } + + void UpdateVisualStates() + { + var element = VisualElementRenderer?.Element; + + if (element != null) + { + VisualStateManager.GoToState(element, Selected + ? VisualStateManager.CommonStates.Selected + : VisualStateManager.CommonStates.Normal); + } + } } } diff --git a/src/Compatibility/Core/src/iOS/Renderers/ImageAnimationHelper.cs b/src/Compatibility/Core/src/iOS/Renderers/ImageAnimationHelper.cs index 0a3c92b35885..6a1b2207686a 100644 --- a/src/Compatibility/Core/src/iOS/Renderers/ImageAnimationHelper.cs +++ b/src/Compatibility/Core/src/iOS/Renderers/ImageAnimationHelper.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.Linq; using System.Text; using System.Threading; @@ -52,9 +53,9 @@ public void AddFrameData(int index, CGImageSource imageSource) using (var delayTimeValue = gifImageProperties?.ValueForKey(ImageIO.CGImageProperties.GIFDelayTime)) { if (unclampedDelayTimeValue != null) - double.TryParse(unclampedDelayTimeValue.ToString(), out delayTime); + double.TryParse(unclampedDelayTimeValue.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out delayTime); else if (delayTimeValue != null) - double.TryParse(delayTimeValue.ToString(), out delayTime); + double.TryParse(delayTimeValue.ToString(), NumberStyles.Any, CultureInfo.InvariantCulture, out delayTime); // Frame delay compability adjustment. if (delayTime <= 0.02f) diff --git a/src/Compatibility/Core/src/iOS/Renderers/ListViewRenderer.cs b/src/Compatibility/Core/src/iOS/Renderers/ListViewRenderer.cs index 5ce1f6c76835..c68c9020afd0 100644 --- a/src/Compatibility/Core/src/iOS/Renderers/ListViewRenderer.cs +++ b/src/Compatibility/Core/src/iOS/Renderers/ListViewRenderer.cs @@ -274,6 +274,9 @@ protected override void OnElementChanged(ElementChangedEventArgs e) } _tableViewController = new FormsUITableViewController(e.NewElement, _usingLargeTitles); SetNativeControl(_tableViewController.TableView); + + if (Forms.IsiOS15OrNewer) + _tableViewController.TableView.SectionHeaderTopPadding = new nfloat(0); _backgroundUIView = _tableViewController.TableView.BackgroundView; diff --git a/src/Controls/src/Core/Application.cs b/src/Controls/src/Core/Application.cs index a4af84d35939..f207f6b64480 100644 --- a/src/Controls/src/Core/Application.cs +++ b/src/Controls/src/Core/Application.cs @@ -37,7 +37,7 @@ public Application() : this(true) } internal Application(bool setCurrentApplication) - { + { if (setCurrentApplication) SetCurrentApplication(this); @@ -101,7 +101,7 @@ public Page? MainPage OnPropertyChanging(); _singleWindowMainPage = value; - + if (Windows.Count == 1) { Windows[0].Page = value; @@ -179,8 +179,36 @@ public AppTheme UserAppTheme /// public AppTheme RequestedTheme => UserAppTheme != AppTheme.Unspecified ? UserAppTheme : PlatformAppTheme; + static Color? _accentColor; /// - public static Color? AccentColor { get; set; } + public static Color? AccentColor + { + get => _accentColor ??= GetAccentColor(); + set => _accentColor = value; + } + + + static Color? GetAccentColor() + { +#if WINDOWS + if (UI.Xaml.Application.Current.Resources.TryGetValue("SystemColorControlAccentBrush", out object accent) && + accent is UI.Xaml.Media.SolidColorBrush scb) + { + return scb.ToColor(); + } + + return null; +#elif ANDROID + if (Current?.Windows?.Count > 0) + return Current.Windows[0].MauiContext.Context?.GetAccentColor(); + + return null; +#elif IOS + return ColorExtensions.AccentColor.ToColor(); +#else + return Color.FromRgba(50, 79, 133, 255); +#endif + } public event EventHandler RequestedThemeChanged { diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewAdapter.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewAdapter.cs index 59ccc434a9ea..23c338a1ae69 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewAdapter.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewAdapter.cs @@ -617,6 +617,10 @@ void OnDataChanged() // we need to reset the ListView's adapter to reflect the changes on page B // If there header and footer are present at the reset time of the adapter // they will be DOUBLE added to the ViewGround (the ListView) causing indexes to be off by one. + + if (_realListView.IsDisposed()) + return; + _realListView.RemoveHeaderView(HeaderView); _realListView.RemoveFooterView(FooterView); _realListView.Adapter = _realListView.Adapter; diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewRenderer.cs index 2a2a58e1749f..7636a8e0c851 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/Android/ListViewRenderer.cs @@ -440,14 +440,27 @@ void UpdateIsRefreshing(bool isInitialValue = false) }); } else - _refresh.Refreshing = isRefreshing; + _refresh.Refreshing = isRefreshing; + + // Allow to disable SwipeToRefresh layout AFTER refresh is done + UpdateIsSwipeToRefreshEnabled(); } } void UpdateIsSwipeToRefreshEnabled() { if (_refresh != null) - _refresh.Enabled = Element.IsPullToRefreshEnabled && (Element as IListViewController).RefreshAllowed; + { + var isEnabled = Element.IsPullToRefreshEnabled && (Element as IListViewController).RefreshAllowed; + _refresh.Post(() => + { + // NOTE: only disable while NOT refreshing, otherwise Command bindings CanExecute behavior will effectively + // cancel refresh animation. If not possible right now we will be called by UpdateIsRefreshing(). + // For details see https://github.com/xamarin/Xamarin.Forms/issues/8384 + if (isEnabled || !_refresh.Refreshing) + _refresh.Enabled = isEnabled; + }); + } } void UpdateFastScrollEnabled() diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs index 850c155dc967..3c957a3ff91e 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/Windows/CellControl.cs @@ -330,17 +330,10 @@ void SetCell(object newContext) // If there is a ListView, load the Cell content from the ItemTemplate. // Otherwise, the given Cell is already a templated Cell from a TableView. ListView lv = _listView.Value; + if (lv != null) { - // 🚀 If there is an old cell, check if it was a group header - // we need this later to know whether we can recycle this cell - bool? wasGroupHeader = null; - var oldCell = Cell; - if (oldCell != null) - { - wasGroupHeader = oldCell.GetIsGroupHeader, Cell>(); - } - + Cell oldCell = Cell; bool isGroupHeader = IsGroupHeader; DataTemplate template = isGroupHeader ? lv.GroupHeaderTemplate : lv.ItemTemplate; object bindingContext = newContext; @@ -358,15 +351,8 @@ void SetCell(object newContext) sameTemplate = oldTemplate == template; } } - // 🚀 if there is no datatemplateselector, we now verify if the old cell - // was a groupheader and whether the new one is as well. - // Again, this is only to verify we can reuse this cell - else if (wasGroupHeader.HasValue) - { - sameTemplate = wasGroupHeader == isGroupHeader; - } - // reuse cell + // Reuse cell var canReuseCell = Cell != null && sameTemplate; // 🚀 If we can reuse the cell, just reuse it... @@ -403,7 +389,8 @@ void SetCell(object newContext) if (Cell != cell) Cell = cell; - // 🚀 even if the cell did not change, we **must** call SendDisappearing() and SendAppearing() + + // 🚀 Even if the cell did not change, we **must** call SendDisappearing() and SendAppearing() // because frameworks such as Reactive UI rely on this! (this.WhenActivated()) else if (Cell != null) { diff --git a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs index ae6e2f798b81..78a44e32896f 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/ListView/iOS/ListViewRenderer.cs @@ -228,6 +228,9 @@ protected override void OnElementChanged(ElementChangedEventArgs e) } _tableViewController = new FormsUITableViewController(e.NewElement, _usingLargeTitles); SetNativeControl(_tableViewController.TableView); + + if (PlatformVersion.IsAtLeast(15)) + _tableViewController.TableView.SectionHeaderTopPadding = new nfloat(0); _backgroundUIView = _tableViewController.TableView.BackgroundView; diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellContentFragment.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellContentFragment.cs index 0f602d312221..6ba87d552037 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellContentFragment.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellContentFragment.cs @@ -173,6 +173,8 @@ void Destroy() if (_root is ViewGroup vg) vg.RemoveView(_shellPageContainer); + + _shellPageContainer.Dispose(); } _root?.Dispose(); @@ -186,6 +188,7 @@ void Destroy() _root = null; _viewhandler = null; _shellContent = null; + _shellPageContainer = null; } protected override void Dispose(bool disposing) diff --git a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs index 5adfcff818b9..5369cae97059 100644 --- a/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs +++ b/src/Controls/src/Core/Compatibility/Handlers/Shell/Android/ShellToolbarTracker.cs @@ -185,7 +185,10 @@ protected override void Dispose(bool disposing) _currentMenuItems?.Clear(); _currentToolbarItems?.Clear(); + _drawerLayout.RemoveDrawerListener(_drawerToggle); _drawerToggle?.Dispose(); + + _toolbar.RemoveAllViews(); } _currentMenuItems = null; diff --git a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs index 453d6590a122..3b8a97f45d38 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/ItemsViewController.cs @@ -18,7 +18,7 @@ public abstract class ItemsViewController : UICollectionViewControll public TItemsView ItemsView { get; } protected ItemsViewLayout ItemsViewLayout { get; set; } bool _initialized; - bool _isEmpty; + bool _isEmpty = true; bool _emptyViewDisplayed; bool _disposed; @@ -211,6 +211,7 @@ public virtual void UpdateItemsSource() { _measurementCells.Clear(); ItemsViewLayout?.ClearCellSizeCache(); + ItemsSource?.Dispose(); ItemsSource = CreateItemsViewSource(); CollectionView.ReloadData(); CollectionView.CollectionViewLayout.InvalidateLayout(); @@ -472,7 +473,14 @@ void AlignEmptyView() return; } - if (CollectionView.EffectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirection.RightToLeft) + bool isRtl; + + if (PlatformVersion.IsAtLeast(10)) + isRtl = CollectionView.EffectiveUserInterfaceLayoutDirection == UIUserInterfaceLayoutDirection.RightToLeft; + else + isRtl = CollectionView.SemanticContentAttribute == UISemanticContentAttribute.ForceRightToLeft; + + if (isRtl) { if (_emptyUIView.Transform.A == -1) { diff --git a/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs b/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs index 6a02b74d137c..3c08fe600134 100644 --- a/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs +++ b/src/Controls/src/Core/Handlers/Items/iOS/TemplatedCell.cs @@ -172,6 +172,8 @@ void SetRenderer(IPlatformViewHandler renderer) InitializeContentConstraints(platformView); + UpdateVisualStates(); + (renderer.VirtualView as View).MeasureInvalidated += MeasureInvalidated; } @@ -244,14 +246,7 @@ public override bool Selected { base.Selected = value; - var element = PlatformHandler?.VirtualView as VisualElement; - - if (element != null) - { - VisualStateManager.GoToState(element, value - ? VisualStateManager.CommonStates.Selected - : VisualStateManager.CommonStates.Normal); - } + UpdateVisualStates(); } } @@ -301,5 +296,15 @@ bool SizesAreSame(CGSize preferredSize, Size elementSize) return true; } + + void UpdateVisualStates() + { + if (PlatformHandler?.VirtualView is VisualElement element) + { + VisualStateManager.GoToState(element, Selected + ? VisualStateManager.CommonStates.Selected + : VisualStateManager.CommonStates.Normal); + } + } } } diff --git a/src/Controls/src/Core/ListView.cs b/src/Controls/src/Core/ListView.cs index d7f5d80b4109..b8c0b8fe5b7f 100644 --- a/src/Controls/src/Core/ListView.cs +++ b/src/Controls/src/Core/ListView.cs @@ -606,7 +606,7 @@ internal override void OnIsPlatformEnabledChanged() void OnCommandCanExecuteChanged(object sender, EventArgs eventArgs) { - RefreshAllowed = RefreshCommand.CanExecute(null); + RefreshAllowed = RefreshCommand != null && RefreshCommand.CanExecute(null); } static void OnFooterChanged(BindableObject bindable, object oldValue, object newValue) diff --git a/src/Core/src/Platform/Android/ContextExtensions.cs b/src/Core/src/Platform/Android/ContextExtensions.cs index 34ea690fe898..1cf0f7b8ee77 100644 --- a/src/Core/src/Platform/Android/ContextExtensions.cs +++ b/src/Core/src/Platform/Android/ContextExtensions.cs @@ -8,6 +8,7 @@ using Android.Views.InputMethods; using AndroidX.AppCompat.App; using AndroidX.Fragment.App; +using Microsoft.Maui.Graphics; using static Microsoft.Maui.Primitives.Dimension; using AActivity = Android.App.Activity; using AApplicationInfoFlags = Android.Content.PM.ApplicationInfoFlags; @@ -277,6 +278,24 @@ public static int GetDrawableId(this Resources resources, string packageName, st return null; } + internal static Color GetAccentColor(this Context context) + { + Color? rc = null; + using (var value = new TypedValue()) + { + if (context.Theme != null) + { + if (context.Theme.ResolveAttribute(global::Android.Resource.Attribute.ColorAccent, value, true)) // Android 5.0+ + { + rc = Color.FromUint((uint)value.Data); + } + } + } + + return rc ?? Color.FromArgb("#ff33b5e5"); + } + + public static int GetActionBarHeight(this Context context) { _actionBarHeight ??= (int)context.GetThemeAttributePixels(Resource.Attribute.actionBarSize); diff --git a/src/Core/src/Platform/Android/TransformationExtensions.cs b/src/Core/src/Platform/Android/TransformationExtensions.cs index 891fa18ad6c6..b09914aec431 100644 --- a/src/Core/src/Platform/Android/TransformationExtensions.cs +++ b/src/Core/src/Platform/Android/TransformationExtensions.cs @@ -28,12 +28,22 @@ public static void UpdateScale(this AView platformView, IView view) public static void UpdateScaleX(this AView platformView, IView view) { - platformView.ScaleX = (float)(view.Scale * view.ScaleX); + var scale = view.Scale; + + if (double.IsNaN(scale)) + return; + + platformView.ScaleX = (float)(scale * view.ScaleX); } public static void UpdateScaleY(this AView platformView, IView view) { - platformView.ScaleY = (float)(view.Scale * view.ScaleY); + var scale = view.Scale; + + if (double.IsNaN(scale)) + return; + + platformView.ScaleY = (float)(scale * view.ScaleY); } public static void UpdateRotation(this AView platformView, IView view)