maui icon indicating copy to clipboard operation
maui copied to clipboard

Shell TitleView disappearing on tab change

Open belmonmi opened this issue 1 year ago • 10 comments

Description

On iOS Simulator with Shell.FlyoutBehavior="Flyout" and Tabs, Shell.TitleView is disappearing on tab change.

Steps to Reproduce

  1. Create new .Net MAUI project.

  2. Add couple ContentPages.

  3. Add "AppTitleView" ContentView

  4. Edit AppShell.xaml to set Shell.FlyoutBehavior="Flyout"

  5. Create couple FlyoutItem with Tab elements.

  6. Add <Shell.TitleView> <shellTitleView:AppTitleView /> </Shell.TitleView> to Content Pages

  7. Run application, switch from "Tab 1" to "Tab 2"

  8. Pages on the "Tab 1" will not show "Shell.TitleView", but if you named that TitleView control it still accesable from code behind.

  9. Simple project to demostrate the behavior: https://github.com/belmonmi/ShellTitleView

Version with bug

6.0.408

Last version that worked well

Unknown/Other

Affected platforms

iOS, I was not able test on other platforms

Affected platform versions

iOS 15.5

Did you find any workaround?

No

Relevant log output

2022-08-26 12:20:38.115611-0500 ShellTitleView[10063:986797] 
Options:
2022-08-26 12:20:38.115788-0500 ShellTitleView[10063:986797]   --bool-flag (Example)
	type: bool  default: false
2022-08-26 12:20:38.115883-0500 ShellTitleView[10063:986797]   --aot-lazy-assembly-load (Load assemblies referenced by AOT images lazily)
	type: bool  default: false
Resolved pending breakpoint for 'ShellTitleView.Program.Main(System.String[])' to C:\Projects\iNet6\Mobile\Test\Issues\ShellTitleView\ShellTitleView\Platforms\iOS\Program.cs:10 [0x00000].
Resolved pending breakpoint for 'Xamarin.HotReload.HotReloadAgent.BreakpointSendToIde(System.String)' to D:\a\_work\1\s\HotReload\Source\Xamarin.HotReload.Agent\HotReloadAgent.cs:419 [0x00000].
Resolved pending breakpoint for 'Xamarin.HotReload.HotReloadAgent.BreakpointCheckpoint()' to D:\a\_work\1\s\HotReload\Source\Xamarin.HotReload.Agent\HotReloadAgent.cs:414 [0x00000].
2022-08-26 12:20:40.312306-0500 ShellTitleView[10063:986797] SecTaskLoadEntitlements failed error=22 cs_flags=200, pid=10063
2022-08-26 12:20:40.312590-0500 ShellTitleView[10063:986797] SecTaskCopyDebugDescription: ShellTitleView[10063]/0#-1 LF=0
2022-08-26 12:20:40.319471-0500 ShellTitleView[10063:986797] SecTaskLoadEntitlements failed error=22 cs_flags=200, pid=10063
2022-08-26 12:20:40.319731-0500 ShellTitleView[10063:986797] SecTaskCopyDebugDescription: ShellTitleView[10063]/0#-1 LF=0
Thread started:  #2
Thread started:  #3
Thread started:  #4
2022-08-26 12:20:41.484090-0500 ShellTitleView[10063:986797] [TableView] Warning once only: UITableView was told to layout its visible cells and other contents without being in the view hierarchy (the table view or one of its superviews has not been added to a window). This may cause bugs by forcing views inside the table view to load and perform layout without accurate information (e.g. table view bounds, trait collection, layout margins, safe area insets, etc), and will also cause unnecessary performance overhead due to extra layout passes. Make a symbolic breakpoint at UITableViewAlertForLayoutOutsideViewHierarchy to catch this in the debugger and see what caused this to occur, so you can avoid this action altogether if possible, or defer it until the table view has been added to a window. Table view: <_UIMoreListTableView: 0x7fa4daef2c00; frame = (0 0; 0 0); clipsToBounds = YES; gestureRecognizers = <NSArray: 0x600002e14330>; layer = <CALayer: 0x600002415140>; contentOffset: {0, 0}; contentSize: {0, 0}; a
djustedContentInset: {0, 0, 0, 0}; dataSource: <UIMoreListController: 0x7fa4d9fa97c0>>
Thread started: .NET Timers #5
Thread started: <Thread Pool> #6
Thread started: .NET ThreadPool Gate #7
Thread started: <Thread Pool> #8
Thread started: <Thread Pool> #9
Thread started: <Thread Pool> #10
Thread started: <Thread Pool> #11
Thread started: <Thread Pool> #12
Thread started: <Thread Pool> #13
Thread started: <Thread Pool> #14
2022-08-26 12:20:45.960535-0500 ShellTitleView[10063:986829] Warning: observer object was not disposed manually with Dispose()
2022-08-26 12:20:45.960790-0500 ShellTitleView[10063:986829] Warning: observer object was not disposed manually with Dispose()

