Skip to content

4.4.0

Compare
Choose a tag to compare
@MoLice MoLice released this 29 Nov 11:45
· 33 commits to master since this release
1230a57

综述

4.4.0 版本主要内容是适配 iOS 15,同时废弃对 iOS 10 的支持。

iOS 15 对开发者而言最大的 UI 改动就是三种系统 bar(UINavigationBar、UITabBar、UIToolbar)默认样式都分为两个状态:滚动前、滚动后。只要你用 Xcode 13 打包,什么都不改的情况下就会出现这两种状态差异,而大部分 App 的预期应该是维持 iOS 14 相同的表现——因为 iOS 15 的这个特性只能在 iOS 15 上生效,系统无法向后兼容,这意味着如果你要保持系统这个特性,你就需要额外为自己的 App 在 iOS 15 上重新设计一套 bar 的外观。因此 QMUI 的兼容思路也是如此:在配置表提供若干开关,尽量减少业务项目达到“维持 App 外观不变”所需要付出的工作量。如果你的适配思路与此相悖,那么本次更新的内容可能对你作用不大,请降低预期。

另,如果你希望全 iOS 版本均能实现 iOS 15 这种滚动效果,建议使用 QMUINavigationBarScrollingAnimator,它比系统功能更丰富,可以精准控制滚动过程中每一个时机的样式,可以联动除了 navigationBar、statusBar 之外的其他任何事情,而系统的仅仅只能定义起始和结束两个状态的 navigationBar 的属性,也无法监听当前的状态变化,局限性还是比较大的。以下是 QMUI Demo 中 QMUINavigationBarScrollingAnimator 功能的演示视频。

QMUINavigationBarScrollingAnimator.mov

新增功能

  1. 配置表增加开关 NavBarUsesStandardAppearanceOnly,当业务项目打开的时候,会保持 UINavigationBar.scrollEdgeAppearanceUINavigationBar.standardAppearance 对齐,从而实现 iOS 15 上的导航栏在滚动前后样式一致。
  2. 配置表增加开关 NavBarRemoveBackgroundEffectAutomatically,当业务项目打开的时候,会让 UINavigationBar 在设置了 backgroundImagebarTintColor 时自动隐藏磨砂,在 backgroundImagebarTintColornil 时自动显示磨砂(也即维持 iOS 14 的默认行为)。因为 iOS 15 及以后,backgroundEffect 可以和 backgroundImagebarTintColor 同时存在了,这与之前业务项目的代码逻辑的预期是不匹配的,要么你用这个开关来回到 iOS 14 的表现,要么你自己为 iOS 15 增加适配逻辑。
  3. 配置表增加开关 TabBarUsesStandardAppearanceOnlyTabBarRemoveBackgroundEffectAutomaticallyToolBarUsesStandardAppearanceOnlyToolBarRemoveBackgroundEffectAutomatically,具体含义请参考上面的 NavBar,这里不再赘述。
  4. 配置表增加开关 TableViewSectionHeaderTopPaddingTableViewGroupedSectionHeaderTopPaddingTableViewInsetGroupedSectionHeaderTopPadding,分别设置三种 style 的 QMUITableView 在 iOS 15 上的 sectionHeaderTopPadding 默认值,默认不修改的话,UITableViewStylePlain 会在每个 sectionHeader 之前多出来23pt的空白,另外两种 style 的列表与 iOS 14 一致。
  5. QMUICommonDefines.h 增加宏 IOS15_SDK_ALLOWED 用于区分当前是否是 Xcode 13 编译。
  6. QMUIAnimationHelper 增加接口 bounceFromValue:toValue:time:coeff: 用于实现系统 UIScrollView 拖到尽头那种阻尼感的体验。
  7. QMUILabel 增加属性 truncatingTailView 用于在文字缩略时可以显示一个自定义的 View,具体可查看 QMUI Demo 的效果。
  8. QMUIModalPresentationViewController 增加属性 window 允许业务获取到 modal 内部正在使用的 UIWindow 对象。
  9. QMUIModalPresentationViewController 增加属性 shouldDimmedAppAutomatically 用于控制当前 modal 显示时是否需要把背后的 App 界面置灰(类似系统的 UIAlertController 显示时的效果)。
  10. QMUIPopupContainerView 增加属性 contentViewSizeThatFitsBlock 方便业务在外部控制 popup 内容的大小,而不一定非要继承一个子类。
  11. QMUIPopupContainerView 增加属性 backgroundView 支持用一个自定义的 View(例如磨砂)作为 popup 的背景,当使用了这个属性后,arrowImage 只会作为遮罩来使用,不会显示 arrowImage 图片内部的纹理(也即只用箭头的造型,不用它的内容)。
  12. QMUIPopupContainerView 优化属性 arrowImage 的实现,允许你将一张 UIImageRenderingModeAlwaysTemplate 的图片作为箭头图片,当你这么做时,图片的颜色会自动跟随 backgroundColor 走,从而避免以前设置了自定义箭头图片后再修改 backgroundColor,会看到箭头颜色与背景色不一致的问题。
  13. #1295 QMUITextField 增加与 QMUITextView 相同的 canPerformPasteActionBlockpasteBlock 接口以支持控制粘贴事件(例如你可以在粘贴文本时把文本变成一张图放在输入框里)。
  14. +[QMUIHelper deviceModel] 增加 iPhone 13、iPad 新设备的信息。
  15. 增加协议 QMUIStringProtocol,将原本 NSString(QMUI) 支持的功能也迁移到 NSAttributedString(QMUI) 内。
  16. 增加 UIBlurEffect(QMUI) 分类,提供 qmui_effectWithBlurRadius: 支持指定明确的模糊半径,提供 qmui_style 支持获取当前 blur 对象的 style 值。同时 QMUI Demo 内增加 UIBlurEffect(QMUI) 的 Demo 展示。
  17. UITableView(QMUI_InsetGrouped) 支持在 iOS 12 及以下的 Interface Builder 里设置 tableView 为 InsetGrouped
  18. #1290 @xixisplit - [UIImage(QMUI) qmui_imageWithGradientColors:] 增加 QMUIImageGradientTypeTopLeftToBottomRightQMUIImageGradientTypeTopRightToBottomLeft 类型。

