dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.17k stars 1.74k forks source link

Maui migrating Xamarin to Maui - Tabbed Page Scroll Issue - Tabs are not scrolling #16470

Open siddhisadh opened 1 year ago

siddhisadh commented 1 year ago

Description

Hi, we are migrating from Xamarin to Maui, so we want to implement this with minimal changes otherwise it will be a big change and we don't want to use ShellTabs..

-Minimum target API is 27

-Expected behavior is tabs should scroll Below is Tabbed Page code

Tab

Steps to Reproduce

  1. Open the Maui application
  2. Run and see the behavior of tabs
  3. It should be scrollable
  4. Added Tabbar.xml file in Resources/Layout/Tabbar.xml. Added below code in project file also,

Link to public reproduction project repository

https://github.com/siddhisadh/MauiAppTabs

Version with bug

Unknown/Other

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Android 9 and Up

Did you find any workaround?

https://learn.microsoft.com/en-us/answers/questions/1332948/in-maui-tabbedpage-tabmode-scrollbar-is-not-workin

Relevant log output

No response

Eilon commented 1 year ago

@siddhisadh the repro app you posted at https://github.com/siddhisadh/MauiAppTabs does not seem to be available or it is not public. Can you please check that you published your repro app and that it is public? Thanks!

ghost commented 1 year ago

Hi @siddhisadh. We have added the "s/needs-repro" label to this issue, which indicates that we require steps and sample code to reproduce the issue before we can take further action. Please try to create a minimal sample project/solution or code samples which reproduce the issue, ideally as a GitHub repo that we can clone. See more details about creating repros here: https://github.com/dotnet/maui/blob/main/.github/repro.md

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

siddhisadh commented 1 year ago

@siddhisadh the repro app you posted at https://github.com/siddhisadh/MauiAppTabs does not seem to be available or it is not public. Can you please check that you published your repro app and that it is public? Thanks!

Hi, Now repository is public. Thank You

AnnYang01 commented 1 year ago

Verified this on Visual Studio Enterprise 17.8.0 Preview 1.0 in Android 13.0-API33, This issue does not repro on .NET 8.0 with below Project. MauiAppTabs-master.zip Tabs can scroll in Android 13.0-API33 Tabbed

ghost commented 1 year ago

Hi @siddhisadh. We have added the "s/try-latest-version" label to this issue, which indicates that we'd like you to try and reproduce this issue on the latest available public version. This can happen because we think that this issue was fixed in a version that has just been released, or the information provided by you indicates that you might be working with an older version.

You can install the latest version by installing the latest Visual Studio (Preview) with the .NET MAUI workload installed. If the issue still persists, please let us know with any additional details and ideally a reproduction project provided through a GitHub repository.

This issue will be closed automatically in 7 days if we do not hear back from you by then - please feel free to re-open it if you come back to this issue after that time.

siddhisadh commented 1 year ago

Expected behavior is tabs should scroll Below is Tabbed Page code

@AnnYang01 Hi, Thanks for your response.

The issue is TABS are not scrolling not tab content. Tabs Title should come full and properly and not in truncated view and should be scroll.

If there are 2-3 tabs , the title is coming properly but when added more then 3 tabs , tabs title is truncated

for eg - Title is New Tab 1 but its showing only N...

Expected Behavior should be like xamarin tabs (image 2nd)

mauiTabs

xamarinTabs

AnnYang01 commented 1 year ago

@siddhisadh thank you for explanation! from the attached project and recording, we can confirm that this issue repro in Android 13.0-API33.

siddhisadh commented 1 year ago

thank you for explanation! from the attached project and recording, we can confirm that this issue repro in Android 13.0-API33.

Ok, when can expect the fix for this as we have some urgent deliverables stuck due to that. Please try to fix this asap as we don't see a proper alternative for the same

Bennynation commented 1 year ago

Is there any news about this problem? I have the same problem

widavies commented 1 year ago

This was a blocker for me too, I submitted a pull request to fix the issue (it involves mapping a property to the underlying TabLayout on Android).

For now, here is a really hacky workaround (please suggest a more reliable workaround if you have an idea on how to do it):


// In your MauiProgram.cs:

            }).ConfigureMauiHandlers(handlers => {
#if ANDROID
                // Add a handler
                handlers.AddHandler(typeof(TabbedPage), typeof(Platforms.Android.ScrollableTabbedViewHandler ));
#endif
            });

