【问题标题】:How to change TabbedPage partial icon color in Xamarin如何在 Xamarin 中更改 TabbedPage 部分图标颜色
【发布时间】:2021-12-30 14:18:53
【问题描述】:

我正在处理 Xamarin 中的 TabbedPage。但是有一个问题是:如何在选择 Tab 时仅部分更改图标颜色。这是我想要的例子:

在 Xamarin 中,它具有更改部分图像颜色的解决方案。还是在选择选项卡时更改图标。这是我处理的代码

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
            xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
            BackgroundColor="#fff"
            ....>    
    <views:Page1 Title="Page 1" IconImageSource="homeicon" BackgroundColor="#fff"/>
    <views:Page2 Title="Page 2" IconImageSource="feeds" BackgroundColor="#fff"/>    
    <views:Page3 Title="Page 3" IconImageSource="chats" BackgroundColor="#fff" />
    <views:Page4 Title="Page 4" IconImageSource="usericon" BackgroundColor="#fff"/>
</TabbedPage>

MyTabbedPageRenderer iOS

public class MyTabbedPageRenderer : TabbedRenderer
{

    protected override void OnElementChanged(VisualElementChangedEventArgs e)
    {
        base.OnElementChanged(e);
        
    }
    public override void ViewWillAppear(bool animated)
    {
        base.ViewWillAppear(animated);

        if (TabBar?.Items == null)
            return;

        foreach (var item in TabBar.Items)
        {
            item.Image = ScalingImageToSize(item.Image, new CGSize(20, 20)); // set the size here as you want 
        }

        var tabs = Element as TabbedPage;
        if (tabs != null)
        {
            for (int i = 0; i < TabBar.Items.Length; i++)
            {
                UpdateTabBarItem(TabBar.Items[i]);
            }
        }
    }
    private void UpdateTabBarItem(UITabBarItem item)
    {
        if (item == null) return;

        if (UIDevice.CurrentDevice.CheckSystemVersion(13, 0))
        {
            UITabBarAppearance app = new UITabBarAppearance();
            app.ConfigureWithOpaqueBackground();
            app.BackgroundColor = UIColor.Clear;

            app.StackedLayoutAppearance.Normal.TitleTextAttributes = new UIStringAttributes() { Font = UIFont.FromName("Roboto Medium", 12), ForegroundColor = Color.FromHex("#808080").ToUIColor() };
            app.StackedLayoutAppearance.Selected.TitleTextAttributes = new UIStringAttributes() { Font = UIFont.FromName("Roboto Medium", 13), ForegroundColor = Color.FromHex("#00AA13").ToUIColor() };
            item.StandardAppearance = app;

            if (UIDevice.CurrentDevice.CheckSystemVersion(15, 0))
            {
                item.ScrollEdgeAppearance = item.StandardAppearance;
            }
        }

    }
    public UIImage ScalingImageToSize(UIImage sourceImage, CGSize newSize)
    {

        if (UIScreen.MainScreen.Scale == 2.0) //@2x iPhone 6 7 8 
        {
            UIGraphics.BeginImageContextWithOptions(newSize, false, 2.0f);
        }


        else if (UIScreen.MainScreen.Scale == 3.0) //@3x iPhone 6p 7p 8p...
        {
            UIGraphics.BeginImageContextWithOptions(newSize, false, 3.0f);
        }

        else
        {
            UIGraphics.BeginImageContext(newSize);
        }

        sourceImage.Draw(new CGRect(0, 0, newSize.Width, newSize.Height));

        UIImage newImage = UIGraphics.GetImageFromCurrentImageContext();

        UIGraphics.EndImageContext();

        return newImage;

    }

}

AppDelegate.cs

UITabBar.Appearance.BackgroundImage = new UIImage();
UITabBar.Appearance.ShadowImage = new UIImage();
UITabBar.Appearance.SelectedImageTintColor = UIColor.FromRGB(0, 170, 19);

它显示的结果:

如何在 android 和 iOS 中选择 Tab 时仅部分更改图标颜色。请求帮忙。谢谢

更新

我根据您的示例进行了更新,但它似乎仍然不起作用。我创建了一个新项目

MainView.xaml