belmonmi avatar Aug 26 '22 17:08 belmonmi

ShellTitle "Tab 1" selected - Shell Title is visible, "Tab 2" selected - Shell Title is visible, back to "Tab 1" - Shell Title disappeared.

belmonmi avatar Aug 26 '22 17:08 belmonmi

I had something similar where I had a Route assigned to a TabBar, but not the child tabs. Added those routes and it fixed the header title updating. It's refreshes slow if adding a new page to a stack, but it happens.

<TabBar Route="home">
       <Tab Title="Cats" Route="cats">
           <ShellContent Title="Cats" ContentTemplate="{DataTemplate local:MainPage}" />
       </Tab>
       <Tab Title="Dogs" Route="dogs">
           <ShellContent Title="Dogs" ContentTemplate="{DataTemplate local:MainPage}" />
       </Tab>
    </TabBar>

avavricek avatar Sep 08 '22 21:09 avavricek

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Sep 16 '22 14:09 ghost

Is there a workaround for this? I have an image in titleview and if I read my logs correctly, the image simply gets disposed and is therefore not visible anymore.

this is pretty much a showstopper :/

nebula2 avatar Oct 13 '22 13:10 nebula2

@nebula2 Exactly! We cannot release as well until it fixed. Application title area has a vital information that has be visible always. BTW: works on Android, no issues. Very frustrated...

belmonmi avatar Oct 13 '22 14:10 belmonmi

@belmonmi

Exactly! We cannot release as well until it fixed. Application title area has a vital information that has be visible always. BTW: works on Android, no issues. Very frustrated...

Jeah i started with designing android . yesterday I got an iPhone to test how the app looks and it was horrible. Spent the whole day fixing the most basic things. I have a readme with a list of issues which is getting bigger and bigger.

There are new issues which may be related to this one here. At least they sound like it.

#10128 and

#10350

It's terrible that I cannot even change to something else on iOS (like showing simple text, or an icon or whatever) because no matter what you put into there - it will disappear or it will be outdated ( #6582 ).

and seeing issues with "priority high" and "moved to backlog" has it's very own taste :-| Having a very hard time to stay calm >.<

nebula2 avatar Oct 13 '22 14:10 nebula2

@nebula2 "Having a very hard time to stay calm" - LOL. Your endurance is exceptional!! :)

belmonmi avatar Oct 13 '22 15:10 belmonmi

@belmonmi I worked around it by not using shell at all. I replaced the shell by a combination of NavigationPage and Syncfusion's TabView.

There are disadvantages and I had to rewrite a few parts of my app in order to get this working - but at least my journey can go on.

nebula2 avatar Oct 14 '22 14:10 nebula2

@nebula2 thank you for the update. We are using Developer Express components; I will check if I can accomplish the same with what they provide.

belmonmi avatar Oct 14 '22 16:10 belmonmi

@belmonmi feel free to contact me if you struggle. A sorrow shared is a sorrow halved

nebula2 avatar Oct 14 '22 17:10 nebula2

@belmonmi, @nebula2 I just added a workaround here, then remembered this issue. Looks like you might have found a workaround using some Syncfusion components. Unfortunately I was not able to use Syncfusion.

I tested my workaround using the flyout and tabs and it appears to work. It is essentially the same except you would need to add a menu item to your TitleView to present the flyout. I have added an example of how to do this in the repro project in #9269, which I believe is a duplicate.

tdeborde2 avatar Oct 20 '22 00:10 tdeborde2

@belmonmi, @nebula2 I just added a workaround here, then remembered this issue. Looks like you might have found a workaround using some Syncfusion components. Unfortunately I was not able to use Syncfusion.

I tested my workaround using the flyout and tabs and it appears to work. It is essentially the same except you would need to add a menu item to your TitleView to present the flyout. I have added an example of how to do this in the repro project in #9269, which I believe is a duplicate.

Thank you for sharing. Better than my approach. I wrote some fancy stuff that instantiates views instead of pages to render stuff inside the SfTabView, where every tab item is a view and not a page.

nebula2 avatar Oct 20 '22 08:10 nebula2

attached video shows a Shell TitleView on an iOS device while navigating between Tabs using .NET 7. Sometimes the Title doesn't appear at all, sometimes it moves up, approximately half way out of the window, and sometimes it renders fine. The same TitleView works always as expected on android.

