ios-library icon indicating copy to clipboard operation
ios-library copied to clipboard

Navigation bar text color is not updating

Open Abichaljha1993 opened this issue 8 months ago • 4 comments

Hi, Earlier I am using iOS SDK 16.12.0 now I have to update the SDK to 18.14.2. There is a lots of configuration get updated. Now I am not able to update navigation bar background colour or text colour. It says use MessageCenterViewStyle methods. I have implemented custom view style

struct CustomMessageCenterViewStyle: MessageCenterViewStyle { @ViewBuilder func makeBody(configuration: Configuration) -> some View { if #available(iOS 16.0, *) { NavigationStack { configuration.content .navigationViewStyle(.automatic) .navigationBarTitleDisplayMode(.inline) .navigationTitle(Text("Custom Message Center").foregroundColor(.white)) .toolbarBackground(.blue, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar) .toolbarColorScheme(configuration.colorScheme) } } else { NavigationView { configuration.content .navigationTitle(Text("Old Custom Message Center").foregroundColor(.white)) .navigationBarTitleDisplayMode(.large) } .navigationViewStyle(.stack) } } }

and assigned this style like this MessageCenterView() .messageCenterViewStyle( CustomMessageCenterViewStyle() )

But I didn't see any navigation colour get changes. Please help me if I am doing some mistake.

Thank You! Abichal

Abichaljha1993 avatar Apr 02 '25 11:04 Abichaljha1993

@Abichaljha1993 I'm able to get our example to work without any issues:

struct CustomMessageCenterViewStyle: MessageCenterViewStyle {
    @ViewBuilder
    func makeBody(configuration: Configuration) -> some View {
        if #available(iOS 16.0, *) {
            NavigationStack {
                configuration.content
                    .navigationBarTitleDisplayMode(.inline)
                    .navigationTitle(Text("Custom Message Center"))
                    .toolbarBackground(.mint, for: .navigationBar)
                    .toolbarBackground(.visible, for: .navigationBar)
                    .toolbarColorScheme(configuration.colorScheme)
            }
        } else {
            NavigationView {
                configuration.content
                    .navigationTitle(Text("Old Custom Message Center"))
                    .navigationBarTitleDisplayMode(.large)
            }
            .navigationViewStyle(.stack)
        }
    }
}
MessageCenterView()
    .messageCenterViewStyle(
        CustomMessageCenterViewStyle()
    )

Image

Is it possible you are testing on <iOS 15 or overriding the navigation bar appearance globally somewhere in your code? Does your navigation title say "Old Custom Message Center"?

crow avatar Apr 03 '25 20:04 crow

Hi David, My application is written in Swift UIKit and previously I am using SDK 14 now we are facing some UI issue on OS 18 content is going inside the navigation bar. Now I am trying to update it to SDK 18. Here I am not able to see "Old Custom Message Center" or new It display "Message Center" if I am not providing any text to theme. Let me share you my existing code so that you can correct me where I am doing any mistake.

`class UrbanAirshipManager: NSObject {

private override init() {}
/// shared instance of  urbanAirShip
static let sharedInstance = UrbanAirshipManager()

static var returnUnreadCount: (() -> Void)?

func isPushNotificationEnabled(completionHandler: @escaping (Bool) -> Void) {
    UNUserNotificationCenter.current().getNotificationSettings { settings in
        DispatchQueue.main.async {
            if settings.authorizationStatus == .authorized || settings.authorizationStatus == .provisional {
                completionHandler(true && UIApplication.shared.isRegisteredForRemoteNotifications)
            } else {
                completionHandler(false)
            }
        }
    }
}

/// configure airship for application.
@MainActor func configureAirship(isEnable: Bool?) {
    
    let config = AirshipConfig.config()
    if ServiceConstant.BaseURLConstant.productionBaseUrl == PRODUCTION {
       // configuration with key
    } else {
           // configuration with key
    }
    config.inProduction = true
    config.detectProvisioningMode = true
    config.messageCenterStyleConfig = "UAMessageCenterDefaultStyle"
    config.urlAllowList = ["*"]
    // Call takeOff (which creates the UAirship singleton)
    Airship.takeOff(config, launchOptions: nil)
    Airship.privacyManager.enabledFeatures = [.push, .tagsAndAttributes, .messageCenter, .analytics]
    Airship.deepLinkDelegate = self
    Airship.push.userPushNotificationsEnabled = isEnable ?? self.isNotificationEnabled()
    Airship.push.defaultPresentationOptions = [.sound]
    Airship.privacyManager.enableFeatures(AirshipFeature.contacts)
    Airship.push.pushNotificationDelegate = self
    Airship.push.backgroundPushNotificationsEnabled = true
    configureMessageCenter()
    MessageCenter.shared.predicate = CustomPredicate()
    AppSyncHelper.syncLippChannel(withoutTimestamp: true)
}
/// is notification enabled
func isNotificationEnabled() -> Bool {
    return Airship.push.userPushNotificationsEnabled
}

/// change notificarion setting
/// - Parameter isEnabled: isEnabled description
func setPushNotification(isEnabled: Bool) {
    Airship.push.userPushNotificationsEnabled = isEnabled
}

/// configure and open messgae center
func openMessageCenter() {
    DispatchQueue.main.async {
        MessageCenter.shared.display()
        AnalyticsManager.shared.logEvent(event: .screenMessageCenter)
        AnalyticsManager.shared.logScreenViewEvent(event: .screenMessageCenter, className: String(describing: type(of: self)))
    }
}

func dismissMessageCenter(isFromBanner: Bool = false) {
    DispatchQueue.main.async {
        let keyWindow = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
        guard let topController = keyWindow?.rootViewController else { return }
        if (topController.presentedViewController as? RegistrationReminderController) != nil {
            regReminderController: while let reminderController = topController.presentedViewController as? RegistrationReminderController {
                reminderController.dismiss(animated: false)
                break regReminderController
            }
            if isFromBanner {
                MessageCenter.shared.dismiss()
            }
        } else {
            MessageCenter.shared.dismiss()
        }
    }
}

func countOfUnreadMessage() async -> Int {
        await MessageCenter.shared.inbox.refreshMessages()
    return await MessageCenter.shared.inbox.messages.filter({$0.extra["conferenceCode"] == defaultConfCode}).count
    }

/// style message center
@MainActor func configureMessageCenter() {
    var theme = MessageCenterTheme()
    theme.navigationBarTitle = "notifications".getLocalizedString()
    theme.messageListContainerBackgroundColor = Color(currentTheme.marine)
    theme.messageViewContainerBackgroundColor = Color(currentTheme.marine)
    theme.cellTitleColor = Color(currentTheme.marine)
    theme.cellTitleFont =  Font(currentTheme.getCustomSizeSemiBoldFont(16))
    theme.cellDateFont =  Font(currentTheme.bodytextSize13Regular)
    theme.cellDateColor = Color(currentTheme.marine)
    theme.editButtonTitleColor = .white
    theme.backButtonColor = .white
    theme.deleteButtonTitleColor = .white
    theme.unreadIndicatorColor = Color(currentTheme.lipstick)
    // Set the theme on the default Message Center
    MessageCenter.shared.theme = theme

/// This line of code not executing properly. MessageCenterView() .messageCenterViewStyle( CustomMessageCenterViewStyle() ) }

/// get channel identifier
func getChannelIdentifier() -> String {
    return Airship.channel.identifier ?? ""
}

/// Check Airship is configure or not
func isAirshipConfigure() -> Bool {
    return Airship.isFlying
}
/// Un-register the application from airship to receive push.
func dereigsterFromAirship() {
    Airship.push.userPushNotificationsEnabled = false
}

}

extension UrbanAirshipManager: DeepLinkDelegate { func receivedDeepLink(_ url: URL, completionHandler: @escaping () -> Void) { DispatchQueue.main.async { [weak self] in deeplinker.handleDeeplink(url: url) self?.dismissMessageCenter() } } func receivedDeepLink(_ deepLink: URL) async { DispatchQueue.main.async { [weak self] in deeplinker.handleDeeplink(url: deepLink) self?.dismissMessageCenter() } } }

class CustomPredicate: MessageCenterPredicate { func evaluate(message: MessageCenterMessage) -> Bool { // return message.extra["conferenceCode"] == defaultConfCode return true } }

struct CustomMessageCenterViewStyle: MessageCenterViewStyle { @ViewBuilder func makeBody(configuration: Configuration) -> some View { if #available(iOS 16.0, *) { NavigationStack { configuration.content .navigationViewStyle(.automatic) .navigationBarTitleDisplayMode(.inline) .navigationTitle(Text("Custom Message Center").foregroundColor(.white)) .toolbarBackground(.blue, for: .navigationBar) .toolbarBackground(.visible, for: .navigationBar) .toolbarColorScheme(configuration.colorScheme) } } else { NavigationView { configuration.content .navigationTitle(Text("Old Custom Message Center").foregroundColor(.white)) .navigationBarTitleDisplayMode(.large) } .navigationViewStyle(.stack) } } }`

Abichaljha1993 avatar Apr 04 '25 04:04 Abichaljha1993

The line of code you commented on Is creating the SwiftUI MessageCenterView then doing nothing with it:

/// This line of code not executing properly.
MessageCenterView()
.messageCenterViewStyle(
CustomMessageCenterViewStyle()
)

You need to display the view itself.

For example - take a look at how the Sample app displays the MessageCenterView in its parent view AppView:

/* Copyright Urban Airship and Contributors */

import AirshipCore
import AirshipMessageCenter
import AirshipPreferenceCenter
import AirshipDebug
import SwiftUI

struct AppView: View {
    @EnvironmentObject var appState: AppState

