SwiftUI SDK Integration

[Problem/Question]
NavigationBar issue with SwiftUI SDK when a TabView is used.

We found out there is an issue while launching a a the ChannelGroupView using the .groupChannelView method from the GroupChannelListView when it is inside a TabView.

The TabView + HostedController (embedded in the SDK) is provoking the navbar to be added twice resulting in an unwanted top margin (cf screenshot).
Processing: Screenshot 2024-09-17 at
Screenshot 2024-09-17 at 12.59.13
12.45.52.png…


[SwiftUI SDK Version]
1.0.0-beta.1

[Reproduction Steps]

        var body: some View {
            TabView {
                GroupChannelListView(
                    headerItem: {
                        .init()
                        .rightView { _ in }
                        .titleView { viewConfig in
                            Text("Messages")
                        }
                    }
                )
                .groupChannelView { channelURL, startingPoint, messageListParams in
                    GroupChannelView(
                        channelURL: channelURL,
                        startingPoint: startingPoint,
                        messageListParams: messageListParams,
                        headerItem: {
                            .init()
                            .rightView { _ in }
                        }
                    )
                }
                .tabItem {
                    Image(systemName: "person")
                }
            }
        }

[Frequency]
Reproducible 100%

[Current impact]
The navigationbar is messed up.

Hi @GetChivy
I just checked this issue.
Could you check the following to try to resolve the issue?

  • Sendbird SwiftUI is provided by hosting viewControllers of Sendbird UIKit.
    During this process, the navigation settings are also set in UIKit, and Sendbird SwiftUI should use the navigationBar configured in Sendbird UIKit.
    When using Sendbird SwiftUI functionality, multiple navigationBars can be exposed if the navigationBar exposed by the SwiftUI is not hidden.
  • To work around this issue in the current version, you can add the following options to View.
    var body: some View {
        TabView {
            GroupChannelListView()
            .tabItem {
                Image(systemName: "person")
            }
        }
        .navigationBarHidden(true) // <-- Add this logic
    }
    

Result

[Github discussion] How do I fix the multiple navigation bars showing up?

Hello @Tez

Thanks for you reply.

I tried your fix, but it does not fix the Navigationbar appearing on the GroupChannelView

You can see in the reproducible code below I added the navigationBarHidden(true) directly on the TabView.

import SwiftUI

extension CustomGroupChannelList.SubView.Builder {
    struct groupChannel: View {
        var body: some View {
            TabView {
                GroupChannelListView(
                    headerItem: {
                        .init()
                        .rightView { _ in }
                        .titleView { viewConfig in
                            Text("Messages")
                        }
                    }
                )
                .groupChannelView({ channelURL, startingPoint, messageListParams in
                    if #available(iOS 16.0, *) {
                        self.toolbar(.hidden, for: .tabBar)
                    } else {
                        // Fallback on earlier versions
                    }
                    return GroupChannelView(
                        channelURL: channelURL,
                        startingPoint: startingPoint,
                        messageListParams: messageListParams,
                        headerItem: {
                            .init()
                            .rightView { _ in }
                        }
                    )
                })
                .onDisappear(perform: {
                    if #available(iOS 16.0, *) {
                        self.toolbar(.hidden, for: .tabBar)
                    } else {
                        // Fallback on earlier versions
                    }
                })
                .tabItem {
                    Image(systemName: "person")
                }
            }.navigationBarHidden(true)
        }
    }
}

#Preview {
    CustomGroupChannelList.SubView.Builder.groupChannel()
}

But i’s still showing the same on the GroupChannelView.

The use case is very simple : we want our messenger to be accessible from our app’s main navigation which is a Tabbar with 4 major screens.

Hi @GetChivy,
Sorry for the late check!
I found the problem when using it as a modal type and reproduced the same as you.
I have done some rough testing on this and will be releasing a new version with the fix.
And I will comment back when it’s released.

Awesome Tez ! Thanks for the feedback, really appreciate.

To help debugging :

I used the modal in the QuickStartSwiftUI project to have a separated Tabbar independent from the main navigation of this project.
However, the issue is not related to the “modal”, but it’s definitely related to the “tabbar”.
Also, with a simple regular tabbar as the main navigation, this double navbar appears just like on the previous screenshot.

Thanks for the quick reply.
I said modal, but it meant presented style.
In the screenshot in question, a tabview based screen is being presented as a modal style.
Sendbird SwiftUI are using uikit’s viewController hosted, and if it is displayed in a modal style in SwiftUi, we will need to modify internal hierarchy search logic.
I’d like to test this a bit more thoroughly, so could you share the your test code to show how you got the tabview based screen to draw the modal style on the screen?

Hi @Tez ,

The sample code is in my first message above (including the TabView being presented).

And, in order to present this TabView, I modified this view from your test project, by commenting the .backgroun() method, and adding a .sheet method.

struct CustomSampleSubView: View {
    var keyfunction: CustomSampleInfo.KeyFunction
    @StateObject var viewModel: CustomSampleSubViewModel
    @State private var isActive = false
    @State private var destinationView: AnyView? = nil
    
    init(keyfunction: CustomSampleInfo.KeyFunction) {
        self.keyfunction = keyfunction
        _viewModel = StateObject(wrappedValue: CustomSampleSubViewModel(with: keyfunction))
    }
    
    var body: some View {
        List {
            ForEach(keyfunction.viewItems, id: \.viewFullPath) { viewItem in
                Button(action: {
                    Task {
                        await viewModel.loadEnvironment(for: viewItem)
                        self.destinationView = AnyView(
                            CustomSampleManager.viewForName(viewItem)
                                .environmentObject(viewModel)
                        )
                        
                        self.isActive = true
                    }
                }) {
                    CustomCell(viewItem: viewItem)
                }
                .sheet(isPresented: $isActive, content: {
                    return destinationView
                })
//                .background(
//                    NavigationLink(
//                        destination: destinationView,
//                        isActive: $isActive,
//                        label: { EmptyView() }
//                    )
//                    .hidden()
//                )
            }
        }
        .navigationTitle(keyfunction.name)
    }
}

Hope this helps. Let me know if you want to setup a call and discuss it further.

Hi @GetChivy
I have done a lot of internal testing and fixed the issues, including the one you commented on at the end.
I will be releasing a new version within the next week or so.
Thanks for the feedback!

@GetChivy The fixed version has been released. please use 1.0.0-beta.2 version.