The following code demonstrates erratic positioning of the text input field in the Chat UI in a simple SwiftUI project. Textfield jumps to near top of view on first tap when keyboard is presented. Other gestures can cause the textfield to reposition to just atop the keyboard as expected, but repositions to near top of view with next presentation of keyboard. This is seen on simulator and device, iOS 14, 15+.
My guess is that the iOS system is automatically adding padding under the textfield when the keyboard is presented and the SDK is also adding the padding manually.
Create a SwiftUI Xcode project and add SPM package dependencies:
- ZendeskChatSDK 2.0.0 - Next Major
- ZendeskSupportSDK 5.0.0 - Next Major
Replace the ContentView.swift code with the following:
import ChatSDK
import ChatProvidersSDK
import CommonUISDK
import MessagingSDK
import SwiftUI
import ZendeskCoreSDK
struct ContentView: View {
@State var showSupportChat: Bool = false
var body: some View {
VStack {
HStack {
Spacer()
Button(action: {
showSupportChat = true
}, label: {
Image(systemName: "questionmark.circle")
.resizable()
.frame(width: 24, height: 24)
})
.padding(.trailing)
}
.padding(.top, 16)
Spacer()
Text("Main Page").font(.largeTitle)
Spacer()
}
// same result with both following presentation methods
.sheet(isPresented: $showSupportChat, onDismiss: {
// .fullScreenCover(isPresented: $showSupportChat, onDismiss: {
showSupportChat = false
}, content: {
MessagingView()
.accentColor(.white)
})
.accentColor(.red)
}
}
struct MessagingView: UIViewControllerRepresentable {
@Environment(\.presentationMode) var presentationMode
func makeUIViewController(context: Context) -> UIViewController {
Zendesk.initialize(
appId: "APP_ID",
clientId: "MOBILE_SDK_CLIENT",
zendeskUrl: "https://my-app-id.zendesk.com"
)
let visitorInfo = VisitorInfo(
name: "Anon E. Moose",
email: "moose.on.loose@somewhere.com",
phoneNumber: "+1(555)555-1212"
)
Zendesk.instance?.setIdentity(
Identity.createAnonymous(
name: visitorInfo.name,
email: visitorInfo.email
)
)
Chat.initialize(accountKey: "CHAT_ACCOUNT_KEY")
let chatConfig = self.chatAPIConfig(
info: visitorInfo,
tags: ["app_name", "en", "US"])
Chat.instance?.configuration = chatConfig
CommonTheme.currentTheme.primaryColor = .red
var chatVC = UIViewController()
do {
let chatEngine = try ChatEngine.engine()
chatVC = try Messaging.instance.buildUI(
engines: [chatEngine],
configs: [self.messagingConfig(), self.chatConfig()]
)
}
catch {
print("Error creating Chat view controller: \(error)")
}
let button = UIBarButtonItem(image: nil, style: .plain, target: nil, action: nil)
button.primaryAction = UIAction(
image: UIImage(systemName: "xmark.circle")
) {_ in
presentationMode.wrappedValue.dismiss()
}
chatVC.navigationItem.leftBarButtonItem = button
// CommonTheme.currentTheme.primaryColor = .red does not affect Navbar color
// as per documentation (link above). Let's try and force it.
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = .red
let attrs: [NSAttributedString.Key: Any] = [.foregroundColor: UIColor.white]
appearance.titleTextAttributes = attrs
appearance.largeTitleTextAttributes = attrs
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
chatVC.navigationController?.navigationBar.standardAppearance = appearance
chatVC.navigationController?.navigationBar.scrollEdgeAppearance = appearance
return UINavigationController(rootViewController: chatVC)
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
//...
}
func chatAPIConfig(info: VisitorInfo, tags: [String]) -> ChatAPIConfiguration {
let chatAPIConfig = ChatAPIConfiguration()
chatAPIConfig.tags = tags
chatAPIConfig.visitorInfo = info
return chatAPIConfig
}
func messagingConfig() -> MessagingConfiguration {
let messagingConfig = MessagingConfiguration()
messagingConfig.name = "My App"
return messagingConfig
}
func chatConfig() -> ChatConfiguration {
let chatConfig = ChatConfiguration()
let formConfig = ChatFormConfiguration(
name: .required,
email: .optional,
phoneNumber: .hidden,
department: .hidden
)
chatConfig.preChatFormConfiguration = formConfig
chatConfig.isPreChatFormEnabled = true
chatConfig.isOfflineFormEnabled = true
chatConfig.isChatTranscriptPromptEnabled = false
chatConfig.isAgentAvailabilityEnabled = true
chatConfig.chatMenuActions = [.endChat]
return chatConfig
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}