    @State var shakeCount: Int = 0

    var body: some View {
        TabView(selection: $appState.selectedTab) {

            HomeView()
                .tabItem {
                    Label(
                        "Home",
                        systemImage: "house.fill"
                    )
                }
                .onAppear {
                    Airship.analytics.trackScreen("home")
                }
                .tag(SampleTabs.home)

            MessageCenterView()
            .messageCenterViewStyle(
                  CustomMessageCenterViewStyle()
             )
            .tabItem {
                Label(
                    "Message Center",
                    systemImage: "tray.fill"
                )
            }
            .badge(self.appState.unreadCount)
            .onAppear {
                Airship.analytics.trackScreen("message_center")
            }
            .tag(SampleTabs.messageCenter)


            PreferenceCenterView(
                preferenceCenterID: MainApp.preferenceCenterID
            )

            .navigationViewStyle(.stack)
            .tabItem {
                Label(
                    "Preferences",
                    systemImage: "person.fill"
                )
            }
            .onAppear {
                Airship.analytics.trackScreen("preference_center")
            }
            .tag(SampleTabs.preferenceCenter)


#if canImport(AirshipDebug)
           debug.tabItem {
               Label(
                   "Debug",
                   systemImage: "gear"
               )
           }
           .onAppear {
               Airship.analytics.trackScreen("debug")
           }
           .tag(SampleTabs.debug)
#endif
        }
        .onShake {
            shakeCount += 1

            let event = CustomEvent(name: "shake_event", value: Double(shakeCount))
            event.track()

            AppState.shared.toastMessage = Toast.Message(
                text: "Tracked custom event: shake_event",
                duration: 2.0
            )
        }
        .overlay(makeToastView())
    }