@rachelkang why is this in backlog? Can we expect a fix soon? It seems not possible to show anything else than a plain string in a Title on iOS using AppShell, which is the default template.

https://user-images.githubusercontent.com/20472867/200828892-3a5f3820-b8b2-4497-ba5c-1ad9dcad6d01.mov

borrmann avatar Nov 09 '22 12:11 borrmann

Hello @belmonmi @borrmann ,

I fixed the issue by using a custom render for AppShell on iOS.

  1. Create a new class DemoMauiApp/Platforms/iOS/Renderers/CustomShellRenderer.cs
using CoreGraphics;
using Microsoft.Maui.Controls.Handlers.Compatibility;
using Microsoft.Maui.Controls.Platform.Compatibility;
using UIKit;

namespace DemoMauiApp.Platforms.iOS.Renderers;

public class CustomShellRenderer : ShellRenderer
{
    protected override IShellPageRendererTracker CreatePageRendererTracker()
    {
        return new CustomShellPageRendererTracker(this);
    }

    protected override IShellNavBarAppearanceTracker CreateNavBarAppearanceTracker()
    {
        return new NoLineAppearanceTracker();
    }
}

public class CustomShellPageRendererTracker : ShellPageRendererTracker
{
    public CustomShellPageRendererTracker(IShellContext context) : base(context) { }

    protected override void UpdateTitleView()
    {
        if (ViewController == null || ViewController.NavigationItem == null)
        {
            return;
        }

        var titleView = Shell.GetTitleView(Page);
        if (titleView == null)
        {
            var view = ViewController.NavigationItem.TitleView;
            ViewController.NavigationItem.TitleView = null;
            view?.Dispose();
        }
        else
        {
            var view = new CustomTitleViewContainer(titleView);
            ViewController.NavigationItem.TitleView = view;
        }
    }
}

public class CustomTitleViewContainer : UIContainerView
{
    public CustomTitleViewContainer(View view) : base(view)
    {
        TranslatesAutoresizingMaskIntoConstraints = false;
    }

    public override CGSize IntrinsicContentSize => UILayoutFittingExpandedSize;
}

public class NoLineAppearanceTracker : IShellNavBarAppearanceTracker
{
    public void Dispose() { }

    public void ResetAppearance(UINavigationController controller) { }

    public void SetAppearance(UINavigationController controller, ShellAppearance appearance)
    {
        var navBar = controller.NavigationBar;
        var navigationBarAppearance = new UINavigationBarAppearance();
        navigationBarAppearance.ConfigureWithOpaqueBackground();
        navigationBarAppearance.ShadowColor = UIColor.Clear;
        navigationBarAppearance.BackgroundColor = UIColor.White; // Set the background color you want on the Shell NavBar
        navBar.ScrollEdgeAppearance = navBar.StandardAppearance = navigationBarAppearance;
    }

    public void SetHasShadow(UINavigationController controller, bool hasShadow) { }

    public void UpdateLayout(UINavigationController controller) { }
}

  1. On the MauiProgram.cs configure the handler:
var builder = MauiApp.CreateBuilder();
        builder
            .UseMauiApp<App>()
            .ConfigureMauiHandlers(handlers =>
            {
#if IOS
                handlers.AddHandler(typeof(Shell), typeof(DemoMauiApp.Platforms.iOS.Renderers.CustomShellRenderer));
#endif
            });
  1. Rebuild and Run 💯

I hope this helps others as well! Thank you

vhugogarcia avatar Nov 10 '22 16:11 vhugogarcia

Thank you, works like a charm! Just had to use my inherited class from Shell, in my case AppShell in MauiProgram.cs

Also I would suggest to set the Backgroundcolor using a saved status, so stuff like AppThemeBinding should still work

    public void SetAppearance(UINavigationController controller, ShellAppearance appearance)
    {
        var navBar = controller.NavigationBar;
        var col = navBar.BackgroundColor;
        var navigationBarAppearance = new UINavigationBarAppearance();
        navigationBarAppearance.ConfigureWithOpaqueBackground();
        navigationBarAppearance.ShadowColor = UIColor.Clear;
        navigationBarAppearance.BackgroundColor = col; 
        navBar.ScrollEdgeAppearance = navBar.StandardAppearance = navigationBarAppearance;
    }

borrmann avatar Nov 10 '22 17:11 borrmann

Woot! That fix worked for us. Thanks!

avavricek avatar Nov 18 '22 20:11 avavricek

@vhugogarcia , Thank you very much for the fix you posted. Very simple, elegant solution and the most important thing it is working.

belmonmi avatar Nov 22 '22 21:11 belmonmi