14
votes

Is there a way to specify a "system" icon to be displayed on a tab when using Xamarin Forms? I would like to use icons such as Favourites, Bookmark, History etc but I do not want to supply all my own images for the various platforms.

Using Xamarin.iOS one can use this syntax:

tab1.TabBarItem = new UITabBarItem (UITabBarSystemItem.Favorites, 0);

I can however not find how to do this in the cross-platform Xamarin.Forms project.

This is my current code:

var profilePage = new ContentPage {
    Title = "Profile",
    //This requires my own images to be added to the project whereas
    //I wish to use built-in images which are platform specific for
    //Favourites, Bookmark, More, etc...
    //Icon = "Profile.png",
    Content = new StackLayout {
        Spacing = 20, Padding = 50,
        VerticalOptions = LayoutOptions.Center,
        Children = {
        new Entry { Placeholder = "Username" },
        new Entry { Placeholder = "Password", IsPassword = true },
        new Button {
            Text = "Login",
            TextColor = Color.White,
            BackgroundColor = Color.FromHex("77D065") }}}};

var settingsPage = new ContentPage {
    Title = "Settings",
    Content = new StackLayout {
        Spacing = 20, Padding = 50,
        VerticalOptions = LayoutOptions.Center,
        Children = {
            new Entry { Placeholder = "Username" },
            new Entry { Placeholder = "Password", IsPassword = true }}}
        };


MainPage = new TabbedPage { Children = {profilePage, settingsPage} };
3
do you need iOS only or Android too? - Yuri S
If you use system icons you cannot change title under it. If that is a problem and you want to use your own title with system icons you will have to get a copy of the image. If you are ok to use system titles let us know and I will provide an answer. Also you are mixing 2 problems in one. Do you want to use cross-platform icons stored in PCL or system icons. If you are talking about system items you cannot specify that in the place of code you show because they have different names for each platform.If you want to just keep them in one place - this is different question. Please clarify - Yuri S
So with the system icons are you saying Apple supplies the titles and I cannot change them? If it's not possible then do you think the only way to do this will be with png icons or are there other types of icons that give very good quality images and resize easily? If so perhaps you could suggest in an answer some sources of icons that could be used and how these could be resized. - Alan2
Correct, you cannot change title if you use Apple's SYSTEM icon. You can use SVG images. I have not tried that but it should be possible. Because icons are usually small you probably can use PNG and you can keep them in PCL (again, I have tried that for regular images but not for tabbars). Let me know if you need more help with that. Please add @YuriS to your comments so I get update - Yuri S
@Alan If you keep them in PCL you just need to create links in platform specific folders pointing to those files in PCL - Yuri S

3 Answers

6
votes

For iOS

you need a custom renderer for your page. In my example, it is CustomTabsPage class. You cannot just use system icons to create a UIImage. We need to use UITabBarItem. The problem is that UITabBarItem doesn't allow changes to either title or image/icon. But, we can copy an image from it.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using UIKit;
using ButtonRendererDemo;
using ButtonRendererDemo.iOS;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ExportRenderer(typeof(CustomTabsPage), typeof(CustomTabsPageRenderer))]
namespace ButtonRendererDemo.iOS
{
    public class CustomTabsPageRenderer : TabbedRenderer
    {

         #region Sytem Image with custom title

        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);

            foreach (var item in TabBar.Items)
            {
                item.Image = GetTabIcon(item.Title);
            }
        }

        private UIImage GetTabIcon(string title)
        {
            UITabBarItem item = null;

            switch (title)
            {
                case "Profile":
                    item = new UITabBarItem(UITabBarSystemItem.Search, 0);
                    break;
                case "Settings":
                    item = new UITabBarItem(UITabBarSystemItem.Bookmarks, 0);
                    break;
            }

            var img = (item != null) ? UIImage.FromImage(item.SelectedImage.CGImage, item.SelectedImage.CurrentScale, item.SelectedImage.Orientation) : new UIImage();
            return img;
        }

        #endregion
    }
}

enter image description here

For Android

things are easier

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using ButtonRendererDemo;
using ButtonRendererDemo.Droid;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using Xamarin.Forms.Platform.Android.AppCompat;
using Android.Support.Design.Widget;

[assembly: ExportRenderer(typeof(CustomTabsPage), typeof(CustomTabsPageRenderer))]
namespace ButtonRendererDemo.Droid
{
    public class CustomTabsPageRenderer : TabbedPageRenderer
    {
        protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
        {
            base.OnElementChanged(e);

            //var layout = (TabLayout)ViewGroup.GetChildAt(1); //should be enough but just for robustness we use loop below

            TabLayout layout = null;
            for (int i = 0; i < ChildCount; i++)
            {
                layout = GetChildAt(i) as TabLayout;
                if (layout != null)
                    break;
            }
            if (layout != null)
            {
                for (int tabIndex = 0; tabIndex < layout.TabCount; tabIndex++)
                    SetTabIcon(layout, tabIndex);
            }
        }

        private void SetTabIcon(TabLayout layout, int tabIndex)
        {
            var tab = layout.GetTabAt(tabIndex);

            switch (tabIndex)
            {
                case 0:
                    tab.SetIcon(Resource.Drawable.icon2);//from local resource
                    break;
                case 1:
                    tab.SetIcon(Resource.Drawable.ic_media_play_dark);//from Android system, depends on version !
                    break;
            }
        }
    }

}

enter image description here

0
votes

In order to use icons, you need a platform-specific structure. In Xamarin.Forms, for this to work:

Icon = "youricon.png";

You need:

  • iOS: put the image in /Resources/youricon.png
  • Android: put the image in /Resources/drawable/youricon.png
  • Win Phone: put the image in the Windows Phone application project root.
-2
votes

You should write custom TabbedPage renderer for iOS project:

public class YourTabbedRenderer : TabbedRenderer {
        public override void ViewWillAppear(bool animated)
        {
            base.ViewWillAppear(animated);
            var items = TabBar.Items;

            for (var i = 0; i < items.Length; i++) {
                // set your icons here, you could do some string comparison (check tab title or tab icon resource name)
                // items[i].Image = 
                // items[i].SelectedImage = 
            }
        }
    }

http://developer.xamarin.com/guides/cross-platform/xamarin-forms/custom-renderer/