Forum Xamarin.Forms

Tabbed Page Action Bar Rendering

JohnnyJaxsJohnnyJaxs USMember ✭✭
edited October 2014 in Xamarin.Forms

The follow is a way to overwhelm the issues when setup the action bar of a tabbed page project.

But before showing the rendered let make a short intro for the guys who is using this for first time.

PART 1 - XAML

The XAML code of a tabbed page is the follow:

`<?xml version="1.0" encoding="utf-8" ?>

<TabbedPage.Children>

    <ContentPage x:Name="tabKeypad">
        <StackLayout 
           ......Some Code
        </StackLayout>

    </ContentPage>

    <ContentPage  x:Name="tabContacts">
        <Grid>
          ......Some Code
        </Grid>
    </ContentPage>

    <ContentPage x:Name="tabFavourites">
        <Grid>
          ......Some Code
        </Grid>
    </ContentPage>

    <ContentPage x:Name="tabCallHistory">
        <Label Text="Coming Soon" />
    </ContentPage>

</TabbedPage.Children>

`

A short description of the XAML tabbed page is the follow:
<TabbedPage> <TabbedPage.Children> <ContentPage x:Name="Tab1"/> <!-- Remmber always to use x:Name and not Name (As may use it in a WPF app) --> <ContentPage x:Name="Tab2"/> <ContentPage x:Name="Tab3"/> </TabbedPage.Children> </TabbedPage>

«1

