笔者性懒,腹中无墨
关于WMPageController,不再赘述.本文旨在简述使用了WMPageController的web页面加入消息提醒等功能,有新消息时以小红点标记,查看之后小红点消失.
简略图:
1.进入控制器首先需要获得所有的webView,控制器继承自WMPageController.如果需要js交互,可以先写一个存放js交互信息的swift文件,方便管理,数据请求也放在这个交互信息的文件里.
WebUrlService.shared.updateUrls { finish in
if finish {
DispatchQueue.main.async {
self.webUrls = WebUrlService.shared.urls
self.reloadData()
}
}
}
其中,WebUrlService即为存放js交互信息的swift文件,updateUrls是数据请求的函数,函数里以将返回的结果保存,通过单利获取这些url数据WebUrlService.shared.urls,给到当前WMPageController的webUrls.
2.通常WMPageController的menuView的各个title是确定的,这个需要与web开发同事沟通好,指定某个或者某几个web页面有消息提醒业务.例如,在众多的菜单title中,有一个"活动"项目,实现需要确定"活动"的位置是否固定,若不固定,那么标题是否固定.假设有一个页面就叫"活动",需要给"活动"加小红点提醒. WMPageController有如下方法:
override func pageController(_ pageController: WMPageController, titleAt index: Int) -> String {
guard let title = webUrls?[index].name else {return "未知"}
if title == "活动" {
redPointIndex = index
}
return title
}
其中webUrls是上一步中获取的所有url信息,redPointIndex是Int型的变量,用于记录"活动"的位置. override - 控制器继承自WMPageController.
3.判断是否有新活动需要提醒
ActivityUrlService.shared.updateActivity { (hasNews) in
if hasNews {
DispatchQueue.main.async {
self.unRead = reload
self.reloadData()
}
}
}
其中,unRead是Bool值的变量,判断是否有未读消息,消息条数若有需要也可以获取.
4.添加小红点,WMPageController有下面方法:
override func menuView(_ menu: WMMenuView!, badgeViewAt index: Int) -> UIView! {
if index == redPointIndex && unRead == true {
let view = UIView(frame: CGRect(x: itemWidths[index]-10, y: 7, width:6, height: 6))
view.layer.cornerRadius = 3
view.layer.masksToBounds = true
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 6, height: 6))
imageView.image = #imageLiteral(resourceName: "btn_red_normal")
view.addSubview(imageView)
return view
}
return nil
}
设置好badgeView的frame,太大会遮挡title.
5.当点击了"活动",将小红点去掉,若跳过"活动",只是任意点击其他的title,则小红点不消失.
override func pageController(_ pageController: WMPageController, didEnter viewController: UIViewController, withInfo info: [AnyHashable : Any]) {
if pageController.selectIndex == Int32(redPointIndex) {
unRead = false
menuView?.updateBadgeView(at: redPointIndex)
}
}
其中, WMPageController的selectIndex属性是Int32,需转换.
6.注意:
以上只是将关键步骤列出, WMPageController的代理方法应根据需要进行处理.
是否显示小红点的判断根据项目的不同而不同,例如:
1) 根据数据请求返回的某个字段.
2)根据请求的时间和消息的发布时间.
3)请求的时间是否要存储,存储在哪里合适.
4)多少分钟之内不再重新请求.
这些均可在类似于上文提到的 ActivityUrlService中做处理.返回Bool值有没有新消息,需不需要刷新menuView即可.
7.举例子,笔者是根据请求与消息的发布时间以及时间间隔判断的,略作参考
// userInfo 存储上一次请求返回的发布时间
let activity_lastReleaseDate_key = "activity_lastReleaseDate_key"
static let shared = ActivityUrlService()
let userDefuaults = UserDefaults.standard
fileprivate var lastRequestDate: Date? //上一次请求的时间
// 闭包返回给控制器
func updateActivity(_ completionHandler: @escaping (Bool) -> Void) {
updateActivityRequest { (finish) in
completionHandler(finish)
}
}
// 数据请求 闭包返回是否有小红点
fileprivate func updateActivityRequest(_ completionHandler: @escaping (Bool) -> Void) {
WebService.request("/api/promotions/latest").validate().responseData { (response) in
guard response.result.isSuccess, let data = response.result.value else {
completionHandler(false)
return
}
guard let dic = JSON(data: data).dictionary else {
completionHandler(false)
return
}
guard let dataDic = dic["data"]?.dictionary else {
completionHandler(false)
return
}
guard let promotion = dataDic["promotion"]?.dictionary else {
completionHandler(false)
return
}
guard let releaseDate = promotion["releaseDate"]?.string else {
completionHandler(false)
return
}
// 判断几个重要的时间
let completion = self.judgeRequestAndRelease(with: releaseDate)
completionHandler(completion)
}
}
/// 比较活动的请求和发布时间
///
/// - Parameter releaseDateStr: 本次请求返回的发布时间
fileprivate func judgeRequestAndRelease(with releaseDateStr: String) -> Bool {
if let last = lastRequestDate {
//有上一次请求的时间
let minute = Date().timeIntervalSince(last)/60
if minute > 10 {
//与当前时间对比,若大于10分钟,则重新请求
lastRequestDate = Date()
guard let value = userDefuaults.object(forKey: activity_lastReleaseDate_key) as? String else {
return false
}
guard let lastReleaseStamp = Int(value) else {
return false
}
// 自己写的一个方法,返回Date
let releasedate = DateConversion.shared.dateStringSwitchToDate(with: releaseDateStr, dateFormate: "yyyy-MM-dd HH:mm:ss")
// 返回时间戳
let releaseStamp = DateConversion.shared.dateSwitchToStamp(with: releasedate)
guard let currentReleaseStamp = Int(releaseStamp) else {
return false
}
if currentReleaseStamp > lastReleaseStamp {
userDefuaults.set(currentReleaseStamp, forKey: activity_lastReleaseDate_key)
return true
} else {
return false
}
}
return false
} else {
// 没有第一次请求的时间,则第一次请求数据
firstRequest(with: releaseDateStr)
return true
}
}
//首次请求
fileprivate func firstRequest(with releaseDateStr: String) {
lastRequestDate = Date() //上一次请求时间当前时间
let releasedate = DateConversion.shared.dateStringSwitchToDate(with: releaseDateStr, dateFormate: "yyyy-MM-dd HH:mm:ss")
let releaseStamp = DateConversion.shared.dateSwitchToStamp(with: releasedate)
userDefuaults.set(releaseStamp, forKey: activity_lastReleaseDate_key)
}