Jamal
Jamal

Reputation: 976

Xamarin Forms Android Custom TabbedPage ActionBar is returning null

I am using custom TabbedPage in my project for showing a badges(count) in Tab bar. I am using the below code for showing a custom tab bar but it is always returning null value in CustomTabbedPageRenderer.cs class OnWindowVisibilityChanged method's activity.ActionBar. I have tried the many workaround like changing the Theme as Theme.AppCompat.Light.DarkActionBar and added the below line in Window.RequestFeature(WindowFeatures.ActionBar); MainActivity.cs , but unfortunately these didn't help me.

MainActivity.cs

  namespace Bakery.Droid
    {
        [Activity(Label = "Bakery.Droid", Icon = "@mipmap/icon_launcher", Theme = "@style/MyTheme", MainLauncher = false, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation, ScreenOrientation = ScreenOrientation.Portrait)]
        public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
        {
                protected override void OnCreate(Bundle bundle)
                {

                    base.OnCreate(bundle);

                    global::Xamarin.Forms.Forms.Init(this, bundle);         

                    LoadApplication(new App());
                }


            }

        }

Home.cs

using System;
using System.Collections.Generic;
using Xamarin.Forms;

namespace Bakery
{
    public class Home : CustomTabPage
    {
        public Home()
        {

            NavigationPage.SetHasNavigationBar(this, false);

            var burger = new NavigationPage(new Burger());
            burger.Icon = "burger.png";
            burger.Title = "Burger";

            var sandwich = new NavigationPage(new Sandwich());
            sandwich.Icon = "sandwich.png";
            sandwich.Title = "Sandwich";

            var pizza = new NavigationPage(new Pizza());
            pizza.Icon = "pizza.png";
            pizza.Title = "Pizza";


            var roll = new NavigationPage(new Roll());
            roll.Icon = "roll.png";
            roll.Title = "Roll";

            //adding childrens into the tab
            Children.Clear();
            Children.Add(burger);
            Children.Add(sandwich);
            Children.Add(pizza);
            Children.Add(roll);
        }

        protected override void OnAppearing()
        {
            base.OnAppearing();     
        }
    }
}

CustomTabPage.cs

using System;
using Xamarin.Forms;

namespace Bakery
{
    public class CustomTabPage : TabbedPage
    {

    }
}

styles.xml

<?xml version="1.0" encoding="UTF-8"?>
<resources>
    <style name="MyTheme" parent="MyTheme.Base">
    </style>

    <style name="MyTheme.Base" parent="Theme.AppCompat.Light.DarkActionBar">

        <item name="windowNoTitle">true</item>

        <item name="windowActionBar">true</item>        

        <item name="windowActionModeOverlay">true</item>        


    </style>

</resources>

CustomTabbedPageRenderer.cs

 [assembly: ExportRenderer(typeof(TabbedPage), typeof(CustomTabbedPageRenderer))]
    namespace Bakery.Droid
    {
        public class CustomTabbedPageRenderer : TabbedRenderer
        {
            Activity activity;
            List<string> filenames;

            protected override void OnElementChanged(ElementChangedEventArgs<TabbedPage> e)
            {
                base.OnElementChanged(e);
                filenames = e.NewElement.Children.Select(t => t.Icon.File).ToList();
            }

            protected override void OnElementPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
            {
                base.OnElementPropertyChanged(sender, e);
                activity = this.Context as Activity;
            }

            protected override void OnWindowVisibilityChanged(Android.Views.ViewStates visibility)
            {
                try
                {
                    base.OnWindowVisibilityChanged(visibility);
                    var actionBar = activity.ActionBar;
                    var colorDrawable = new ColorDrawable(Android.Graphics.Color.Yellow);
                    actionBar.SetStackedBackgroundDrawable(colorDrawable);
                    System.Diagnostics.Debug.WriteLine("Onwindow visible");
                    ActionBarTabsSetup(actionBar);
                }
                catch (Exception Exception)
                {
                    System.Diagnostics.Debug.WriteLine("Exception: " + Exception.ToString());
                }
            }

            void ActionBarTabsSetup(ActionBar actionBar)
            {
                for (var i = 0; i < actionBar.NavigationItemCount; ++i)
                {
                    var tab = actionBar.GetTabAt(i);
                    var id = GetImageFromFilename(i);
                    if (id != 0)
                        TabSetup(tab, id);
                }
            }

            void TabSetup(ActionBar.Tab tab, int resID)
            {
                var relLay = new Android.Widget.RelativeLayout(activity)
                {
                    LayoutParameters = new LayoutParams(LayoutParams.WrapContent, 180)

                };

                var linLay = new LinearLayout(activity)
                {
                    LayoutParameters = new LayoutParams(LayoutParams.WrapContent, 180),
                    Orientation = Orientation.Vertical,
                };
                linLay.SetHorizontalGravity(Android.Views.GravityFlags.Center);
                var imageView = new ImageView(activity);
                imageView.SetImageResource(resID);
                imageView.SetPadding(-35, 4, -35, 0);
                imageView.SetMinimumWidth(60);

                var textView = new TextView(activity)
                {
                    Text = tab.Text
                };


                linLay.AddView(imageView);
                linLay.AddView(textView);       

                relLay.AddView(linLay);

                var badgeView = new TextView(activity)
                {
                    Text = "2"
                };

                var badgeImageView = new ImageView(activity);
                badgeImageView.SetImageResource(Resource.Drawable.red);
                badgeImageView.SetMinimumWidth(5);
                badgeImageView.SetMinimumHeight(5);
                badgeImageView.SetPadding(77, 5, 0, 0);
                badgeView.SetPadding(85, 0, 0, 0);

                relLay.AddView(badgeImageView);
                relLay.AddView(badgeView);
                tab.SetCustomView(relLay);
            }

            int GetImageFromFilename(int n)
            {
                var filename = filenames[n].Split('.');
                var id = Resources.GetIdentifier(filename[0], "drawable", activity.PackageName);
                return id;
            }
        }
    }

