Forum Xamarin.Forms
We are excited to announce that the Xamarin Forums are moving to the new Microsoft Q&A experience. Q&A is the home for technical questions and answers at across all products at Microsoft now including Xamarin!

We encourage you to head over to Microsoft Q&A for .NET for posting new questions and get involved today.

Tabbed page custom renderer on Xamarin.Forms

asiapiazzaasiapiazza Member ✭✭

How can I achieve something like the top bar in the screenshot ("Totale Regioni Province") using a tabbed page custom renderer?
Right now I'm using "fake tabs" made of three different labels.

I need to change font family, font size and padding of the tabs.

Best Answer

Answers

  • JarvanJarvan Member, Xamarin Team Xamurai
    edited July 9

    I need to change font family, font size and padding of the tabs.

    You could cutomize a 'tabView' and use the contentView to display the 'item page'. It'll be easy to change the font style and padding for a label.

    For the switch function, try to detect the gesture tapped event to make the corresponding contentViews to be visible.

    <Grid>
        <Label Grid.Column="0">
            <Label.GestureRecognizers>
                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"/>
            </Label.GestureRecognizers>
        </Label>
        <Label Grid.Column="1">...</Label>
        <Label Grid.Column="2">...</Label>
    </Grid>
    <local:View1 x:Name="view_1"/>
    <local:View2 x:Name="view_2" IsVisible="false"/>
    <local:View3 x:Name="view_3" IsVisible="false"/>
    
  • asiapiazzaasiapiazza Member ✭✭
    edited July 8

    it would work for sure but I would have to move all the code I wrote for the tabs into a single content page and it would become pretty much a mess, that's why I was trying to do it using a custom renderer @Jarvan

  • JarvanJarvan Member, Xamarin Team Xamurai

    but I would have to move all the code I wrote for the tabs into a single content page

    The ControlTemplate may help you on this function. Create a custom control template to display the tab view and consume the template for the pages.

    Check the code:
    App.xaml

    <Application ...>
        <Application.Resources>
            <ResourceDictionary>
                <Style x:Key="labelStyle" TargetType="Label">
                    <Setter Property="HorizontalOptions" Value="CenterAndExpand"/>
                    <Setter Property="VerticalOptions" Value="CenterAndExpand"/>
                    <Setter Property="FontSize" Value="18"/>
                    <Setter Property="Padding" Value="3"/>
                    <Setter Property="FontAttributes" Value="Bold"/>
                </Style>
            </ResourceDictionary>
    
            <ControlTemplate x:Key="template">
                <Grid>
                    <Grid.RowDefinitions>
                        <RowDefinition Height="0.1*" />
                        <RowDefinition Height="0.9*" />
                    </Grid.RowDefinitions>
                    <Grid Grid.Row="0" BackgroundColor="LightBlue">
                        <Label Grid.Column="0" Text="Option_1" Style="{StaticResource  labelStyle}">
                            <Label.GestureRecognizers>
                                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_1"/>
                            </Label.GestureRecognizers>
                        </Label>
                        <Label Grid.Column="1" Text="Option_2" Style="{StaticResource  labelStyle}">
                            <Label.GestureRecognizers>
                                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_2"/>
                            </Label.GestureRecognizers>
                        </Label>
                        <Label Grid.Column="2" Text="Option_3" Style="{StaticResource  labelStyle}">
                            <Label.GestureRecognizers>
                                <TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped_3"/>
                            </Label.GestureRecognizers>
                        </Label>
                    </Grid>
                    <ContentPresenter Grid.Row="1" />
                </Grid>
            </ControlTemplate>
        </Application.Resources>
    </Application>
    

    Tap gesture event:

    private void TapGestureRecognizer_Tapped_1(object sender, EventArgs e)
    {
        if (Current.MainPage.GetType() == typeof(MainPage))
            return;
        Application.Current.MainPage = new NavigationPage(new MainPage());
    }
    

    Consume the ControlTemplate in each page.

    <ContentPage ...
                 ControlTemplate="{StaticResource template}">
        ...
    </ContentPage>
    


    Here is the demo file, you could refer to the code.

  • asiapiazzaasiapiazza Member ✭✭
    edited July 9

    What if I want to change the label's opacity when changing page to give the impression of using a tabbed page (like in the screenshot i posted above, the selected page should have opacity = 1 for its label, while the other should be something like 0.6).

    I tried to access each label programmatically and change the opacity that way, but it doesn't work because the control template is reloaded when switching page. @Jarvan

  • JarvanJarvan Member, Xamarin Team Xamurai
    edited July 10

    To create a custom tabbedPage renderer:
    On Android, create a layout.xml to customize the tab view. Set the view in SetTabIcon method of the render class

    public class CustomTabbedPageRenderer : TabbedPageRenderer
    {
        public MyTabbedPageRenderer(Context context) : base(context)
        {
        }
    
        protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
        {
            base.SetTabIcon(tab, icon);
            tab.SetCustomView(Resource.Layout.Custom_tab_layou);
    
            //set the text and icon
        }
    }
    

    You could google withe the keyword as Xamarin.Forms: Change Icon & Text size in TabbedPage tabs to check the related tutorial.

    iOS: Override the ViewWillAppear method to iterate the Tab children, then change each item setting a SetTitleTextAttributes.

    public class CustomTabbedPageRenderer : TabbedRenderer
    {
        public override void ViewWillAppear(bool animated)
        {
            if (TabBar?.Items == null)
                return;
    
            var tabs = Element as TabbedPage;
            if (tabs != null)
            {
                for (int i = 0; i < TabBar.Items.Length; i++)
                {
                    UpdateTabBarItem(TabBar.Items[i], tabs.Children[i].Icon);
                }
            }
    
            base.ViewWillAppear(animated);
        }
    
        private void UpdateTabBarItem(UITabBarItem item, string icon)
        {
            if (item == null || icon == null)
                return;
    
            // Set the font for the title.
        }
    }
    

    For this, search with the keyword as Extending TabbedPage in Xamarin Forms to get the related link.

  • asiapiazzaasiapiazza Member ✭✭
    edited July 10

    Any idea on how would the Custom_tab_layout look like?
    Sorry to bother you but I have zero experience in android development and I'm struggling to figure it out on my own, thank you. @Jarvan

  • asiapiazzaasiapiazza Member ✭✭
    edited July 13
    I've already achieved this using a pancake view. My question was about that SetTabIcon method for the android custom renderer. I tried to create a Custom_tab_layout.xml like you suggested with a simple TextView with the right fontsize, font family and padding like I wanted, and I applied it with tab.SetCustomView(Resource.Layout.Custom_tab_layou), but the name of the tab isn't shown.

    Any idea on how to set the title of the page as the title of the tab? @Jarvan
  • JarvanJarvan Member, Xamarin Team Xamurai

    Try the following code, it works on my side.

    public class CustomTabbedPageRenderer : TabbedPageRenderer
    {
        public CustomTabbedPageRenderer(Context context) : base(context)
        {
        }
    
        protected override void SetTabIcon(TabLayout.Tab tab, FileImageSource icon)
        {
            base.SetTabIcon(tab, icon);
            tab.SetCustomView(Resource.Layout.tab_layout);
    
            var title = tab.CustomView.FindViewById<TextView>(Resource.Id.title);
            title.SetText(tab.Text, TextView.BufferType.Normal);
            //custom the font style
    
            ColorStateList colors2 = null;
            if ((int)Build.VERSION.SdkInt >= 23)
                colors2 = Resources.GetColorStateList(Resource.Color.icon_tab, Forms.Context.Theme);
            else
                colors2 = Resources.GetColorStateList(Resource.Color.icon_tab);
    
            title.SetTextColor(colors2);
        }
    }
    
  • asiapiazzaasiapiazza Member ✭✭
    Is this supposed to change the selected tab textcolor too? If not how would I do that? @Jarvan
  • JarvanJarvan Member, Xamarin Team Xamurai

    To change the textcolor when selecting, try to the platform-specific method.

    public partial class TabbedPage1 : Xamarin.Forms.TabbedPage
    {
        public TabbedPage1()
        {
            InitializeComponent();
    
            this.On<Android>().SetBarItemColor(Color.Red);
            this.On<Android>().SetBarSelectedItemColor(Color.White);
        }
    }
    

    Refer to: https://github.com/xamarin/Xamarin.Forms/pull/4899

    However, it doesn't seem to work for the custom renderer. To change the font style of the tab, you could do this via the configuration in Tabbar.xml.

    <android.support.design.widget.TabLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/sliding_tabs"
        ...
        app:tabTextAppearance="@style/CustomTab"
        .../>
    

    styles.xml

    <style name="CustomTab" parent="@android:style/Widget.Holo.ActionBar.TabText">
        <item name="android:textSize">15sp</item>
      </style>
    
Sign In or Register to comment.