还是可恶的网易七鱼SDK
接上篇
当我要 present
一个SDK
的viewController
时, 就是前面提到的QYSessionViewController
, 不知道怎么搞的, 这个viewController
会默认弹出键盘, 这就很影响用户体验了, 本来你是隐式地弹出这个viewController
, 让用户无法察觉, 然后在这个被拉起的viewController
中成功地创建会话, 然后隐式地发出消息. 键盘突然闪一下算怎么回事呢?
所以我的思路是:
最开始的时候, 我觉得应该是在键盘即将弹出的时候, 隐藏键盘. 发现不行
然后我的思路是, 在键盘的frame
即将发生变化的时候, 隐藏键盘, 发现还是不行, 键盘依然弹出
最后发现, 必须在textDidBeginEditingNotification
的时候去隐藏键盘, 才可以
最后发现, 其调用顺序是:
UITextView.textDidBeginEditingNotification
-> UITextView.keyboardWillChangeFrameNotification
-> UITextView.keyboardWillShowNotification
NotificationCenter.default.also { it in
it.addObserver(self, selector: #selector(hideKeyboard(noti:)), name: UITextView.textDidBeginEditingNotification, object: nil)
}
NotificationCenter.default.also { it in
it.addObserver(self, selector: #selector(hideKeyboard(noti:)), name: UITextView.keyboardWillChangeFrameNotification, object: nil)
}
NotificationCenter.default.also { it in
it.addObserver(self, selector: #selector(hideKeyboard(noti:)), name: UITextView.keyboardWillShowNotification, object: nil)
}
也就是说, 要在发出UITextView.textDidBeginEditingNotification
这个通知之后隐藏键盘才是最及时的, 这个时候, 隐藏键盘是不会弹出键盘的, 其余两个, 及时写了隐藏键盘的代码, 键盘也还是会弹出, 让用户感知到
因为我用的是第三方, 所以我隐藏键盘的代码是:
IQKeyboardManager.shared().resignFirstResponder()
另一个需要注意的问题是, 通知监听和取消监听的时机, 因为最开始的时候, 我是在viewDidLoad
监听和viewDidDisappear
取消监听的, 这就会造成一个问题, 因为我这个viewController
是一个webView
的容器, 所以大部分的跳转都其实是H5
的跳转, 所以这样一来, 并没有起到相应的想过, 相反, 在很多不需要隐藏键盘的H5
界面, 键盘都隐藏了, 因为它们的容器是监听了通知, 当收到UITextView.textDidBeginEditingNotification
这个通知之后隐藏键盘. 所以我把监听的通知放在了调用方法之中.
/// 发送客服自定义消息
func sendCustomMessage(dict: Dictionary<String, Any?>) {
NotificationCenter.default.also { it in
it.addObserver(self, selector: #selector(hideKeyboard(noti:)), name: UITextView.textDidBeginEditingNotification, object: nil)
}
if let productDict = dict["productDetail"] as? Dictionary<String, Any>,
let product = JSONDeserializer<CustomServiceProduct>.deserializeFrom(dict: productDict)
{
let commodityInfo = QYCommodityInfo()
commodityInfo.show = product.show
commodityInfo.cardType = product.cardType
commodityInfo.title = product.title
commodityInfo.desc = product.desc
commodityInfo.note = product.note
commodityInfo.pictureUrlString = product.picture
commodityInfo.urlString = product.url
commodityInfo.actionText = product.actionText
commodityInfo.goodsId = product.goodsId
commodityInfo.goodsCId = product.goodsCId
commodityInfo.orderId = product.orderId
commodityInfo.actionTextColor = UIColor.cp_text()
// TODO: - 这里的逻辑很奇葩, 这个会话是和控制器耦连的, 所以控制器如果没有push或者present出来, 会话是无法真正连接的
// TODO: - 所以思路就是创建会话, 并present出来, 但用户感知不到, 给客服发消息, 然后dissmiss掉会话
// 创建一个与客服的回话
let session = QYSDK.shared().sessionViewController()
// 文档上说要包在nav中使用, 那就勉强包一下吧
// 不知道包含了什么骚操作
// 创建一个空的控制器, 他的view在屏幕之外, 就是不让用户看到
let vc = UIViewController()
vc.view.frame = CGRectMake(0, UIScreen.main.bounds.size.height + 100, 1, 1)
// 然后把这个控制器的view, 添加在当前控制器的view上
view.addSubview(vc.view)
guard let session = session else { return }
let nav = UINavigationController(rootViewController: session)
// 设置模态的类型, 如果按照默认, 会有动画效果, 就会被看出来
nav.modalPresentationStyle = .overCurrentContext
// 空的控制器, 将nav模态出来
vc.present(nav, animated: false) {
// 模态出来之后, 延时1.5秒操作, 这里的时间无法把控, 之前设置过1s, 但是, 仍有可能会话没有连接成功
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 1.5) {
// 延时1.5s后, 会话连接成功(其实也不一定)后, 发送消息给客服
session.sendCommodityInfo(commodityInfo)
// 然后再过0.25秒, 将会话控制器dismiss掉, 全程不让用户感知
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.25) {
session.dismiss(animated: false) {
NotificationCenter.default.also { it in
it.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: nil)
}
}
}
}
}
}else {
}
callback(with: .Success, method: .SendCustomMessage)
}
方法开始时, 监听通知, 当sessionViewController
弹出之后, 成功发送消息, sessionViewController
被dismiss
掉之后, 取消通知. 这样就不会干扰到其他H5
的界面了.
网友评论