    @ViewBuilder
    private func makeToastView() -> some View {
        Toast(message: self.$appState.toastMessage)
            .padding()
    }

#if canImport(AirshipDebug)
    @ViewBuilder
    var debug: some View {
        if #available(iOS 16.0, *) {
            NavigationStack {
                ZStack{
                    AirshipDebugView()
                }
            }
        } else {
            NavigationView {
                AirshipDebugView()
            }
            .navigationViewStyle(.stack)
        }
    }
#endif
}


struct AppView_Previews: PreviewProvider {
    static var previews: some View {
        AppView()
    }
}

crow avatar Apr 06 '25 19:04 crow

This is swift UI. But my application is in UIKIT. How can I achieve this is UIKit? SDK didn't expose navigation to customise, like message container view background colour detail view cell colour etc. are expose so we can customise it using UIKit applocation.

Abichaljha1993 avatar Apr 14 '25 06:04 Abichaljha1993

SwiftUI views can be used inside UIKit with UIHostingViewControllers. That way you can customize it however you like in SwiftUI using the style overrides we discussed while still retaining the ability to embed the view in a UIKit app. Here's a quick example of creating a UIKit-compatible message center called MyMessageCenterView that's customized:

class MyMessageCenterView: UIViewController {
    override func viewDidLoad() {
        super.viewidLoad()

        let swiftUIView = MessageCenterView()
                                           .messageCenterViewStyle( CustomMessageCenterViewStyle() ) /// Customize here

        let host = UIHostingController(rootView: swiftUIView)
        addChild(host)
        host.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(host.view)

        NSLayoutConstraint.activate([
            host.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
            host.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
            host.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor),
            host.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
        ])

        host.didMove(toParent: self)
    }
}

struct CustomMessageCenterViewStyle: MessageCenterViewStyle {
    @ViewBuilder
    func makeBody(configuration: Configuration) -> some View {
        if #available(iOS 16.0, *) {
            NavigationStack {
                configuration.content
                    .navigationBarTitleDisplayMode(.inline)
                    .navigationTitle(Text("Custom Message Center"))
                    .toolbarBackground(.mint, for: .navigationBar)
                    .toolbarBackground(.visible, for: .navigationBar)
                    .toolbarColorScheme(configuration.colorScheme)
            }
        } else {
            NavigationView {
                configuration.content
                    .navigationTitle(Text("Old Custom Message Center"))
                    .navigationBarTitleDisplayMode(.large)
            }
            .navigationViewStyle(.stack)
        }
    }
}

crow avatar May 09 '25 16:05 crow