会带来 QMUI 新旧版本兼容问题的更新

  1. 为了适配 iOS 15,UINavigationBarUIToolbar 从这个版本开始,改为用 iOS 13 就提供的新系统接口 UINavigationBarAppearanceUIToolbarAppearance 来设置样式(UITabBar 的在 QMUI 4.0.0 适配 iOS 13 时就已经换成新接口了),新旧接口是互斥的,一旦项目里某个地方用了新接口,整个项目的旧接口都会失效。但为了尽量减少业务项目更新 QMUI 版本的工作量,我们在 UINavigationBar(QMUI)UIToolbar(QMUI) 内对旧接口做了映射,统一转换为新接口,因此预期业务项目更新版本后应该不会出现 UINavigationBarUIToolbar 的样式差异问题。
  2. 由于最低版本从 iOS 10 升级到 iOS 11,因此去掉了 QMUI 内所有为 iOS 10 写的代码,并且以前为了兼容 iOS 11 才有的 API 而加的接口(例如 qmui_safeAreaInsets)也没必要了。
  3. 由于 #1325 的问题,再考虑到该功能原本的实现代码有些混乱,因此这个版本重构了 AutomaticCustomNavigationBarTransitionStyle 的实现,减少了对 QMUINavigationControllerAppearanceDelegate 系列接口多次不必要的调用,并且更稳定。
  4. 由于现如今 QMUIButton 的功能已足够灵活,相比之下基于它衍生的 QMUIFillButtonQMUIGhostButton 显得有点鸡肋,且预设的 enum 难以准确满足业务项目的配色需求,因此这个版本我们将 QMUIFillButtonQMUIGhostButton 删除,建议原本在用的项目将其改为 QMUIButton,或者你也可以复制这两个类的文件放在业务项目里继续使用。
  5. 4.3.0 里标记为废弃的 QMUILinkButton 在 4.4.0 里正式删除。
  6. 更换 QMUITheme 在 iOS 13 及以后的系统里监听系统 userInterfaceStyle 变化的方式,从而达到:
    1. 避免之前监听 -[UIWindow traitCollection] 会导致每次有任何界面操作(触摸、按下键盘快捷键、Dark Mode 切换)时都会触发这段逻辑,而我们仅仅只希望利用它来监听 Dark Mode 切换而已。
    2. #1087 #1318 避免之前 hook -[UIWindow traitCollection] 导致在 Xcode 唤醒的场景里 App 第一次升起键盘会触发 Main Thread Checker 的问题。
    3. 旧的实现方案在系统 userInterfaceStyle 发生变化,到 QMUITheme 成功切换之间的耗时较长,在此期间访问 QMUIThemeManager.currentTheme 得到的值必定都是错误的(例如这过程中就会触发 UIViewController preferredStatusBarStyle,而业务项目在该方法里获取当前 QMUIThemeManager.currentTheme 的操作还是比较常见的)问题。
  7. 去掉 QMUIThemePrivate 里重写 -[UIView setBackgroundColor:]-[UITableViewCell setBackgroundColor:] 的代码,实测 iOS 11-15 均不需要这种处理了,而这段代码会导致 QMUIThemeColor 无法搭配 UIViewPropertyAnimator 使用。
  8. 去掉 QMUIThemePrivate 里重写 -[UITextField setNeedsDisplay] 的代码,实测不需要。
  9. QMUIHelper 重命名 is61InchScreenAndiPhone12is61InchScreenAndiPhone12Later,重命名 screenSizeFor61InchAndiPhone12screenSizeFor61InchAndiPhone12Later
  10. QMUIHelper.safeAreaInsetsForDeviceWithNotch 对全面屏 iPad 返回的 top 值从 0 改为 24。
  11. QMUIHelper.resetDimmedApplicationWindow 的实现里,把 Normal 改为系统默认的 Automatic(免测)。
  12. 配置表开关 NavBarButtonFontBold 在 iOS 15 里对系统的 Done 类型的 UIBarButtonItem 也能生效,iOS 14 及以前只能对 QMUINavigationButtonTypeBold 才生效。
  13. 删除配置表开关 StatusbarStyleLightInitially,新增配置表开关 DefaultStatusBarStyle,新开关的类型为 UIStatusBarStyle,可以支持精准的状态栏样式控制,从而避免类似 #1311 的问题。

