Xamarin.forms: [Enhancement] Shell TabBar Action on Current Tab Tapped

Created on 15 Jun 2019  Â·  18Comments  Â·  Source: xamarin/Xamarin.Forms

Summary

When a Shell has tabs it would be great if there was an easy way to do something when the current tab is tapped.

I can't see anything documented for this so hopefully i'm not missing something.

API Changes

I am not too sure of the best way to go about this.
Maybe something like a command property OnCurrentTabTapped for each tab?
I am sure one of the team will have a better idea on this.

Intended Use Case

Many popular apps have actions where the current tab is tapped e.g fitbit and youtube tapping the home tab when on the home page takes you back to the top of the page. It would also be useful when a sub page is in view to get back to the main page.

The have been some pre shell solutions for this e.g:
https://stackoverflow.com/questions/42801222/xamarin-forms-tabbedpage-event-when-current-tab-is-tapped-to-refresh-the-page
https://stackoverflow.com/questions/44847298/how-to-detect-xamarin-forms-tabbed-page-click-ios

shell in-progress high impact proposal-open enhancement âž•

Most helpful comment

It would be really nice to get a simple event where we can hook into but as I needed this now, here is a small sample that pops to root when the user presses the current selected tab. This uses a renderer which AFAIK is the only possible way to do. It would also be really nice that both platforms do the same thing as right now iOS pops to root by default whereas Android does nothing.

Add those two renderers to your Android project. I guess it works the same on iOS but I haven't tried.

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

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using My.App.Android.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(Shell), typeof(JknShellRenderer))]
namespace My.App.Android.Renderers
{
    /// <summary>
    /// The JknShellRenderer is necessary in order to replace the ShellItemRenderer with your own.
    /// </summary>
    class JknShellRenderer : ShellRenderer
    {
        public JknShellRenderer(Context context) : base(context)
        {
        }

        protected override IShellItemRenderer CreateShellItemRenderer(ShellItem shellItem)
        {
            return new JknShellItemRenderer(this);
        }
    }
}

And

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

using Android.Graphics;
using Android.OS;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;


namespace My.App.Android.Renderers
{
    /// <summary>
    /// This renderer is necessary to allow us to handle the TabReselected (current tab clicked) event as it is not implemented by default on Android
    /// and the only way is to go through a renderer. 
    /// </summary>
    public class JknShellItemRenderer : ShellItemRenderer
    {
        public JknShellItemRenderer(IShellContext shellContext) : base(shellContext)
        {
        }

        /// <summary>
        /// Pops to root when the selected tab is pressed.
        /// </summary>
        /// <param name="shellSection"></param>
        protected override void OnTabReselected(ShellSection shellSection)
        {
            Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
            {
                await shellSection?.Navigation.PopToRootAsync();
            });
        }
    }
}

All 18 comments

agree with this - quite a few popular apps (spotify / instagram) have this as a learned UX, but currently not possible with App Shell.

It looks like when you tap it on an iOS it pops back to the root but on Android it does nothing. There is no method to override or event to subscribe to.

Any news on this?

This feature becomes particularly important when you have a large list that you need to refresh, or scroll to the top of. If using pull to refresh, you would need to scroll to the top of the list manually, and then refresh.
For a work around I have implemented a toolbar item to scroll to the top of the list.

It would be nice to have the ability to tap the current tab and somehow capture this, you could then of course implement the same functionality as facebook and instagram - which would then invoke the scroll and/or refresh.

Another use for this feature is the ability to change the app style when switching tabs.

This should be included in Xamarin Shell. Just a way to capture a Tap event would be enough.

So it was correct to warning user that Shell is currently a Beta, or for using with one page only

On iOS you can use the "OnNavigating" shell event and catch when "current" and "target" have the same route. But on droid the event does not fire when you press the current tab...

It would be really nice to get a simple event where we can hook into but as I needed this now, here is a small sample that pops to root when the user presses the current selected tab. This uses a renderer which AFAIK is the only possible way to do. It would also be really nice that both platforms do the same thing as right now iOS pops to root by default whereas Android does nothing.

Add those two renderers to your Android project. I guess it works the same on iOS but I haven't tried.

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

using Android.App;
using Android.Content;
using Android.OS;
using Android.Runtime;
using Android.Views;
using Android.Widget;
using My.App.Android.Renderers;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;

[assembly: ExportRenderer(typeof(Shell), typeof(JknShellRenderer))]
namespace My.App.Android.Renderers
{
    /// <summary>
    /// The JknShellRenderer is necessary in order to replace the ShellItemRenderer with your own.
    /// </summary>
    class JknShellRenderer : ShellRenderer
    {
        public JknShellRenderer(Context context) : base(context)
        {
        }

        protected override IShellItemRenderer CreateShellItemRenderer(ShellItem shellItem)
        {
            return new JknShellItemRenderer(this);
        }
    }
}

And

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

using Android.Graphics;
using Android.OS;
using Android.Support.Design.Widget;
using Android.Views;
using Android.Widget;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;


namespace My.App.Android.Renderers
{
    /// <summary>
    /// This renderer is necessary to allow us to handle the TabReselected (current tab clicked) event as it is not implemented by default on Android
    /// and the only way is to go through a renderer. 
    /// </summary>
    public class JknShellItemRenderer : ShellItemRenderer
    {
        public JknShellItemRenderer(IShellContext shellContext) : base(shellContext)
        {
        }

        /// <summary>
        /// Pops to root when the selected tab is pressed.
        /// </summary>
        /// <param name="shellSection"></param>
        protected override void OnTabReselected(ShellSection shellSection)
        {
            Xamarin.Forms.Device.BeginInvokeOnMainThread(async () =>
            {
                await shellSection?.Navigation.PopToRootAsync();
            });
        }
    }
}

Is there still not anyway to do this in Forms? I just want to have the ability TabPage provided to hook into selected tab tap. Scroll my listview in that tab to the top.

thanks @jonx

@aherrick see the links in the initial comment. Is that not helping?

+1

the example by @jonx worked great fyi

is there an ETA on this guy? It's been over a year, and we still don't have consistent behavior between iOS & Android for this core piece of tab navigation UX.

Upvoting this.

Upvoting this.

Upvoting this

Upvoting this.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Stensan picture Stensan  Â·  3Comments

Papirosnik picture Papirosnik  Â·  3Comments

simontocknell picture simontocknell  Â·  3Comments

EmilAlipiev picture EmilAlipiev  Â·  3Comments

sonic1015 picture sonic1015  Â·  3Comments