<?xml version="1.0" encoding="utf-8" ?>
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:views="clr-namespace:Appssss.Views"
            x:Class="Appssss.Views.Mainview">
  <!--Pages can be added as references or inline-->
    <views:Page1 Title="Page 1" IconImageSource="homeicon" BackgroundColor="#fff"/>
    <views:Page2 Title="Page 2" IconImageSource="feeds" BackgroundColor="#fff"/>
    <views:Page3 Title="Page 3" IconImageSource="moneys" BackgroundColor="#fbfbfb" />
    <views:Page4 Title="Page 4" IconImageSource="chats" BackgroundColor="#fff" />
    <views:Page5 Title="Page 5" IconImageSource="usericon" BackgroundColor="#fff"/>
</TabbedPage>

MainView.xaml.cs

namespace Appssss.Views
{
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class Mainview : Xamarin.Forms.TabbedPage
    {
        public Mainview(int index)
        {
            InitializeComponent();
            On<Xamarin.Forms.PlatformConfiguration.Android>().SetToolbarPlacement(ToolbarPlacement.Bottom);
            SetPage(index);
        }
        void SetPage(int index)
        {
            CurrentPage = Children[index];
        }
    }
}

CustomTabbedPageRenderer.cs

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Appssss.Droid.Renderers;
using Google.Android.Material.Tabs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android.AppCompat;
using static Google.Android.Material.Tabs.TabLayout;