如何适配新版

  1. 全局搜索“QMUIFillButton”、“QMUIGhostButton”,将用到的地方换成 QMUIButton,如果较多,建议在项目里创建工具方法(可以参考 QMUI Demo 里的 +[QDUIHelper generateGhostButtonWithColor:]。或者也可以将这两个被删除的文件移到业务项目中继续使用。
  2. 全局搜索“QMUILinkButton”,将用到的地方改为 QMUIButton + UIView.qmui_borderPosition 代替。例如:
    // QMUILinkButton *linkButton = QMUILinkButton.new;
    QMUIButton *linkButton = QMUIButton.new;
    linkButton.qmui_borderPosition = QMUIViewBorderPositionBottom;
    linkButton.qmui_borderColor = linkButton.currentTitleColor;
    linkButton.qmui_borderWidth = 1;// QMUILinkButton 之前默认的下划线大小为1pt
  3. 全局搜索”qmui_safeAreaInsets“,将其替换为系统的 safeAreaInsets,前者依然能用但已被标记为废弃,下个版本会删除。
  4. 全局搜索”qmui_contentInset“,将其替换为系统的 adjustedContentInset,前者依然能用但已被标记为废弃,下个版本会删除。
  5. 全局搜索”qmui_maskedCorners“,将其替换为系统的 maskedCorners,前者依然能用但已被标记为废弃,下个版本会删除。
  6. 全局搜索”qmui_performBatchUpdates“,将其替换为系统的 performBatchUpdates
  7. 全局搜索 “is61InchScreenAndiPhone12”,将其重命名为 “is61InchScreenAndiPhone12Later”。
  8. 全局搜索 “screenSizeFor61InchAndiPhone12”,将其重命名为“screenSizeFor61InchAndiPhone12Later”。
  9. 检查用到 QMUIHelper.safeAreaInsetsForDeviceWithNotch 的地方在 iPad 上是否正常。
  10. 检查用到 AutomaticCustomNavigationBarTransitionStyle 效果的地方是否正常。
  11. 检查将 QMUIThemeColor 作为 UIView.backgroundColorUITableViewCell.backgroundColor 的地方,theme 切换时是否正常。
  12. 检查 theme 切换时 UITextField 的文字颜色是否正常。
  13. 如果项目有使用 QMUITheme,请检查 App 的 Dark Mode 功能是否正常,特别留意 App 在后台、有键盘升起的时候。另外请检查项目里是否有使用 UITraitCollection.currentTraitCollection.userInterfaceStyle 来判断当前 App 样式的写法,有的话,请去掉并改为用 QMUIThemeManagerCenter.defaultThemeManager.currentThemeIdentifier,因为前者这个系统的方法在 Dark Mode 切换过程中可能会得到错误的值。

如果有使用配置表

  1. 请删除包含”fillButton“、”ghostButton“字样的10个开关。
  2. #pragma mark - NavigationBar 分段里添加以下开关,并将其设置为项目所需的值。请保证语句的顺序在其他 navBar 开关之前。
    if (@available(iOS 15.0, *)) {
        QMUICMI.navBarUsesStandardAppearanceOnly = NO;
        QMUICMI.navBarRemoveBackgroundEffectAutomatically = NO;
    }
  3. #pragma mark - TabBar 分段里添加以下开关,并将其设置为项目所需的值。请保证语句的顺序在其他 tabBar 开关之前。
    if (@available(iOS 15.0, *)) {
        QMUICMI.tabBarUsesStandardAppearanceOnly = NO;
        QMUICMI.tabBarRemoveBackgroundEffectAutomatically = NO;
    }
  4. #pragma mark - Toolbar 分段里添加以下开关,并将其设置为项目所需的值。请保证语句的顺序在其他 toolBar 开关之前。
    if (@available(iOS 15.0, *)) {
        QMUICMI.toolBarUsesStandardAppearanceOnly = NO;
        QMUICMI.toolBarRemoveBackgroundEffectAutomatically = NO;
    }
  5. 将下方代码添加到配置表里的适当位置,并将其设置为项目所需的值。
    if (@available(iOS 15, *)) {
        QMUICMI.tableViewSectionHeaderTopPadding = UITableViewAutomaticDimension;
        QMUICMI.tableViewGroupedSectionHeaderTopPadding = UITableViewAutomaticDimension;
        QMUICMI.tableViewInsetGroupedSectionHeaderTopPadding = UITableViewAutomaticDimension;
    }
  6. 请检查项目里用到的 Done 类型的 UIBarButtonItem,字体样式是否符合预期。
  7. 将下方代码添加到配置表里,并将其设置为项目所需的值。同时全局搜索”StatusbarStyleLightInitially“字样,将用到的地方换成新的”DefaultStatusBarStyle“。
    QMUICMI.defaultStatusBarStyle = UIStatusBarStyleDefault; // DefaultStatusBarStyle : 默认的状态栏样式,默认值为 UIStatusBarStyleDefault,也即在 iOS 12 及以前是黑色文字,iOS 13 及以后会自动根据当前 App 是否处于 Dark Mode 切换颜色。如果你希望固定为白色,请设置为 UIStatusBarStyleLightContent,固定黑色则设置为 QMUIStatusBarStyleDarkContent。

Bugfix

  1. #1276 修复 QMUITextView 重写错 init 方法,导致 initWithFrame:textContainer: 无法应用初始值的 bug。
  2. #1308 #1316 修复在输入框内长按移动光标时会错误触发 UIGestureRecognizer(QMUI) assert 的问题。
  3. #1312 修复启动时试图通过 qmui_getProjectClassList 获取项目里所有业务 Class 失败的 bug。
  4. #1320 修复 - [QMUITableViewCell initForTableView:xxx] 方法的实现不恰当,可能引起 Swift 内重复调用 init 的问题。
  5. #1322 @ACFancy 修复 QMUITextFieldQMUITextView 在进行”重做“操作时依然可能引发 #1168 里描述的问题的 bug。
  6. 修复 QMUIPopupMenuViewitemTitleFontitemTitleColorpadding 的值发生变化时没有刷新 item 样式的 bug。
  7. 修复 UITextField 的文字颜色无法响应 QMUITheme 切换的 bug(包含聚焦和非聚焦状态都有问题)。
  8. 修复对一个 QMUIThemeImage 调用 qmui_imageWithTintColor: 时如果参数是个 QMUIThemeColor,则最终这个图片无效的 bug。
  9. 修复使用 UILabel(QMUI).qmui_textAttributes 的时候,先设置 textAlignment 再设置 texttextAlignment 不生效的 bug。
  10. 修复在 iOS 13 及以上的系统里,当业务在 willDisplayCell 里修改 cell.backgroundColor 时会导致 UITableView(QMUI).qmui_insetGroupedCornerRadius 无效的 bug。

QMUI Demo

  1. 增加 QMUIKit→UIBlurEffect(QMUI) 的 Demo。
  2. 增加 Lab→Animation→Animation Curves 用于将动画曲线以图表形式表达,并支持不同曲线之间对比的 Demo。
  3. 增加 Lab→Dropdown Notification 用于实现 App 内自己的顶部通知功能。
  4. QMUILabel 增加对新功能 truncatingTailView 的展示。
  5. QMUIInteractiveDebugPanelItem 增加快速生成文本 item、segmentedControl item 的方法。
  6. UINavigationBar(QMUISmoothEffect) 适配了 QMUI 4.4.0 里对 AutomaticCustomNavigationBarTransitionStyle 的重构。
  7. UINavigationItem(QMUIBottomAccessoryView) 适配了 QMUI 4.4.0 里对 AutomaticCustomNavigationBarTransitionStyle 的重构。

QMUI Code Snippets

  1. if os 默认值从 iOS 14 改为 iOS 15。