using Android.Content.Res; using Android.Graphics.Drawables; #if __ANDROID_29__ using AndroidX.Core.Widget; using Google.Android.Material.BottomNavigation; #else using Android.Support.Design.Internal; using Android.Support.Design.Widget; #endif using System; using Xamarin.Forms; using Xamarin.Forms.Platform.Android; using AColor = Android.Graphics.Color; using R = Android.Resource; namespace Gallery.Droid.Renderers.AppShellSection { public class AppShellBottomNavViewAppearanceTracker : IShellBottomNavViewAppearanceTracker { [System.Diagnostics.CodeAnalysis.SuppressMessage("CodeQuality", "IDE0052:Remove unread private members", Justification = "")] IShellContext _shellContext; ShellItem _shellItem; ColorStateList _defaultList; bool _disposed; ColorStateList _colorStateList; public AppShellBottomNavViewAppearanceTracker(IShellContext shellContext, ShellItem shellItem) { _shellItem = shellItem; _shellContext = shellContext; } public virtual void ResetAppearance(BottomNavigationView bottomView) { if (_defaultList != null) { bottomView.ItemTextColor = _defaultList; bottomView.ItemIconTintList = _defaultList; } SetBackgroundColor(bottomView, Color.White); } public virtual void SetAppearance(BottomNavigationView bottomView, IShellAppearanceElement appearance) { IShellAppearanceElement controller = appearance; var backgroundColor = controller.EffectiveTabBarBackgroundColor; var foregroundColor = controller.EffectiveTabBarForegroundColor; var disabledColor = controller.EffectiveTabBarDisabledColor; var unselectedColor = controller.EffectiveTabBarUnselectedColor; // currently unused var titleColor = controller.EffectiveTabBarTitleColor; if (_defaultList == null) { #if __ANDROID_28__ _defaultList = bottomView.ItemTextColor ?? bottomView.ItemIconTintList ?? MakeColorStateList(titleColor.ToAndroid().ToArgb(), disabledColor.ToAndroid().ToArgb(), foregroundColor.ToAndroid().ToArgb()); #else _defaultList = bottomView.ItemTextColor ?? bottomView.ItemIconTintList; #endif } _colorStateList = MakeColorStateList(titleColor, disabledColor, foregroundColor); bottomView.ItemTextColor = _colorStateList; bottomView.ItemIconTintList = _colorStateList; var menu = bottomView.Menu; if (menu != null && menu.HasVisibleItems && menu.Size() == 4) { var itemUser = menu.GetItem(0); itemUser.SetIcon(itemUser.IsChecked ? Resource.Drawable.ic_user : Resource.Drawable.ic_user_regular); var itemRecommend = menu.GetItem(1); itemRecommend.SetIcon(itemRecommend.IsChecked ? Resource.Drawable.ic_sparkles : Resource.Drawable.ic_sparkles_regular); var itemRank = menu.GetItem(2); itemRank.SetIcon(itemRank.IsChecked ? Resource.Drawable.ic_rank : Resource.Drawable.ic_rank_regular); var itemFavorite = menu.GetItem(3); itemFavorite.SetIcon(itemFavorite.IsChecked ? Resource.Drawable.ic_bookmark : Resource.Drawable.ic_bookmark_regular); } SetBackgroundColor(bottomView, backgroundColor); } protected virtual void SetBackgroundColor(BottomNavigationView bottomView, Color color) { var oldBackground = bottomView.Background; var colorDrawable = oldBackground as ColorDrawable; var colorChangeRevealDrawable = oldBackground as AppColorChangeRevealDrawable; AColor lastColor = colorChangeRevealDrawable?.EndColor ?? colorDrawable?.Color ?? Color.Default.ToAndroid(); AColor newColor; if (color == Color.Default) newColor = Color.White.ToAndroid(); else newColor = color.ToAndroid(); if (!(bottomView.GetChildAt(0) is BottomNavigationMenuView menuView)) { if (colorDrawable != null && lastColor == newColor) return; if (lastColor != newColor || colorDrawable == null) { bottomView.SetBackground(new ColorDrawable(newColor)); } } else { if (colorChangeRevealDrawable != null && lastColor == newColor) return; var index = ((IShellItemController)_shellItem).GetItems().IndexOf(_shellItem.CurrentItem); var menu = bottomView.Menu; index = Math.Min(index, menu.Size() - 1); var child = menuView.GetChildAt(index); if (child == null) return; var touchPoint = new Android.Graphics.Point(child.Left + (child.Right - child.Left) / 2, child.Top + (child.Bottom - child.Top) / 2); bottomView.SetBackground(new AppColorChangeRevealDrawable(lastColor, newColor, touchPoint)); } } ColorStateList MakeColorStateList(Color titleColor, Color disabledColor, Color unselectedColor) { var disabledInt = disabledColor.IsDefault ? _defaultList.GetColorForState(new[] { -R.Attribute.StateEnabled }, AColor.Gray) : disabledColor.ToAndroid().ToArgb(); var checkedInt = titleColor.IsDefault ? _defaultList.GetColorForState(new[] { R.Attribute.StateChecked }, AColor.Black) : titleColor.ToAndroid().ToArgb(); var defaultColor = unselectedColor.IsDefault ? _defaultList.DefaultColor : unselectedColor.ToAndroid().ToArgb(); return MakeColorStateList(checkedInt, disabledInt, defaultColor); } ColorStateList MakeColorStateList(int titleColorInt, int disabledColorInt, int defaultColor) { var states = new int[][] { new int[] { -R.Attribute.StateEnabled }, new int[] {R.Attribute.StateChecked }, new int[] { } }; var colors = new[] { disabledColorInt, titleColorInt, defaultColor }; return new ColorStateList(states, colors); } #region IDisposable public void Dispose() { Dispose(true); } protected virtual void Dispose(bool disposing) { if (_disposed) return; _disposed = true; if (disposing) { _defaultList?.Dispose(); _colorStateList?.Dispose(); _shellItem = null; _shellContext = null; _defaultList = null; _colorStateList = null; } } #endregion IDisposable } }