In Platforms/Android/CustomRenderers.cs add:

public class ScrollableTabbedViewHandler : TabbedViewHandler {
    public override void UpdateValue(string property) {
        base.UpdateValue(property);

        var tabs = Platform.CurrentActivity?.FindViewById<FragmentContainerView>(Microsoft.Maui.Resource.Id
            .navigationlayout_toptabs);

        var tabLayout = tabs?.GetChildAt(0);

        if(tabLayout is TabLayout layout) {
            layout.TabMode = TabLayout.ModeScrollable;
            layout.SetSelectedTabIndicatorColor(Colors.White.ToAndroid());
        }
    }
}

This handler feels really hacky (having to use UpdateValue doesn't seem right), I tried ConnectHandler, but the TabLayout isn't available that early and CreatePlatformView is seemingly never called.

Let me know if you guys have any ideas, I suppose it doesn't matter that much anyway as long as it holds us over until the PR is merged.

Edit: Here's how to make the tab text have the correct case (the default is ALL CAPS):

if(tabLayout is TabLayout layout) {
    layout.TabMode = TabLayout.ModeScrollable;
    layout.SetSelectedTabIndicatorColor(Colors.White.ToAndroid());

    for(int i = 0; i < layout.TabCount; i++) {
        TabLayout.Tab? tab = layout.GetTabAt(i);
        TabLayout.TabView? view = tab?.View;

        for(int j = 0; j < (view?.ChildCount ?? 0); j++) {
            var child = view?.GetChildAt(j);

            if(child is TextView tv) {
                tv.SetAllCaps(false);
            }
        }
    }
}
Bennynation commented 1 year ago

Big thank you Widavies ! Seems to work well, you make my day

siddhisadh commented 1 year ago

Thank you for the solution. :)

Bennynation commented 1 year ago

I just realized that the workaround does not work when a page containing a tabbedPage opens a modal having a tabbedpage. The modal's tabbedpage will not have scrolling since CurrentActivity will not return the modal. I haven't found how to access the TabMode of the modal for the moment.

RodgerLeblanc commented 1 year ago

@Bennynation I can reproduce the same behavior when a TabbedPage is within a page that has been pushed with Navigation.PushModalAsync, the only workaround that I found so far is using reflection to access the TabLayout :

public class ScrollableTabbedViewHandler : TabbedViewHandler
{
    public override void SetVirtualView(IView view)
    {
        base.SetVirtualView(view);

        TrySetModeScrollable(view);
    }

    private bool TrySetModeScrollable(IView view)
    {
        try
        {
            FieldInfo tabbedPageManagerFieldInfo = typeof(TabbedPage).GetField("_tabbedPageManager", BindingFlags.NonPublic | BindingFlags.Instance);
            object tabbedPageManager = tabbedPageManagerFieldInfo?.GetValue(view);

            FieldInfo tabLayoutFieldInfo = tabbedPageManager?.GetType().GetField("_tabLayout", BindingFlags.NonPublic | BindingFlags.Instance);
            TabLayout tabLayout = tabLayoutFieldInfo?.GetValue(tabbedPageManager) as TabLayout;

            if (tabLayout != null)
            {
                tabLayout.TabMode = TabLayout.ModeScrollable;
                tabLayout.TabGravity = TabLayout.GravityFill;

                return true;
            }

            return false;
        }
        catch
        {
            return false;
        }
    }
}

public static class MauiProgram
{
    public static MauiApp CreateMauiApp()
    {
        var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            //...
            .ConfigureMauiHandlers((handlers) =>
            {
#if ANDROID
                handlers.AddHandler(typeof(TabbedPage), typeof(ScrollableTabbedViewHandler));
#endif
            });

        //...

        return builder.Build();
    }
}

Note that using reflection means this workaround can break at any moment as it supposes that a field _tabbedPageManager exists in TabbedPage class, and that a field _tabLayout exists in the internal TabbedPageManager class. If Microsoft decides to rename/remove those fields, this code will not work anymore.

vklinkov commented 6 months ago

We made POC before starting to migrate to MAUI. But POC do not cover this case. Yes, same problem with tabs scroll. Work around is working. Waiting for fix.