[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
namespace Appssss.Droid.Renderers
{
    public class CustomTabbedPageRenderer : TabbedPageRenderer, IOnTabSelectedListener
    {
        public CustomTabbedPageRenderer(Context context) : base(context)
        {

        }
        void IOnTabSelectedListener.OnTabSelected(TabLayout.Tab tab)
        {
            if (tab == null)
            {
                return;
            }

            switch (tab.Text)
            {
                case "Page 1":
                    tab.SetIcon(Resource.Drawable.homeiconselect);
                    break;
                case "Page 2":
                    tab.SetIcon(Resource.Drawable.feedsselect);
                    break;
                case "Page 3":
                    tab.SetIcon(Resource.Drawable.moneysselect);
                    break;
                case "Page 4":
                    tab.SetIcon(Resource.Drawable.chatsselect);
                    break;
                case "Page 5":
                    tab.SetIcon(Resource.Drawable.usericonselect);
                    break;
                default:
                    break;

            }
        }
        void IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
        {
            if (tab == null)
            {
                return;
            }

            switch (tab.Text)
            {
                case "Page 1":
                    tab.SetIcon(Resource.Drawable.homeicon);
                    break;
                case "Page 2":
                    tab.SetIcon(Resource.Drawable.feeds);
                    break;
                case "Page 3":
                    tab.SetIcon(Resource.Drawable.moneys);
                    break;
                case "Page 4":
                    tab.SetIcon(Resource.Drawable.chats);
                    break;
                case "Page 5":
                    tab.SetIcon(Resource.Drawable.usericon);
                    break;
                default:
                    break;
            }
        }

    }
}

这是结果,我注意到它仍然没有按预期改变:

我创建了不同的图标,但注意到它仍然无法正常工作。我还没有在 iOS 上尝试过。

更新 2

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using Appssss.Droid.Renderers;
using Google.Android.Material.BottomNavigation;
using Google.Android.Material.Tabs;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using static Google.Android.Material.BottomNavigation.BottomNavigationView;
using static Google.Android.Material.Tabs.TabLayout;

[assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
namespace Appssss.Droid.Renderers
{
    public class CustomTabbedPageRenderer : TabbedPageRenderer, IOnTabSelectedListener
    {
        public CustomTabbedPageRenderer(Context context) : base(context)
        {

        }
        protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
        {
            base.OnElementChanged(e);

            if (e.NewElement != null)
            {
                IEnumerable<View> children = GetAllChildViews(ViewGroup);
                BottomNavigationView bottomNavBar = (BottomNavigationView)children.SingleOrDefault(view => view is BottomNavigationView);

                if (bottomNavBar != null)
                {
                    bottomNavBar.NavigationItemSelected += BottomNavBar_NavigationItemSelected;
                    bottomNavBar.Menu.GetItem(0).SetIcon(Resource.Drawable.diamond);
                }

            }
        }
        int previous;
        private void BottomNavBar_NavigationItemSelected(object sender, NavigationItemSelectedEventArgs e)
        {
            var current = e.Item.ItemId;

            switch (e.Item.ToString())
            {
                case "Page 1":
                    e.Item.SetIcon(Resource.Drawable.diamond);
                    break;
                case "Page 2":
                    e.Item.SetIcon(Resource.Drawable.diamond);
                    break;
                default:
                    break;
            }


            var previousView = sender as BottomNavigationView;
            IMenu menu = previousView.Menu;
            var previousItem = menu.GetItem(previous);


            if (previousItem.IsChecked)
            {
                switch (previousItem.ToString())
                {
                    case "Page 1":
                        previousItem.SetIcon(Resource.Drawable.cactus_24px);
                        break;
                    case "Page 2":
                        previousItem.SetIcon(Resource.Drawable.cactus_24px);
                        break;
                    default:
                        break;
                }


            }

            previous = current;
        }

        private IEnumerable<View> GetAllChildViews(View view)
        {
            if (!(view is ViewGroup group))
                return new List<View> { view };

            List<View> result = new List<View>();
            int childCount = group.ChildCount;

            for (int i = 0; i < childCount; i++)
            {
                View child = group.GetChildAt(i);
                List<View> childList = new List<View> { child };
                childList.AddRange(GetAllChildViews(child));
                result.AddRange(childList);
            }

            return result.Distinct();
        }
    }
}

得到错误:

我试过了

更新3

好像没有使用库:using static Google.Android.Material.BottomNavigation.BottomNavigationView;

【问题讨论】:

    标签: xamarin


    【解决方案1】:

    一种简单的方法是在您选择选项卡时更改图标。使用两个图标,一个黑色的,一个红色的。

    通常,如果我们想更改图标颜色,一种方法是将背景设置为您发布的结果(第二张截图)。第二种方法是使用 Material Icons 代替图片源。

    但所有方法都不会将颜色更改为红色并留下两条黑线作为您想要的示例。

    Complex 方法是在选择 Tab 时绘制新图像。 Xamarin.Forms 提供了几种方法来做到这一点:

    更新:

    您可以在自定义渲染器中执行此操作。

    Android: Android 提供了一个类IOnTabSelectedListener 来监听选项卡的选中和未选中状态。下面是一个简单的代码供您参考。

    [assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
    namespace App18.Droid
    {
    public class CustomTabbedPageRenderer: TabbedPageRenderer, IOnTabSelectedListener
    {
        public CustomTabbedPageRenderer(Context context) : base(context)
        {
    
        }
        void IOnTabSelectedListener.OnTabSelected(TabLayout.Tab tab)
        {
            if (tab == null)
            {
                return;
            }
    
            switch (tab.Text)
            {
                case "Page 1":
                    tab.SetIcon(Resource.Drawable.icon);
                    break;
                case "Page 2":
                    tab.SetIcon(Resource.Drawable.icon);
                    break;
                default:
                    break;
            }
        }
        void IOnTabSelectedListener.OnTabUnselected(TabLayout.Tab tab)
        {
            if (tab == null)
            {
                return;
            }
    
            switch (tab.Text)
            {
                case "Page 1":
                    tab.SetIcon(Resource.Drawable.cactus_24px);
                    break;
                case "Page 2":
                    tab.SetIcon(Resource.Drawable.cactus_24px);
                    break;
                default:
                    break;
            }
        }
      
    }
    }
    

    iOS: 对于 ios,您可以使用 ViewControllerSelected 注册方法 ViewControllerSelected。 有关更多详细信息,请查看以下链接。 how to make the tabbed page navigate when clicked on the same tab text/icon twice?

    更新2:

    Android:对于底部的标签,你需要访问原生的BottomNavigationView

    [assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
    namespace App18.Droid
    {
    public class CustomTabbedPageRenderer : TabbedPageRenderer, IOnTabSelectedListener
    {
        public CustomTabbedPageRenderer(Context context) : base(context)
        {
    
        }
        protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
        {
            base.OnElementChanged(e);
    
            if (e.NewElement != null)
            {
                IEnumerable<View> children = GetAllChildViews(ViewGroup);
                BottomNavigationView bottomNavBar = (BottomNavigationView)children.SingleOrDefault(view => view is BottomNavigationView);
    
                if (bottomNavBar != null)
                {               
                    bottomNavBar.NavigationItemSelected += BottomNavBar_NavigationItemSelected;
                    bottomNavBar.Menu.GetItem(0).SetIcon(Resource.Drawable.diamond);
                }
    
            }
        }
        int previous; 
        private void BottomNavBar_NavigationItemSelected(object sender, NavigationItemSelectedEventArgs e)
        {
             var current = e.Item.ItemId;
    
            switch (e.Item.ToString())
            {
                case "Page 1":
                    e.Item.SetIcon(Resource.Drawable.diamond);
                    break;
                case "Page 2":
                    e.Item.SetIcon(Resource.Drawable.diamond);
                    break;
                default:
                    break;
            }       
            
    
            var previousView = sender as BottomNavigationView;
            IMenu menu = previousView.Menu;
            var previousItem = menu.GetItem(previous);
           
    
            if (previousItem.IsChecked)
            {
                switch (previousItem.ToString())
                {
                    case "Page 1":
                        previousItem.SetIcon(Resource.Drawable.cactus_24px);
                        break;
                    case "Page 2":
                        previousItem.SetIcon(Resource.Drawable.cactus_24px);
                        break;
                    default:
                        break;
                }
               
                
            }
    
            previous = current;
        }
    
        private IEnumerable<View> GetAllChildViews(View view)
        {
            if (!(view is ViewGroup group))
                return new List<View> { view };
    
            List<View> result = new List<View>();
            int childCount = group.ChildCount;
    
            for (int i = 0; i < childCount; i++)
            {
                View child = group.GetChildAt(i);
                List<View> childList = new List<View> { child };
                childList.AddRange(GetAllChildViews(child));
                result.AddRange(childList);
            }
    
            return result.Distinct();
        }
    }
    }
    

    更新3:

    对于View的错误,使用Android.Views.View而不是Xamarin.Forms.View

    using View = Android.Views.View;
    

    对于项目的错误,我添加了所有代码以及您使用的引用,项目没有错误。清理 bin 和 obj 文件夹以重新构建项目。

    更新4

    在任何函数之外声明一个TabbedPage 实例变量。并设置bottomNavBar不为null时的值。

     TabbedPage tabbedPage;
        protected override void OnElementChanged(Xamarin.Forms.Platform.Android.ElementChangedEventArgs<Xamarin.Forms.TabbedPage> e)
        {
            base.OnElementChanged(e);
            if (e.NewElement != null)
            {
                IEnumerable<View> children = GetAllChildViews(ViewGroup);
                BottomNavigationView bottomNavBar = (BottomNavigationView)children.SingleOrDefault(view => view is BottomNavigationView);
                if (bottomNavBar != null)
                {
                    tabbedPage = e.NewElement;
                    bottomNavBar.NavigationItemSelected += BottomNavBar_NavigationItemSelected;
                    bottomNavBar.Menu.GetItem(0).SetIcon(Resource.Drawable.diamond_24);
                }
            }
        }
    

    BottomNavBar_NavigationItemSelected 中设置tabbedPageCurrentPage

       private void BottomNavBar_NavigationItemSelected(object sender, BottomNavigationView.NavigationItemSelectedEventArgs e)
        {
            var current = e.Item.ItemId;
            switch (e.Item.ToString())
            {
                case "Page 1":
                    e.Item.SetIcon(Resource.Drawable.diamond_24);
                    break;
                case "Page 2":
                    e.Item.SetIcon(Resource.Drawable.diamond_24);
                    break;
                case "Page 3":
                    e.Item.SetIcon(Resource.Drawable.diamond_24);
                    break;
                default:
                    break;
            }
            var previousView = sender as BottomNavigationView;
            IMenu menu = previousView.Menu;
            var previousItem = menu.GetItem(previous);
             if (previous != current)
            {
                if (previousItem.IsChecked)
                {
                    switch (previousItem.ToString())
                    {
                        case "Page 1":
                            previousItem.SetIcon(Resource.Drawable.cactus_24);
                            break;
                        case "Page 2":
                            previousItem.SetIcon(Resource.Drawable.cactus_24);
                            break;
                        case "Page 3":
                            previousItem.SetIcon(Resource.Drawable.cactus_24);
                            break;
                        default:
                            break;
                    }
    
                }
    
            }
            tabbedPage.CurrentPage = tabbedPage.Children[current];
            previous = current;
        }
    

    【讨论】:

    • 所以在您看来,最简单的方法是在前后创建 2 张图像。我也觉得挺好的。你在 Xamarin 的 ios 和 android 上对此有具体说明吗?
    • 我会尽快更新代码。
    • 请检查亩更新。
    • 我按照你的指示做了,但是还是不行。您可以查看上面的更新部分。谢谢
    • @ChimDiTru 该代码适用于 Android 上的普通选项卡,该选项卡显示在顶部。对于底部标签,我会尽快反馈。
    猜你喜欢
    • 2017-07-28
    • 2016-09-27
    • 1970-01-01
    • 1970-01-01
    • 2022-08-17
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 2010-10-23
    相关资源
    最近更新 更多