Posts

  • JohnnyJaxsJohnnyJaxs USMember ✭✭
    edited October 2014

    Now lets go to see how i develop my renderer.
    My App Scenario:
    My app is a phone app.... You know, a keypad, a contacts tab etc.
    Also as you can imagine the need of a process a to call the native dialer is obvious.
    At the beginning this was looked easy, but i have face several problems with the events.
    All started when i was sent a number to the native dialer and after the call was terminated the action bar 'OnWindowVisibilityChanged' event was called. Also when i exit and enter again the app without delete from memory.
    Anyway the follow solution, and after some tests,i believe is enough stable.

    NOTE: BUT when i use the tabbed page as the detail page of a Master Detail Page(MDP), then....a mess!
    As long as a tab was selected, then the on draw event was called( This event was called twice, by its nature - In the second call the Master Detail Page Action Bar was re-initialized to the default settings). I fix that but when the selection in the MDP master page was change, tabs color was reset to default(black). Solve it but then.....
    I can continue for a long time. I have solve most of the events issues(Basically you must play and clarify/understand the differences; and when to use:
    1. actionBar.SetBackgroundDrawable(colorDrawable);
    2. actionBar.SetStackedBackgroundDrawable(colorDrawable);

    ...Anyway at the moment i will give the solution about the Tabbed Page renderer. If somebody need help by using MDP and a Tabbed Page i will be glad to help.
    Something last. Finally i decide to create my MDP and Tabbed Page interface by just using a Content page, grid,stack layout, listviews etc...

    PART 2 - Tabbed Page Action Bar Renderer {Android}

    What u can do:
    1. Add you icons to the tab.
    2. Set the tab background color.
    3. Set the tab padding.

    namespace TestingViews.Droid { public class CustomTabRenderer : TabbedRenderer { private Activity activity; private const string COLOR = "#f7f8f8";

           //This flag is used in the case when the app is not completely closed, and the user return back.
            private bool isFirstDesign = true;
    
            protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
                activity = this.Context as Activity;
            }
    
            protected override void OnWindowVisibilityChanged(ViewStates visibility)
            {
                base.OnWindowVisibilityChanged(visibility);
                if (isFirstDesign)
                {
                    ActionBar actionBar = activity.ActionBar;
    
                    ColorDrawable colorDrawable = new ColorDrawable(Android.Graphics.Color.ParseColor(COLOR));
                    actionBar.SetStackedBackgroundDrawable(colorDrawable);
                    ActionBarTabsSetup(actionBar);
    
                    isFirstDesign = false; 
                }
            }
    
            private void ActionBarTabsSetup(ActionBar actionBar)
            {
                Android.App.ActionBar.Tab keypad = actionBar.GetTabAt(0);
                if (TabIsEmpty(keypad))
                    TabSetup(keypad, Resource.Drawable.keypad);
    
                Android.App.ActionBar.Tab contacts = actionBar.GetTabAt(1);
                if (TabIsEmpty(contacts))
                    TabSetup(contacts, Resource.Drawable.contacts);
    
                Android.App.ActionBar.Tab favorites = actionBar.GetTabAt(2);
                if (TabIsEmpty(favorites))
                    TabSetup(favorites, Resource.Drawable.favorites);
    
                Android.App.ActionBar.Tab callsLog = actionBar.GetTabAt(3);
                if (TabIsEmpty(callsLog))
                    TabSetup(callsLog, Resource.Drawable.calls_log);
    
                Android.App.ActionBar.Tab chat = actionBar.GetTabAt(4);
                if (TabIsEmpty(chat))
                    TabSetup(chat, Resource.Drawable.messages);
            }
    
            private bool TabIsEmpty(ActionBar.Tab tab)
            {
                if (tab != null)
                    if (tab.CustomView == null)
                        return true;
                return false;
            }
    
            private void TabSetup(ActionBar.Tab tab, int resourceID)
            {
                ImageView iv = new ImageView(activity);
                iv.SetImageResource(resourceID);
                iv.SetPadding(-35, 8, -35, 16);
    
                tab.SetCustomView(iv);
            }
        }
    }`
    
  • David.6954David.6954 USUniversity ✭✭

    Thanks for posting your solution! I learned a lot of useful information from it.

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    Something to mention.
    The reason that i use TabIsEmpty(ActionBar.Tab tab) is for preventing of re-drawing each tab view when exit-and-come-back (Basically when the OnWindowVisibilityChanged is called).

    Have a nice day

  • TeoTeo DKMember ✭✭
    edited October 2014

    @JohnnyJaxs‌ My TabbedRenderer class doesnt have a method named void OnElementPropertyChanged . Which means that base.OnElementPropertyChanged(sender, e); returns an error. Am I doing something wrong?

    I am trying to set some badges, which shouldn't be too difficult, however, I can't find a way to detect when my custom BadgeValue property changes, because of the above. Atm I use a workaround with MessagingCenter, but I really don't like it.

  • David.6954David.6954 USUniversity ✭✭

    I am running it one problem with this solution, the icons will only load when I click on a tab. They do not load when the page loads. Did I do something wrong?

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    Something to clarify. The above renderer is for Android.

    @ConstantinGherghescu have you add the assembly reference?

    Above the namespace [ In my case above namespace TestingViews.Droid ] i have add and you have to add too

    [assembly: ExportRenderer(typeof(TabbedPage), typeof(TestingViews.Droid.CustomTabRenderer))]

    ,where TestingViews is your project name and the CustomTabRenderer is the renderer name.

    ..Of course you can do that from the assembly file, but i get used to write it here.

    @David.6954 it will must be much faster and easier to post a part of your solution or if you don't want just post the structure you have follow.

    Don't worry we will find a solution for you.
    JJ

  • TeoTeo DKMember ✭✭

    @JohnnyJaxs Yes, I have the assembly reference. I am doing it on iOS, so maybe that's the issue.

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    @ConstantinGherghescu i am going to deploy it in the iphone soon and i will let you know.
    But as i have read somewhere(inside the forum) iphone can work with the default icon property, as i said i have just read it and not test it.

  • TeoTeo DKMember ✭✭

    Yes, it works. I also did some custom stuff to have selected states on icons, but that is pretty straightforward. I was specifically interested in onElementPropertyChanged , because it seems weird that I'm getting errors when im trying to override it.

    So my question was not necessarily related to the icons, but more along the lines of why doesn't TabbedRenderer not have the onElementPropertyChanged method.

  • David.6954David.6954 USUniversity ✭✭

    Yeah sure, here is part of my solution:
    Thanks again for any help! :)

    My custom tabbed page looks like this:

    namespace AssetTracking
    {
    public class AssetDetailsTabbedPage : CustomTabbedPage
    {
    assets asset;

        public AssetDetailsTabbedPage ()
        {
            this.SetBinding (ContentPage.TitleProperty, "assettag");
            this.Children.Add (new AssetDetails { Title="Details", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5)  });
        }
        protected override void OnAppearing ()
        {
            asset = (assets)this.BindingContext;
            BindingContext = AssetTrackingRepository.GetAsset (asset.assetid);
    
            if (this.Title == "" || this.Title == null) {
                this.Title = "New Asset";
            } else {
                this.Title = "Asset Tag: " + asset.assettag;
                this.Children.Add (new AssetDetailsPinpoint { Title="Pinpoint", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
                this.Children.Add (new AssetDetailsStatus { Title="Status", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
                this.Children.Add (new AssetDetailsMaintenance { Title="Maintenance", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
                this.Children.Add (new AssetDetailsNotes { Title="Notes", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
                this.Children.Add (new AssetDetailsWarranties { Title="Warranties", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
            }
            base.OnAppearing ();
        }
    }
    

    }

    And my customer renderer looks like this:

    [assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]

    namespace AssetTracking.Android
    {
    public class CustomTabbedPageRenderer : TabbedRenderer
    {
    private Activity activity;
    private const string COLOR = "#FFFFFF";
    private const string TEXTCOLOR = "#353535";

        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            activity = this.Context as Activity;
    
            ActionBar actionBar = activity.ActionBar;
    
            ColorDrawable colorDrawable = new ColorDrawable(global::Android.Graphics.Color.ParseColor(COLOR));
            actionBar.SetStackedBackgroundDrawable(colorDrawable);
            if (actionBar.TabCount > 0) {
                ActionBarTabsSetup (actionBar);
            }
        }
        private void ActionBarTabsSetup(ActionBar actionBar)
        {
            global::Android.App.ActionBar.Tab details = actionBar.GetTabAt(0);
            if (TabIsEmpty (details)) {
                details.SetIcon (Resource.Drawable.toolbartoolsdisplay);
                //TabSetup(details, Resource.Drawable.toolbartoolsdisplay);
            }
    
            global::Android.App.ActionBar.Tab pinpoint = actionBar.GetTabAt(1);
            if (TabIsEmpty (pinpoint)) {
                pinpoint.SetIcon (Resource.Drawable.toolbarmappindisplay);
                //TabSetup (pinpoint, Resource.Drawable.toolbarmappindisplay);
            }
    
            global::Android.App.ActionBar.Tab status = actionBar.GetTabAt(2);
            if (TabIsEmpty (status)) {
                status.SetIcon (Resource.Drawable.toolbarmenudisplay);
                //TabSetup (status, Resource.Drawable.toolbarmenudisplay);
            }
    
            global::Android.App.ActionBar.Tab maintenance = actionBar.GetTabAt(3);
            if (TabIsEmpty (maintenance)) {
                maintenance.SetIcon (Resource.Drawable.AttachmentDisplay);
                //TabSetup (maintenance, Resource.Drawable.AttachmentDisplay);
            }
    
            global::Android.App.ActionBar.Tab notes = actionBar.GetTabAt(4);
            if (TabIsEmpty (notes)) {
                notes.SetIcon (Resource.Drawable.toolbardocumentcheckdisplay);
                //TabSetup (notes, Resource.Drawable.toolbardocumentcheckdisplay);
            }
    
            global::Android.App.ActionBar.Tab warranties = actionBar.GetTabAt(5);
            if (TabIsEmpty (warranties)) {
                warranties.SetIcon (Resource.Drawable.toolbarribbondisplay);
                //TabSetup (warranties, Resource.Drawable.toolbarribbondisplay);
            }
        }
    
        private bool TabIsEmpty(ActionBar.Tab tab)
        {
            if (tab != null)
                if (tab.CustomView == null)
                    return true;
            return false;
        }
        }
    

    }

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    @ConstantinGherghescu thanks about the confirmation. As soon as start working in the IPhone i will let you know.

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    @David.6954 have you checked OnVisibilityChange()?
    I will review your code tonight.
    Let me know if you find it until then.

  • TeoTeo DKMember ✭✭

    @JohnnyJaxs Have you managed to change the width of the tabs until now? I can't for the life of me make them smaller.

  • David.6954David.6954 USUniversity ✭✭

    @JohnnyJaxs‌ I have tried OnVisiblityChanged(). I have also tried most of the On<...>Changed events and none of them seemed to fix the issue.

  • BryceBrooksBryceBrooks USMember

    protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)

    Doesn't seem to exist on the iOS renderer. How are we supposed to handle property changes? Thanks!

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    Hi, sorry for answering so late but i had an accident. Now i am back.

    @ConstantinGherghescu i haven't try it. Give me some time and i will test it.

    @David.6954 Have you found any solution so far?

    @BryceBrooks‌ i haven't test it to iphone, but i will do it soon and i will find a solution. @ConstantinGherghescu has verify that there is no such method in iphone renderer. Check the post at October 9.

    I will come with more answers asap.

  • MitchMilamMitchMilam USMember ✭✭✭

    @BryceBrooks‌ what version of Xamarin.Forms are you using? if it is not 1.2.3 then you need to upgrade. If you just created a new project it will be using 1.0 and there was a change in the renderer code in 1.1 (I think).

  • BryceBrooksBryceBrooks USMember
    edited November 2014

    @MitchMilam‌ I am using the latest but no go on the override. I went with the solution below. My custom tabbed page class has a bindable TintColor property.

    On iOS I added a property changed handler in my custom renderer and that seemed to do it:

            protected override void OnElementChanged (VisualElementChangedEventArgs e)
            {
                base.OnElementChanged (e);
    
                var page = (CustomTabbedPage)Element;
                page.PropertyChanged += OnPropertyChanged;
    
                //TabBar.TintColor = Color.FromHex("#767676").ToUIColor();
                TabBar.TintColor = page.TintColor.ToUIColor ();
            }
    
            private void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs args)
            {
                if (args.PropertyName == "TintColor") {
                    var page = (CustomTabbedPage)sender;
                    TabBar.TintColor = page.TintColor.ToUIColor ();
                }
            }
    
  • Manikandan.5390Manikandan.5390 USMember
    edited November 2014

    @JohnnyJaxs‌ and @David.6954 In my custom render actionBar.TabCount always zero actionBar.TabCount = 0, Can you please post your tabbedpage code

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    @Manikandan.5390 have check the XAML code in the top of the page?

  • How can we implement below feature in TabbedPage for Android?

    1. Width of the tab
    2. Bottom position of the tab (same like IOS)
    3. Set different images in different tab (similar like attachment)
    4. Change Selected Tab image
  • @ JonnyJaxs I would appreciate help with using Tabbedpage and MasterDetail Page. If i use a Tabbedpage as the detail page of an MDP, the actionbar of the tabbedpage remains still when i slide. The problem is also described here: https://forums.xamarin.com/discussion/18608/masterdetail-tabbed-pages-have-unexpected-results-on-android Please help. Thanks

  • Help :(
    I have this error: Invalid index 0, size is 0, http://puu.sh/fmg4t/c6bbf6f7be.png

    I have your same code :S

  • @David.6954 i have the same problem, the icons only appear when clicking a tab, did you found any solution?

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    I want to maintain this thread, but the last few month i have work too much, so less time for missing that.
    Sorry about that.

    First of all before i start with the answers, i have to say that due to the issues that i have faced with the interface part( MDP, tabbed pages) and the list-view scrolling+ issues, i have decide to moved on Xamarin instead of Xamarin Forms.
    With my short journey with the Xamarin Forms(which has stop on last December) i believe that the XF release is a very fast way to develop a basic feature app fully cross platform, but when you have an app like viber, skype telecommunication type which involves different field with a lot, but a lot of customization where performance and efficiency has a major role , then i prefer to work with Xamarin.

    Anyway this for my experience so far. I am watching the progress and make some tests when i have time and i believe there is a big potential of doing something really cross-platform("really" = i mean the interface part too).

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    @DineshPatankar check the follow funcation:

     private void TabSetup(ActionBar.Tab tab, int resourceID)
            {
                ImageView iv = new ImageView(activity);
                iv.SetImageResource(resourceID);
                iv.SetPadding(-35, 8, -35, 16);
    
                tab.SetCustomView(iv);
            }
    

    Also check the Part 2 at the beginning of the thread. The post is for an Android renderer.
    Also i haven't try to move the action bar at the bottom. To be honest i dont think that you can. Also why to do that?
    Each platform must have its uniqueness... at least this my opinion. So you question(1,3,4) are answered here.

  • CharlinCharlin DOUniversity ✭✭

    Hello! .. Im using your render but i can't see the icons, only can see if when clicking in one of the tabs :S ...

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri BRMember ✭✭✭

    Seems like Class Android.App.ActionBar.Tab was deprecated and dont work in API 19 for me.... there are any corresponding way to do this in high level API's?

  • JohnnyJaxsJohnnyJaxs USMember ✭✭

    @Charlin please post your code.

    @RaphaelChiorlinRanieri unfortunately because at the moment i moved to Xamarin(not forms) it will take me some time to come back and work again. Hopefully somebody will give you a reply.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri BRMember ✭✭✭

    @JohnnyJaxs Thanks! Will hope that someone have solved it!

  • CharlinCharlin DOUniversity ✭✭
    edited April 2015

    @JohnnyJaxs I have almost your same code than yours, the only different is that i had to move the code inside of "OnWindowsChanged" because this threw me a exception: Invalid index 0, size is 0, http://puu.sh/fmg4t/c6bbf6f7be.png

    [assembly: ExportRenderer(typeof(Xamarin.Forms.Labs.Controls.MyTabbedPage), typeof(TestingViews.Droid.CustomTabRenderer))]
    namespace TestingViews.Droid
    {
    public class CustomTabRenderer : TabbedRenderer
    {

        private Activity activity;
        private const string COLOR = "#FFFFFF";
        private const string TEXTCOLOR = "#000000";
        private bool isFirstDesign = true;
        //This flag is used in the case when the app is not completely closed, and the user return back.
    
    
        protected override void OnElementPropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            base.OnElementPropertyChanged(sender, e);
            activity = this.Context as Activity;
    
            ActionBar actionBar = activity.ActionBar;
    
            ColorDrawable colorDrawable = new ColorDrawable(global::Android.Graphics.Color.ParseColor(COLOR));
            actionBar.SetStackedBackgroundDrawable(colorDrawable);
            if (actionBar.TabCount > 0) {
                ActionBarTabsSetup (actionBar);
            }
    
        }
    
        private void ActionBarTabsSetup(ActionBar actionBar)
        {
            try {
    
                    Android.App.ActionBar.Tab avatar = actionBar.GetTabAt(0);
                    if (TabIsEmpty (avatar)) {
                        //avatar.SetIcon (Resource.Drawable.nav_statss);
    
                        TabSetup(avatar, Resource.Drawable.search);
                    }
    
                    Android.App.ActionBar.Tab contacts = actionBar.GetTabAt(1);
                    if (TabIsEmpty (contacts)) {
                        //contacts.SetIcon (Resource.Drawable.nav_notification);
                        //contacts.SetText ("Notifications");
                        TabSetup(contacts, Resource.Drawable.search_active40x40);
                        //actionBar.SelectTab (contacts);
    
                    }
    
                    Android.App.ActionBar.Tab favorites = actionBar.GetTabAt(2);
                    if (TabIsEmpty(favorites))
                        favorites.SetIcon (Resource.Drawable.nav_images);
    
    
                    Android.App.ActionBar.Tab callsLog = actionBar.GetTabAt(3);
                    if (TabIsEmpty(callsLog))
                        callsLog.SetIcon (Resource.Drawable.search_default);
                        //TabSetup(callsLog, Resource.Drawable.avatar);
                //  callsLog.SetText ("Upload");
    
                    Android.App.ActionBar.Tab test = actionBar.GetTabAt(4);
                    if (TabIsEmpty(test))
                        test.SetIcon (Resource.Drawable.nav_account);
                        //TabSetup(callsLog, Resource.Drawable.avatar);
                    //    test.SetText ("Account");
    
            } catch (Exception ex) {
    
            }
    
        }
    
        private bool TabIsEmpty(ActionBar.Tab tab)
        {
            if (tab != null)
            if (tab.CustomView == null)
                return true;
            return false;
        }
    
        private void TabSetup(ActionBar.Tab tab, int resourceID)
        {
            ImageView iv = new ImageView(activity);
            iv.SetImageResource(resourceID);
            //iv.SetPadding(-50, 10, -50, 20);
            iv.SetPadding(-35, 8, -35, 16);
            iv.SetMinimumWidth (20);
            tab.SetCustomView(iv);
        }
    
    }
    

    }

    Thanks :)

  • viossimadjaviossimadja DEMember ✭✭

    I got the same error, can somebody help out here?
    Thx in advance!

  • viossimadjaviossimadja DEMember ✭✭

    Charlin, I´ve used this one and it works properly for me:

    `public class AssetDetailsTabbedPage : CustomTabbedPage
    {
    assets asset;

    public AssetDetailsTabbedPage ()
    {
        this.SetBinding (ContentPage.TitleProperty, "assettag");
        this.Children.Add (new AssetDetails { Title="Details", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5)  });
    }
    protected override void OnAppearing ()
    {
        asset = (assets)this.BindingContext;
        BindingContext = AssetTrackingRepository.GetAsset (asset.assetid);
    
        if (this.Title == "" || this.Title == null) {
            this.Title = "New Asset";
        } else {
            this.Title = "Asset Tag: " + asset.assettag;
            this.Children.Add (new AssetDetailsPinpoint { Title="Pinpoint", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
            this.Children.Add (new AssetDetailsStatus { Title="Status", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
            this.Children.Add (new AssetDetailsMaintenance { Title="Maintenance", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
            this.Children.Add (new AssetDetailsNotes { Title="Notes", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
            this.Children.Add (new AssetDetailsWarranties { Title="Warranties", Icon="AttachmentActive.png", BackgroundColor = Color.White, Padding = new Thickness (5, 5, 5, 5) });
        }
        base.OnAppearing ();
    }
    

    }
    }`

    Big thx to David.6954

  • Aqhtar.7621Aqhtar.7621 USMember

    @JohnnyJaxs i used the same custom renderer for the tabbed page u posted but i am getting array index out of bound exception. It would be very grateful having your words on this.
    PS- the error is in actionBar.GetTabAt(0), actionBar.GetTabAt(1)

  • CharlinCharlin DOUniversity ✭✭
    edited September 2015

    Hello!.. This was my solution

    Render:

    using System;
    using TestingViews.Droid;
    using Android.Widget;
    using Android.App;
    using Android.Graphics.Drawables;
    using Android.Views;
    using System.ComponentModel;
    using Xamarin.Forms.Platform.Android;
    using Xamarin.Forms;
    using Android.Graphics;
    using CGMobile;
    using CGMobile.Droid;

    [assembly: ExportRenderer(typeof(CustomTabPage), typeof(TestingViews.Droid.CustomTabRenderer))]
    namespace TestingViews.Droid
    {
    public class CustomTabRenderer : TabbedRenderer
    {

        private Activity activity;
        private TabbedPage _tabbedPage;
        private const string COLOR = "#FFFFFF";
    
    
        protected override void OnElementChanged (ElementChangedEventArgs<TabbedPage> e)
        {
            base.OnElementChanged (e);
    
            activity = this.Context as Activity;
            _tabbedPage = e.NewElement as TabbedPage;
    
    
        }
    
        protected override void DispatchDraw (Canvas canvas)
        {
    
            ActionBar actionBar = activity.ActionBar;
    
    
            if (actionBar.TabCount > 0) {
                ColorDrawable colorDrawable = new ColorDrawable(global::Android.Graphics.Color.ParseColor(COLOR));
                actionBar.SetStackedBackgroundDrawable(colorDrawable);
                ActionBarTabsSetup (actionBar);
    
            }
    
            base.DispatchDraw (canvas);
        }
    
    
        private void ActionBarTabsSetup(ActionBar actionBar)
        {
            try {
                //_tabbedPage.Children[0].IC
                for(int i = 0; i< actionBar.TabCount; i++)
                {
                    Android.App.ActionBar.Tab dashboardTab = actionBar.GetTabAt(i);
                    if (TabIsEmpty (dashboardTab)) {
    
                        int id = Resources.GetIdentifier(_tabbedPage.Children[i].Icon.File, "drawable", Context.PackageName); 
                        TabSetup(dashboardTab, id);
                    }
    
                }
    
            } catch (Exception) {
    
            }
    
        }
    
        private bool TabIsEmpty(ActionBar.Tab tab)
        {
            if (tab != null)
            if (tab.CustomView == null)
                return true;
            return false;
        }
    
        private void TabSetup(ActionBar.Tab tab, int resourceID)
        {
            ImageView iv = new ImageView(activity);
            iv.SetImageResource(resourceID);
            iv.SetPadding(0, 10, 0, 0);
    
            tab.SetCustomView(iv);
        }
    
    }
    

    }

    In forms:

    this.Children.Add (new MyPage1 { Icon="ico3b",Title=AppResources.Inventories.ToUpper(), ClassId = "Inventory"});
    this.Children.Add (new MyPage { Icon="ico4b",Title=AppResources.Deliveries.ToUpper()});

  • Chris.3704Chris.3704 USUniversity ✭✭

    Awesome, Charlin. That worked for me. Good job!

  • Abhijeet_SuryaAbhijeet_Surya USMember ✭✭✭

    Is it possible to draw tabs @ bottom of pages in Xamarin forms android, without doing complex customisation.

  • Pierre-ChristopheDusPierre-ChristopheDus FRUniversity ✭✭✭

    @Charlin
    Do you have a screenshot of the result you obtain?
    I tried to reproduce what you've done, but I only get a white area instead of the awaited Titles and Icons...

    I use your code for the renderer, and I add my children like this:
    this.Children.Add(new FamiliesChildPage { Icon = "Families.png", Title = "FAMILIES" }); this.Children.Add(new TicketsChildPage { Icon = "Tickets.png", Title = "TICKETS" });

    => Did I forget something?

  • Pierre-ChristopheDusPierre-ChristopheDus FRUniversity ✭✭✭

    @Charlin
    Thanks for your return!
    In fact, my problem was that I had misnamed my icons in the "Resources\drawable" folder: I used capital letters...
    But in your sample, you only display the icons without the associated title: is it possible to display the icon above the title, on basing from the same renderer?

Sign In or Register to comment.