QMUI iOS——致力于提高项目 UI 开发效率的解决方案
随着 QMUI 最初的几位老人家各奔天涯,历经7年自费集资的老官网 qmuiteam.com在不久的将来费用消耗完就不再维护了,以后都在 GitHub。对应地,依附于官网的自动上报统计 SendAnalyticsToQMUITeam
也在这个版本删除,借此也跟大家分享下统计数据(毕竟在座的各位都参与其中)。
截止至2023-7-24,QMUI iOS 累计接入6w项目(以Bundle Id为维度),日活跃项目 1.6k+,月活跃项目 4.3k+。
这个版本主要是累积这段时间的修修补补。
qmui_outsideEdge
对 UIBarButtonItem.customView
也生效,以后你可以让导航栏按钮的响应区域扩大到导航栏之外了。CALayer(QMUI)
增加属性 qmui_maskPathBlock
用于快捷添加遮罩。CALayer(QMUI)
增加属性 qmui_evenOddMaskPathBlock
用于快捷镂空一个区域。NSArray(QMUI)
增加方法 qmui_compactMapWithBlock:
用于转换数组里的元素类型,并支持过滤掉 nil
。NSDictionary(QMUI)
分类,提供 qmui_mapWithBlock:
方法用于转换字典里的 key-value 类型,提供 qmui_deepMapWithBlock:
方法用于深度拷贝的转换。-[NSMutableAttributedString appendAttributedString:]
遇到参数为 nil
时会命中系统 assert: nil argument 的情况。UILabel(QMUI)
增加 qmui_centerOfCapHeight
属性用于获取单行文本里 font.capHeight
的位置。UINavigationController(QMUI)
增加属性 qmui_alwaysInvokeAppearanceMethods
用于在 UINavigationController
不可视时进行 push/pop 依然能触发 vc 生命周期方法的方法。UINavigationController(QMUI)
增加属性 qmui_lastOperation
用于获取当前正在进行的切换界面动画类型(push 或 pop)。UITextField(QMUI)
增加属性 qmui_respondsToDeleteActionAtLeading
用于对齐 UITextView
的行为:在输入框开头继续按删除按钮也可以触发 shoudChange 的 delegate 方法。SendAnalyticsToQMUITeam
。SendAnalyticsToQMUITeam
。UISearchController.searchBar
作为 UITableView.tableHeaderView
时,进入搜索状态,搜索结果列表顶部有一大片空白的问题。forceEnableInteractivePopGestureRecognizer
的界面被 push 的过程中快速手势返回,容易导致 App 卡死的 bug。AutomaticCustomNavigationBarTransitionStyle
在 setViewControllers:
场景下的若干问题。QMUIImagePickerViewController
初始滚动位置可能错误的 bug。QMUIAlertController
以 ActionSheet
演示呈现较长内容时,顶部布局没考虑 safeAreaInsets
的问题。QMUIBadge
对纯文本的 UIBarButtonItem
基准布局错误的 bug。QMUIButton
在 adjustsButtonWhenDisabled = NO
时也会在 setEnabled:YES
里重置 alpha
的问题。QMUINavigationButton
自定义返回按钮点击区域太小的问题。QMUIKeyboardManager
在以 iPad“侧拉”模式打开的 App 中获取键盘可视高度错误的 bug,iPhone、iPad 全屏/分屏/台前调度,都没这个问题。QMUITheme
在切换 theme 时错误地覆盖 UITextView.textColor
导致如果输入框内存在不同颜色的富文本时会颜色错误的 bug。qmui_addSizeObserverForWindow:
,最终其中某个 window size 发生变化时所有 block 都被触发的 bug。UISearchBar(QMUI)
快速在 show/hide left/right accessoryView 时容易出现状态错误的 bug。UIView(QMUI).qmui_shouldShowDebugColor
属性在开启又关闭后可能导致元素背景全黑的问题。QMUI 4.6.1 版本主要是在 4.6.0 的基础上把最低 iOS 支持版本从 11 提升到 13,以对齐微信。也正因此,很多仅对 iOS 11、12 写的代码也一并去除了(包括很多 hook),所以建议大部分项目都升级到 QMUI 4.6.1 以使用更精简的代码。
仍需支持 iOS 11、12 系统的项目,请使用 QMUI 4.6.0 。
QMUITableViewStyleInsetGrouped
。UITableView (QMUI)
的 qmui_style
属性。QMUIStatusBarStyleDarkContent
。QMUIHelper.statusBarStyleDarkContent
方法。UISearchBar (QMUI)
的 qmui_textField
属性。ShouldFixTabBarTransitionBugInIPhoneX
开关。QMUITableViewStyleInsetGrouped
,将其替换为系统的 UITableViewStyleInsetGrouped
。UITableView.qmui_style
的地方(包括 Xib 文件),将其替换为系统的 UITableView.style
属性。QMUIStatusBarStyleDarkContent
,将其替换为系统的 UIStatusBarStyleDarkContent
。QMUIHelper.statusBarStyleDarkContent
的地方,将其替换为系统的 UIStatusBarStyleDarkContent
。UISearchBar.qmui_textField
的地方,将其改为系统的 UISearchBar.searchTextField
。ShouldFixTabBarTransitionBugInIPhoneX
。QMUI 4.6.0 版本主要内容是兼容 iOS 16 及 iPhone 14 等新设备,以屏幕旋转、键盘管理为主。其中屏幕旋转的使用方式可以查看 Wiki:《适用于 iOS 16 及以下版本的屏幕方向控制方式》。
QMUIPopupMenuView
增加 sectionSpacing
属性用于控制 section
之间的间隙。QMUIThemeColor
、QMUIThemeImage
、QMUIThemeVisualEffect
均增加了 name
属性及对应的 init 方法,让业务可以用字符串来标记该动态对象。NSShadow (QMU)
分类提供一个便捷的 init 方法。CALayer (QMUI)
增加属性 qmui_shadow
支持用 NSShadow
对象来描述投影样式,从而可以一行代码完成投影的设置。NSArray (QMUI)
增加方法 qmui_firstMatchWithBlock:
用于过滤第一个符合 block 条件的元素。UIBezierPath (QMUI)
增加方法 qmui_bezierPathWithMediaTimingFunction:
支持将一个 CAMediaTimingFunction
转成一条宽高为 1 的贝塞尔曲线(可以理解为数据可视化)。QMUICommonDefines.h
增加 IOS16_SDK_ALLOWED
宏用来标志当前是否为 Xcode 14 编译环境。[QMUIHelper screenSizeFor67InchAndiPhone14Later]
方法、[QMUIHelper is67InchScreenAndiPhone14Later]
方法、IS_67INCH_SCREEN_AND_IPHONE14
宏用于标记当前设备是否为 iPhone 14 Pro Max 尺寸的屏幕。[QMUIHelper statusBarHeightConstant]
用于获取静态的状态栏高度。-[QMUIHelper deviceName]
、-[QMUIHelper deviceModel]
增加新设备的信息。-[QMUIHelper safeAreaInsetsForDeviceWithNotch]
增加新设备的值。UIViewController (QMUI_Interface)
增加方法 qmui_rotateToInterfaceOrientation:
用于强制将当前界面旋转到某个指定方向。UIViewController (QMUI_Interface)
增加方法 qmui_setNeedsUpdateOfSupportedInterfaceOrientations
对应 iOS 16 系统的 setNeedsUpdateOfSupportedInterfaceOrientations
,用于告诉系统当前希望刷新屏幕方向。UITableViewCell (QMUI)
增加属性 qmui_configureReorderingStyleBlock
支持修改 cell 在排序过程中的样式。QMUIPopupContainerView
将 UIColor *shadowColor
属性改为 NSShadow *shadow
以支持更完整的投影样式。UISlider (QMUI)
将 qmui_thumbShadowColor
、qmui_thumbShadowOffset
、qmui_thumbShadowRadius
删除,改为新增的 qmui_thumbShadow
属性。StatusBarHeightConstant
能兼容 iOS 16、iPhone 14 Pro 灵动岛。AS_65INCH_SCREEN
宏内。-[QMUIHelper isRegularScreen]
内。+[QMUIHelper rotateToDeviceOrientation:]
方法。QMUIPopupContainerView.shadowColor
的地方,将其改为新的 shadow
属性。UISlider.qmui_thumbShadowColor
、UISlider.qmui_thumbShadowOffset
、UISlider.qmui_thumbShadowRadius
的地方,将其替换为新的 qmui_thumbShadow
属性。StatusBarHeightConstant
的地方,分别测试其在 iPhone 13 和 iPhone 14 Pro 下的布局是否正确。AS_65INCH_SCREEN
的地方,测试其在 iPhone 14 Pro Max 下的布局是否正确。-[QMUIHelper isRegularScreen]
的地方,测试其在 iPhone 14 Pro Max 下表现是否正确。+[QMUIHelper rotateToDeviceOrientation:]
的地方,将其换成 -[UIViewController qmui_rotateToInterfaceOrientation:]
。QMUIPopupContainerView
将 sourceView
设置为 nil
时 crash 的 bug。UIView.qmui_hitTestBlock
的返回值应该添加 _Nullable
以对齐系统。QMUIKeyboardManager
的各种 bug。UIView.backgroundColor
设置为 QMUIThemeColor
后再设置为另一个与 QMUIThemeColor
当前色值相同的颜色时,后者无效的 bug。UINavigationController
里修改 navigationBar
可能会导致 navigationBar
样式错误的 bug。tintColorAdjustsTitleAndImage
的 QMUIButton
在 App 切到桌面再切回来时颜色错误的 bug。QMUINavigationTitleView.subAccessoryView
在计算布局时如果 subAccessoryView
带有 transform
则布局错误的 bug。QMUIPopupContainerView
在 sourceView
、sourceBarItem
的值更新时没有清除与旧值的绑定关系的 bug。QMUIPopupContainerView
计算宽高可能不准确的 bug:应该取 px 整数而不是 pt 整数。QMUIPopupMenuButtonItem
里强制修改 button.contentEdgeInsets.top/bottom
为 0 的 bug。QMUITextView
文本颜色设置为 QMUIThemeColor
后无法响应 theme 变化的 bug。-[QMUIHelper keyboardHeightWithNotification:inView:]
在 iOS 16 台前调度下无法返回正确值的 bug。UITableViewCell(QMUI).qmui_selectedBackgroundColor
有时候失效的 bug。AutomaticallyRotateDeviceOrientation
在 iOS 16 下已经不需要了,请业务项目知悉即可。NSObject (QMUI).qmui_ivarList
输出的内容里,为每个 Ivar 开头增加了 offset 值的展示,同时显示十进制和十六进制的值,中间用“|”隔开。AutomaticCustomNavigationBarTransitionStyle
的情况下,从界面 B pop 回界面 A 的过程,如果 A 的导航栏效果与全局默认效果不同,则在 pop 过程中 A 的导航栏样式错误的 bug。qmui_outsideEdge
在不可见的 view 上生效的 bug。QMUIAlertController
在 alert、actionSheet 两种 style 下,如果不存在 title、message、customView 时,第一个 action 的顶部依然错误出现分隔线的 bug。UIScrollView (QMUI).qmui_alreadyAtTop
可能因为浮点精度问题导致返回值错误的 bug。QMUIBarProtocol
用于同时约定 UINavigationBar
、UITabBar
的功能接口,因为这两种 bar 所需要的功能基本都一样,用 protocol 来约定也便于后续同步调整这两种 bar 的功能。同时也因此使得 UINavigationBar (QMUI)
新增了 qmui_effectView
、qmui_effectViews
、qmui_effect
、qmui_effectForegroundColor
几个与磨砂相关的接口。QMUIBarProtocol
为 UINavigationBar
带来更多的能力,所以这个版本我们优化了 QMUISmoothEffect
、AutomaticCustomNavigationBarTransitionStyle
里与磨砂相关的表现,使其更符合组件预期。UIView (QMUINavigationTitleView).qmui_useAsNavigationTitleView
属性用于标记某个 view 为自定义的导航栏 titleView,以便 QMUI 自动帮你处理一些布局上的系统 bug。QMUIPopupMenuView
增加 willHandleButtonItemEventBlock
属性便于统一管理 item 的点击行为。CALayer (QMUI)
增加 qmui_layerWithName:
方法用于便捷查找指定 name 的 layer。UIActivityIndicator(QMUI)
支持用 qmui_size
指定大小。QMUIBarProtocol
的调整,我们同时删除了 UINavigationBar (QMUI).qmui_backgroundContentView
属性。UISearchController.dimsBackgroundDuringPresentation
默认值在 iOS 15 下被改为 NO 了,为了保持与旧版本的一致,QMUISearchController
里将其改为 YES。QMUICommonTableViewController
内自带的 QMUISearchController
的搜索结果列表的 UITableViewStyle
从 Plain 改为与当前宿主 vc 的 tableView.style 一致。qmui_substringFromIndex
的参数 index 等于字符串长度时返回的值从 nil 改为 @"",以保持与系统方法一致。UINavigationBar (QMUI).qmui_backgroundContentView
属性,请将 QMUIKit 旧代码抄到业务项目里。QMUISearchController
的地方,检查进入搜索状态时界面表现是否符合预期。QMUICommonTableViewController
、带有搜索功能,且 style 不为 UITableViewStylePlain
的列表,其搜索结果的 tableViewStyle 是否符合预期。qmui_substringFromIndex
的地方,在 index 等于 string.length 时表现是否正常。QMUIAlertController
以 alert 形式显示时,如果内容特别多,浮层会溢出到屏幕的 safeAreaInsets 区域的问题。QMUIConsole.canShow = NO
时依然会创建相关的 view、viewController 对象的问题。-[UILabel _accessibilityButtonShapesChangedNotification:]: message sent to deallocated instance 0x17e751d60
的问题。QMUIMultipleDelegates
在 iOS 16 下配合 UIScrollView
可能引发 crash 的问题。QMUINavigationTitleView.needsLoadingPlaceholderSpace = NO
时即便不显示 loading,loading 也会占位,导致文字偏右的问题。QMUITextView
文字换行时丢失系统滚动动画特效的 bug。- [QMUITextView setFrame:]
被调用时即便 size 没变化也会触发 setContentOffset:
产生滚动的问题。+[QMUIHelper applicationSize]
在 MacCatalyst App / M1 上返回了 CGSizeZero
导致 APPLICATION_WIDTH
、APPLICATION_HEIGHT
的值为 0 的 bug。preferredStatusBarStyle
方法并且在其中调用 childViewControllerForStatusBarStyle
方法的情况下,iOS 12 present 起 AVPlayerViewController
在 dismiss 时会触发 preferredStatusBarStyle
导致死循环的 bug:因为 AVPlayerViewController
内部的 preferredStatusBarStyle
会转向 presentingViewController
的 preferredStatusBarStyle
,而后者又会 return AVPlayerViewController
,于是死循环。qmui_substringAvoidBreakingUpCharacterSequences
系列方法在遇到 length 为1、range 与 string 相等的情况时会 crash 的 bug。QMUIStringPrivate
里的 assert 条件与系统方法不匹配的问题。substring:avoidBreakingUpCharacterSequencesWithRange:lessValue:countingNonASCIICharacterAsTwo:
在接受的 range 头尾都刚好落在一个 emoji 的中间时会得到一个负值 range 并引起 crash 的 bug,同时对负值 range 做 QMUIAssert 的提醒但不干预其返回值。QMUIConsole
在没使用配置表或者配置表里没设置 TableViewCellBackgroundColor
的情况下,打印出来的日志背景是白色的,看不见文字的 bug。StatusBarHeightConstant
的值,使其在 statusBarHidden 时,iOS 14 下返回44,iOS 15 返回50,保持与系统 UIApplication.statusBarFrame.size.height
一致。NSURL (QMUI).qmui_queryItems
item 类型错误的 bug。QMUITextView
当文本较多,在真机上长按系统输入法的删除按钮达到快速删除模式时,输入框底部容易出现大段空白的 bug。UITableView.delegate
开启了 qmui_multipleDelegatesEnabled
后在 dealloc 时可能引发 crash 的问题。UISlider(QMUI)
先设置 qmui_step
再设置 qmui_stepDidChangeBlock
后某些情况下首次点击无法触发 block 的 bug。UIImageView
、UIButton
配合 template image 使用时无法通过 tintColor
来修改图片颜色的 bug。QMUINavigationTitleView
先设置 needsLoadingView = YES
再修改 loadingViewSize
会导致文字无法完整显示的 bug。QMUILabel.truncatingTailView
在 label.text 为空时 crash 的 bug。UITableView
先 setDelegate:
再 setDataSource:
可能引发 crash 的问题。QMUIConsole
专属的 window 类型从 UIWindow
改为 QMUIConsoleWindow
,使其更容易与其他 window 区分开(例如在 Lookin 里查看结构时)。- [NSString (QMUI) qmui_trim]
默认去掉 C 里的字符串结束符“\0”。UISlider (QMUI)
增加 qmui_stepDidChangeBlock
以更便捷的方式监听 step 的变化,同时修复之前用 value changed 监听可能不准确的 bug。-[NSString (QMUI) qmui_capitalizedString
的实现,如果字符串以 Emoji 开头,就不应该尝试转为大写了。UITabBar (QMUI).qmui_effectViews
在 iOS 12 及以下会 crash 的 bug。QMUIStringPrivate
增加对 NSString
substring 系列接口的异常情况的保护,方便自动发现类似裁剪字符串时不小心把 emoji 从中间裁剪的场景,避免出现乱码、crash。NSObject (QMUI)
增加 qmui_viewInfo
属性用于 Debug 时方便地输出某个 view 的 view 层级结构。QMUINavigationBarScrollingAnimator
自动获取 UINavigationBar
的逻辑,旧版本是通过 QMUIHelper.visibleViewController.navigationController.navigationBar
来获取,新版本改为通过绑定的 scrollView 一层一层往上找,找到所在的 viewController 的导航栏。所以如果业务项目以前存在“scrollView 所在的 viewController,和 scrollView 控制的 navigationBar 不处于同一个 UINavigationController” 里时,则更新 QMUI 版本后 animator 会失效。大部分情况下业务项目应该不会存在这种场景。QMUINavigationBarScrollingAnimator
、QMUINavigationBarScrollingSnapAnimator
的地方,效果是否与 4.4.1 一致。NavBarRemoveBackgroundEffectAutomatically
在开启了 AutomaticCustomNavigationBarTransitionStyle
时可能对假 bar 无效的 bug。QMUINavigationBarScrollingAnimator
在 scrollView 所在的 viewController 已经被推出 UINavigationController
时,滚动器依然能对 UINavigationBar 产生影响的 bug。QMUIButton
开启了 adjustsImageTintColorAutomatically
后修改 normal 的 image,highlighted、disabled 的 image 无法同步更新的 bug。QMUIModalPresentationAnimationStylePopup
的 hide 动画无法看到缩小过程的 bug。QMUISmoothEffect
在转场过程中修改 effect 可能出现的 crash。UILabel (QMUI_Marquee)
分类,支持开启系统 UILabel
内置的跑马灯效果,功能比 QMUIMarqueeLabel
简单,但由于是系统内置的能力,性能应该是不需要担心的。我们推荐在满足需求的前提下优先使用 UILabel (QMUI_Marquee)
。UISlider (QMUI)
分类用于取代之前的 QMUISlider
(后者已删除),提供同等功能的同时,增加了 qmui_numberOfSteps
用于支持离散式数据,同时让 UIView (QMUI).qmui_outsideEdge
作用在 UISlider
上时,可以扩大中间圆点的响应区域(以前是扩大整个 slider,这通常不符合预期)。
QMUITextFieldDelegate
增加方法 textField:shouldChangeCharactersInRange:replacementString:originalValue:
,用于业务使用了 maximumTextLength
时可以通过这个方法来实现业务自定义的输入限制。在之前的版本里,自定义的输入限制和 maximumTextLength
是两个互斥的能力。QMUITextViewDelegate
也增加了方法 textView:shouldChangeTextInRange:text:originalValue:
,原因不再赘述。UIImage (QMUI)
里的 qmui_imageWithTintColor:
、qmui_imageWithColor:
方法增加 QMUIAssert 用于辅助发现业务里“无法正确用一个 QMUIThemeColor 生成一张 QMUIThemeImage” 的场景。UITabBar (QMUI)
增加 qmui_effectViews
用于在 iOS 15 里获取所有的背景磨砂 view。QMUISlider
提供的功能没必要非要以子类的形式存在,因此这个版本我们删除了 QMUISlider
,同时新增了功能更加强大的 UISlider (QMUI)
分类。QMUISlider
,请将其改为 UISlider (QMUI)
里的对应属性(通常都是加个 qmui_
前缀而已),或者也可以直接复制 QMUISlider.h/.m 到项目内继续使用。QMUITableViewCell
并且重写了 initWithStyle:reuseIdentifier:
方法,但在业务使用时通过 initForTableView:withStyle:reuseIdentifier:
构造 cell 的场景,表现是否正常(预期应该与 4.3.0 保持一致)。QMUILog
段落的位置迁移到 UIControl
的前面,这样才能保证其他模块在用到与 QMUILog 相关的开关时能读取到正确的值。UISlider (QMUI)
分类,顺便修复了 iOS 14 及以后的系统里无法正确获取到 thumbView 的 bug。UIView
使用了 qmui_layoutSubviewsBlock
属性,则会导致在 iPad 里开启悬浮键盘时,聚焦一个带有 inputAccessoryView
的输入框时会死循环卡死的 bug。NavBarRemoveBackgroundEffectAutomatically
后 iOS 15 里的 barTintColor
无法与 effectView
共存的 bug。AutomaticCustomNavigationBarTransitionStyle
在前后两个导航栏的显隐状态不一致时表现错误的 bug。QMUINavigationControllerAppearanceDelegate
系列方法控制自己的导航栏样式,则停留在该界面时切换 QMUITheme,导航栏样式会被覆盖为配置表的全局样式,而非该界面自己设置的值。-[NSString(QMUI) qmui_substringAvoidBreakingUpCharacterSequencesToIndex:]
方法在 index 刚好等于 string.length
时会 crash 的 bug:从语义上这样的 index 应当是合法的,此时需要返回当前 string 的 copy。UITabBar (QMUI).qmui_effectView
在 iOS 15 下无法正确获取到背景磨砂 view 的 bug,会导致 UITabBar (QMUI).qmui_effect
失效。QMUITableViewStyleInsetGrouped
的列表,每个 section 最后一个 cell 右下角的圆角丢失的 bug。UISlider (QMUI)
的 Demo。QMUIMarqueeLabel
Demo 增加 UILabel (QMUI_Marquee)
功能的展示。QMUIInteractiveDebugPanelViewController
的使用方式,使其可以方便地以 subview 的形式添加到界面上显示,也可以配置自己项目的外观。UIImage (QMUI)
Demo 增加渐变图片的展示。UITextField (QMUI)
Demo 增加对自定义内容格式限制的展示。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
功能的演示视频。
NavBarUsesStandardAppearanceOnly
,当业务项目打开的时候,会保持 UINavigationBar.scrollEdgeAppearance
与 UINavigationBar.standardAppearance
对齐,从而实现 iOS 15 上的导航栏在滚动前后样式一致。NavBarRemoveBackgroundEffectAutomatically
,当业务项目打开的时候,会让 UINavigationBar
在设置了 backgroundImage
、barTintColor
时自动隐藏磨砂,在 backgroundImage
、barTintColor
为 nil
时自动显示磨砂(也即维持 iOS 14 的默认行为)。因为 iOS 15 及以后,backgroundEffect
可以和 backgroundImage
、barTintColor
同时存在了,这与之前业务项目的代码逻辑的预期是不匹配的,要么你用这个开关来回到 iOS 14 的表现,要么你自己为 iOS 15 增加适配逻辑。TabBarUsesStandardAppearanceOnly
、TabBarRemoveBackgroundEffectAutomatically
、ToolBarUsesStandardAppearanceOnly
、ToolBarRemoveBackgroundEffectAutomatically
,具体含义请参考上面的 NavBar
,这里不再赘述。TableViewSectionHeaderTopPadding
、TableViewGroupedSectionHeaderTopPadding
、TableViewInsetGroupedSectionHeaderTopPadding
,分别设置三种 style 的 QMUITableView
在 iOS 15 上的 sectionHeaderTopPadding
默认值,默认不修改的话,UITableViewStylePlain
会在每个 sectionHeader 之前多出来23pt的空白,另外两种 style 的列表与 iOS 14 一致。QMUICommonDefines.h
增加宏 IOS15_SDK_ALLOWED
用于区分当前是否是 Xcode 13 编译。QMUIAnimationHelper
增加接口 bounceFromValue:toValue:time:coeff:
用于实现系统 UIScrollView
拖到尽头那种阻尼感的体验。QMUILabel
增加属性 truncatingTailView
用于在文字缩略时可以显示一个自定义的 View,具体可查看 QMUI Demo 的效果。
QMUIModalPresentationViewController
增加属性 window
允许业务获取到 modal 内部正在使用的 UIWindow
对象。QMUIModalPresentationViewController
增加属性 shouldDimmedAppAutomatically
用于控制当前 modal 显示时是否需要把背后的 App 界面置灰(类似系统的 UIAlertController
显示时的效果)。QMUIPopupContainerView
增加属性 contentViewSizeThatFitsBlock
方便业务在外部控制 popup 内容的大小,而不一定非要继承一个子类。QMUIPopupContainerView
增加属性 backgroundView
支持用一个自定义的 View(例如磨砂)作为 popup 的背景,当使用了这个属性后,arrowImage
只会作为遮罩来使用,不会显示 arrowImage
图片内部的纹理(也即只用箭头的造型,不用它的内容)。
QMUIPopupContainerView
优化属性 arrowImage
的实现,允许你将一张 UIImageRenderingModeAlwaysTemplate
的图片作为箭头图片,当你这么做时,图片的颜色会自动跟随 backgroundColor
走,从而避免以前设置了自定义箭头图片后再修改 backgroundColor
,会看到箭头颜色与背景色不一致的问题。QMUITextField
增加与 QMUITextView
相同的 canPerformPasteActionBlock
、pasteBlock
接口以支持控制粘贴事件(例如你可以在粘贴文本时把文本变成一张图放在输入框里)。+[QMUIHelper deviceModel]
增加 iPhone 13、iPad 新设备的信息。QMUIStringProtocol
,将原本 NSString(QMUI)
支持的功能也迁移到 NSAttributedString(QMUI)
内。UIBlurEffect(QMUI)
分类,提供 qmui_effectWithBlurRadius:
支持指定明确的模糊半径,提供 qmui_style
支持获取当前 blur 对象的 style 值。同时 QMUI Demo 内增加 UIBlurEffect(QMUI)
的 Demo 展示。UITableView(QMUI_InsetGrouped)
支持在 iOS 12 及以下的 Interface Builder 里设置 tableView 为 InsetGrouped
。- [UIImage(QMUI) qmui_imageWithGradientColors:]
增加 QMUIImageGradientTypeTopLeftToBottomRight
、QMUIImageGradientTypeTopRightToBottomLeft
类型。UINavigationBar
、UIToolbar
从这个版本开始,改为用 iOS 13 就提供的新系统接口 UINavigationBarAppearance
、UIToolbarAppearance
来设置样式(UITabBar
的在 QMUI 4.0.0 适配 iOS 13 时就已经换成新接口了),新旧接口是互斥的,一旦项目里某个地方用了新接口,整个项目的旧接口都会失效。但为了尽量减少业务项目更新 QMUI 版本的工作量,我们在 UINavigationBar(QMUI)
、UIToolbar(QMUI)
内对旧接口做了映射,统一转换为新接口,因此预期业务项目更新版本后应该不会出现 UINavigationBar
、UIToolbar
的样式差异问题。qmui_safeAreaInsets
)也没必要了。AutomaticCustomNavigationBarTransitionStyle
的实现,减少了对 QMUINavigationControllerAppearanceDelegate
系列接口多次不必要的调用,并且更稳定。QMUIButton
的功能已足够灵活,相比之下基于它衍生的 QMUIFillButton
、QMUIGhostButton
显得有点鸡肋,且预设的 enum 难以准确满足业务项目的配色需求,因此这个版本我们将 QMUIFillButton
、QMUIGhostButton
删除,建议原本在用的项目将其改为 QMUIButton
,或者你也可以复制这两个类的文件放在业务项目里继续使用。QMUILinkButton
在 4.4.0 里正式删除。QMUITheme
在 iOS 13 及以后的系统里监听系统 userInterfaceStyle
变化的方式,从而达到:
-[UIWindow traitCollection]
会导致每次有任何界面操作(触摸、按下键盘快捷键、Dark Mode 切换)时都会触发这段逻辑,而我们仅仅只希望利用它来监听 Dark Mode 切换而已。-[UIWindow traitCollection]
导致在 Xcode 唤醒的场景里 App 第一次升起键盘会触发 Main Thread Checker 的问题。userInterfaceStyle
发生变化,到 QMUITheme 成功切换之间的耗时较长,在此期间访问 QMUIThemeManager.currentTheme
得到的值必定都是错误的(例如这过程中就会触发 UIViewController preferredStatusBarStyle,而业务项目在该方法里获取当前 QMUIThemeManager.currentTheme 的操作还是比较常见的)问题。QMUIThemePrivate
里重写 -[UIView setBackgroundColor:]
、-[UITableViewCell setBackgroundColor:]
的代码,实测 iOS 11-15 均不需要这种处理了,而这段代码会导致 QMUIThemeColor
无法搭配 UIViewPropertyAnimator
使用。QMUIThemePrivate
里重写 -[UITextField setNeedsDisplay]
的代码,实测不需要。QMUIHelper
重命名 is61InchScreenAndiPhone12
为 is61InchScreenAndiPhone12Later
,重命名 screenSizeFor61InchAndiPhone12
为 screenSizeFor61InchAndiPhone12Later
。QMUIHelper.safeAreaInsetsForDeviceWithNotch
对全面屏 iPad 返回的 top 值从 0 改为 24。QMUIHelper.resetDimmedApplicationWindow
的实现里,把 Normal 改为系统默认的 Automatic(免测)。NavBarButtonFontBold
在 iOS 15 里对系统的 Done 类型的 UIBarButtonItem
也能生效,iOS 14 及以前只能对 QMUINavigationButtonTypeBold
才生效。StatusbarStyleLightInitially
,新增配置表开关 DefaultStatusBarStyle
,新开关的类型为 UIStatusBarStyle
,可以支持精准的状态栏样式控制,从而避免类似 #1311 的问题。QMUIButton
,如果较多,建议在项目里创建工具方法(可以参考 QMUI Demo 里的 +[QDUIHelper generateGhostButtonWithColor:]
。或者也可以将这两个被删除的文件移到业务项目中继续使用。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
safeAreaInsets
,前者依然能用但已被标记为废弃,下个版本会删除。adjustedContentInset
,前者依然能用但已被标记为废弃,下个版本会删除。maskedCorners
,前者依然能用但已被标记为废弃,下个版本会删除。performBatchUpdates
。QMUIHelper.safeAreaInsetsForDeviceWithNotch
的地方在 iPad 上是否正常。AutomaticCustomNavigationBarTransitionStyle
效果的地方是否正常。QMUIThemeColor
作为 UIView.backgroundColor
、UITableViewCell.backgroundColor
的地方,theme 切换时是否正常。UITextField
的文字颜色是否正常。UITraitCollection.currentTraitCollection.userInterfaceStyle
来判断当前 App 样式的写法,有的话,请去掉并改为用 QMUIThemeManagerCenter.defaultThemeManager.currentThemeIdentifier
,因为前者这个系统的方法在 Dark Mode 切换过程中可能会得到错误的值。#pragma mark - NavigationBar
分段里添加以下开关,并将其设置为项目所需的值。请保证语句的顺序在其他 navBar 开关之前。
if (@available(iOS 15.0, *)) {
QMUICMI.navBarUsesStandardAppearanceOnly = NO;
QMUICMI.navBarRemoveBackgroundEffectAutomatically = NO;
}
#pragma mark - TabBar
分段里添加以下开关,并将其设置为项目所需的值。请保证语句的顺序在其他 tabBar 开关之前。
if (@available(iOS 15.0, *)) {
QMUICMI.tabBarUsesStandardAppearanceOnly = NO;
QMUICMI.tabBarRemoveBackgroundEffectAutomatically = NO;
}
#pragma mark - Toolbar
分段里添加以下开关,并将其设置为项目所需的值。请保证语句的顺序在其他 toolBar 开关之前。
if (@available(iOS 15.0, *)) {
QMUICMI.toolBarUsesStandardAppearanceOnly = NO;
QMUICMI.toolBarRemoveBackgroundEffectAutomatically = NO;
}
if (@available(iOS 15, *)) {
QMUICMI.tableViewSectionHeaderTopPadding = UITableViewAutomaticDimension;
QMUICMI.tableViewGroupedSectionHeaderTopPadding = UITableViewAutomaticDimension;
QMUICMI.tableViewInsetGroupedSectionHeaderTopPadding = UITableViewAutomaticDimension;
}
UIBarButtonItem
,字体样式是否符合预期。QMUICMI.defaultStatusBarStyle = UIStatusBarStyleDefault; // DefaultStatusBarStyle : 默认的状态栏样式,默认值为 UIStatusBarStyleDefault,也即在 iOS 12 及以前是黑色文字,iOS 13 及以后会自动根据当前 App 是否处于 Dark Mode 切换颜色。如果你希望固定为白色,请设置为 UIStatusBarStyleLightContent,固定黑色则设置为 QMUIStatusBarStyleDarkContent。
UIGestureRecognizer(QMUI)
assert 的问题。qmui_getProjectClassList
获取项目里所有业务 Class 失败的 bug。- [QMUITableViewCell initForTableView:xxx]
方法的实现不恰当,可能引起 Swift 内重复调用 init 的问题。QMUITextField
、QMUITextView
在进行”重做“操作时依然可能引发 #1168 里描述的问题的 bug。QMUIPopupMenuView
在 itemTitleFont
、itemTitleColor
、padding
的值发生变化时没有刷新 item 样式的 bug。UITextField
的文字颜色无法响应 QMUITheme
切换的 bug(包含聚焦和非聚焦状态都有问题)。QMUIThemeImage
调用 qmui_imageWithTintColor:
时如果参数是个 QMUIThemeColor
,则最终这个图片无效的 bug。UILabel(QMUI).qmui_textAttributes
的时候,先设置 textAlignment
再设置 text
,textAlignment
不生效的 bug。cell.backgroundColor
时会导致 UITableView(QMUI).qmui_insetGroupedCornerRadius
无效的 bug。QMUILabel
增加对新功能 truncatingTailView
的展示。QMUIInteractiveDebugPanelItem
增加快速生成文本 item、segmentedControl item 的方法。UINavigationBar(QMUISmoothEffect)
适配了 QMUI 4.4.0 里对 AutomaticCustomNavigationBarTransitionStyle
的重构。UINavigationItem(QMUIBottomAccessoryView)
适配了 QMUI 4.4.0 里对 AutomaticCustomNavigationBarTransitionStyle
的重构。