Upvotes: 0

Views: 1055

Answers (1)

Elvis Xia - MSFT
Elvis Xia - MSFT

Reputation: 10831

I am using the below code for showing a custom tab bar but it is always returning null value in CustomTabbedPageRenderer.cs class OnWindowVisibilityChanged method's activity.ActionBar.

The ActionBar is null because it is never set in the activity. You need to set the actionbar first:

  1. In MainActivity.cs Set the SupportActionBar like below:

    //Create your own theme "MyTheme"
    [Activity(Label = "CustomTabbedPageDemo", Icon = "@drawable/icon", Theme = "@style/MyTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)]
    public class MainActivity : global::Xamarin.Forms.Platform.Android.FormsAppCompatActivity
    {
        protected override void OnCreate(Bundle bundle)
        {
            //Get the ActionBar Layout in Resouce\layout\Toolbar.axml
            var toolbar=(Toolbar)LayoutInflater.Inflate(Resource.Layout.Toolbar, null);
            //Set the Support ActionBar
            SetSupportActionBar(toolbar);
            SupportActionBar.Title = "My ActionBar";
            base.OnCreate(bundle);
    
            global::Xamarin.Forms.Forms.Init(this, bundle);
        LoadApplication(new App());
        }
    }
    
  2. Create your own theme to replace the default one. Xamarin.Forms requires theme inherited from Theme.AppCompat.XXX.XXX:

    <style name="MyTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="windowNoTitle">true</item>
        <item name="windowActionBar">false</item>
        <item name="colorPrimary">#5A8622</item>
    </style>
    
  3. Basic Toolbar.axml example:

    <?xml version="1.0" encoding="utf-8"?>
    <android.support.v7.widget.Toolbar 
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/toolbar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="?attr/colorPrimary"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"/>
    
  4. Modify your CustomTabPageRenderer.cs change the namespace of ActionBar from Android.App to using Android.Support.V7.App and retrieve the ActionBar through activity.SupportActionBar:

    using Android.Support.V7.App;
    ...
    protected override void OnWindowVisibilityChanged(Android.Views.ViewStates visibility)
    {
        try
        {
            base.OnWindowVisibilityChanged(visibility);
            //get the support actionbar
            var actionBar = activity.SupportActionBar;
    
            var colorDrawable = new ColorDrawable(Android.Graphics.Color.Yellow);
            actionBar.SetStackedBackgroundDrawable(colorDrawable);
            System.Diagnostics.Debug.WriteLine("Onwindow visible");
    
            ActionBarTabsSetup(actionBar);
        }
        catch (Exception Exception)
        {
            System.Diagnostics.Debug.WriteLine("Exception: " + Exception.ToString());
        }
    }
    

Upvotes: 1

Related Questions