You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

198 lines
12 KiB

2 years ago
/**
* Tencent is pleased to support the open source community by making QMUI_iOS available.
* Copyright (C) 2016-2020 THL A29 Limited, a Tencent company. All rights reserved.
* Licensed under the MIT License (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
* http://opensource.org/licenses/MIT
* Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.
*/
//
// UIViewController+QMUI.h
// qmui
//
// Created by QMUI Team on 16/1/12.
//
#import <UIKit/UIKit.h>
#import "QMUICore.h"
NS_ASSUME_NONNULL_BEGIN
/// 在 App 的 rootViewController.view.frame.size 发生变化(例如横竖屏旋转,或者 iPad Split View 模式下调整大小)前发出通知,你可以通过 QMUIPrecedingAppSizeUserInfoKey 获取变化前的值(也即当前值),用 QMUIFollowingAppSizeUserInfoKey 获取变化后的值。
extern NSNotificationName const QMUIAppSizeWillChangeNotification;
/// 对应一个 NSValue 包裹的 CGSize 对象
extern NSString *const QMUIPrecedingAppSizeUserInfoKey;
/// 对应一个 NSValue 包裹的 CGSize 对象
extern NSString *const QMUIFollowingAppSizeUserInfoKey;
typedef NS_OPTIONS(NSUInteger, QMUIViewControllerVisibleState) {
QMUIViewControllerUnknow = 1 << 0, // 初始化完成但尚未触发 viewDidLoad
QMUIViewControllerViewDidLoad = 1 << 1, // 触发了 viewDidLoad
QMUIViewControllerWillAppear = 1 << 2, // 触发了 viewWillAppear
QMUIViewControllerDidAppear = 1 << 3, // 触发了 viewDidAppear
QMUIViewControllerWillDisappear = 1 << 4, // 触发了 viewWillDisappear
QMUIViewControllerDidDisappear = 1 << 5, // 触发了 viewDidDisappear
QMUIViewControllerVisible = QMUIViewControllerWillAppear | QMUIViewControllerDidAppear,// 表示是否处于可视范围,判断时请用 & 运算,例如 qmui_visibleState & QMUIViewControllerVisible
};
@interface UIViewController (QMUI)
/** 获取和自身处于同一个UINavigationController里的上一个UIViewController */
@property(nullable, nonatomic, weak, readonly) UIViewController *qmui_previousViewController;
/** 获取上一个UIViewController的title,可用于设置自定义返回按钮的文字 */
@property(nullable, nonatomic, copy, readonly) NSString *qmui_previousViewControllerTitle;
/**
* controller里的最高层可见viewControllerself.view.window是否存在
*
* @see App里的可见viewController使 [QMUIHelper visibleViewController]
*
* @return controller里的最高层可见viewController
*/
- (nullable UIViewController *)qmui_visibleViewControllerIfExist;
/**
* viewController present YES NO
* @warning UINavigationController UIViewController self self.navigationController viewController self.navigationController present self.qmui_isPresented = self.navigationController.qmui_isPresented = YES便 navigationController
*/
- (BOOL)qmui_isPresented;
/**
* UI相关的通知 UIKeyboardNotificationUIMenuControllerNotification等push到其他界面
*/
- (BOOL)qmui_isViewLoadedAndVisible;
/**
viewController viewDidLoad/viewWillApear/viewDidAppear/viewWillDisappear/viewDidDisappear
*/
@property(nonatomic, assign, readonly) QMUIViewControllerVisibleState qmui_visibleState;
/**
viewController
*/
@property(nullable, nonatomic, copy) void (^qmui_visibleStateDidChangeBlock)(__kindof UIViewController *viewController, QMUIViewControllerVisibleState visibleState);
/**
* UINavigationBar self.view maxY self.view.subviews
* @warning 使 self.view.window 使 viewDidLoad 使 viewDidLayoutSubviewsviewWillAppear: 使
* @warning UINavigationBar 0
*/
@property(nonatomic, assign, readonly) CGFloat qmui_navigationBarMaxYInViewCoordinator;
/**
* UIToolbar self.view self.view.subviews
* @warning 使 self.view.window 使 viewDidLoad 使 viewDidLayoutSubviewsviewWillAppear: 使
* @warning UIToolbar 0
*/
@property(nonatomic, assign, readonly) CGFloat qmui_toolbarSpacingInViewCoordinator;
/**
* UITabBar self.view self.view.subviews
* @warning 使 self.view.window 使 viewDidLoad 使 viewDidLayoutSubviewsviewWillAppear: 使
* @warning UITabBar 0
*/
@property(nonatomic, assign, readonly) CGFloat qmui_tabBarSpacingInViewCoordinator;
/// 提供一个 block 可以方便地控制是否要隐藏状态栏,适用于无法重写父类方法的场景。默认不实现这个 block 则不干预显隐。
@property(nullable, nonatomic, copy) BOOL (^qmui_prefersStatusBarHiddenBlock)(void);
/// 提供一个 block 可以方便地控制状态栏样式,适用于无法重写父类方法的场景。默认不实现这个 block 则不干预样式。
/// @note iOS 13 及以后,自己显示的 UIWindow 无法盖住状态栏了,但 iOS 12 及以前的系统,以 UIWindow 显示的浮层是可以盖住状态栏的,请知悉。
@property(nullable, nonatomic, copy) UIStatusBarStyle (^qmui_preferredStatusBarStyleBlock)(void);
/// 提供一个 block 可以方便地控制状态栏动画,,适用于无法重写父类方法的场景。默认不实现这个 block 则不干预动画。
@property(nullable, nonatomic, copy) UIStatusBarAnimation (^qmui_preferredStatusBarUpdateAnimationBlock)(void);
/// 提供一个 block 可以方便地控制全面屏设备屏幕底部的 Home Indicator 的显隐,适用于无法重写父类方法的场景。默认不实现这个 block 则不干预显隐。
@property(nullable, nonatomic, copy) BOOL (^qmui_prefersHomeIndicatorAutoHiddenBlock)(void) API_AVAILABLE(ios(11.0));
/**
viewController statusBar prefersStatusBarHidden containerViewController UITabBarControllerUINavigationController containerViewController prefersStatusBarHidden statusBar containerViewController childViewControllerForStatusBarHidden prefersStatusBarHidden qmui_prefersStatusBarHidden
*/
@property(nonatomic, assign, readonly) BOOL qmui_prefersStatusBarHidden;
/**
viewController statusBar style preferredStatusBarStyle containerViewController UITabBarControllerUINavigationController containerViewController preferredStatusBarStyle statusBar style containerViewController childViewControllerForStatusBarHidden preferredStatusBarStyle qmui_preferredStatusBarStyle
*/
@property(nonatomic, assign, readonly) UIStatusBarStyle qmui_preferredStatusBarStyle;
/**
viewController LargeTitle
@warning viewController navigationController
*/
@property(nonatomic, assign, readonly) BOOL qmui_prefersLargeTitleDisplayed;
@end
/**
* viewDidAppear: viewDidAppear: viewDidAppear:
*
*/
@interface UIViewController (Data)
/// 当数据加载完(什么时候算是“加载完”需要通过属性 qmui_dataLoaded 来设置)并且界面已经走过 viewDidAppear: 时,这个 block 会被执行,执行结束后 block 会被清空,以避免重复调用。
@property(nullable, nonatomic, copy) void (^qmui_didAppearAndLoadDataBlock)(void);
/// 请在你的数据加载完成时手动修改这个属性为 YES,如果此时界面已经走过 viewDidAppear:,则 qmui_didAppearAndLoadDataBlock 会被立即执行,如果此时界面尚未走 viewDidAppear:,则等到 viewDidAppear: 时,qmui_didAppearAndLoadDataBlock 就会被自动执行。
@property(nonatomic, assign, getter = isQmui_dataLoaded) BOOL qmui_dataLoaded;
@end
@interface UIViewController (Runtime)
/**
* UIViewController
* @param selector
* @return YES NO 使 UIViewController
*/
- (BOOL)qmui_hasOverrideUIKitMethod:(_Nonnull SEL)selector;
@end
@interface UIViewController (RotateDeviceOrientation)
/// 在配置表 AutomaticallyRotateDeviceOrientation 功能开启的情况下,QMUI 会自动判断当前的 UIViewController 是否具备强制旋转设备方向的权利,而如果 QMUI 判断结果为没权利但你又希望当前的 UIViewController 具备这个权利,则可以重写该方法并返回 YES。
/// 默认返回 NO,也即交给 QMUI 自动判断。
- (BOOL)qmui_shouldForceRotateDeviceOrientation;
@end
@interface UIViewController (QMUINavigationController)
/// 判断当前 viewController 是否处于手势返回中,仅对当前手势返回涉及到的前后两个 viewController 有效
@property(nonatomic, assign, readonly) BOOL qmui_navigationControllerPoppingInteracted;
/// 基本与上一个属性 qmui_navigationControllerPoppingInteracted 相同,只不过 qmui_navigationControllerPoppingInteracted 是在 began 时就为 YES,而这个属性仅在 changed 时才为 YES。
/// @note viewController 会在走完 viewWillAppear: 之后才将这个值置为 YES。
@property(nonatomic, assign) BOOL qmui_navigationControllerPopGestureRecognizerChanging;
/// 当前 viewController 是否正在被手势返回 pop
@property(nonatomic, assign) BOOL qmui_poppingByInteractivePopGestureRecognizer;
/// 当前 viewController 是否是手势返回中,背后的那个界面
@property(nonatomic, assign) BOOL qmui_willAppearByInteractivePopGestureRecognizer;
/// 可用于对 View 执行一些操作, 如果此时处于转场过渡中,这些操作会跟随转场进度以动画的形式展示过程
/// @param animation 要执行的操作
/// @param completion 转场完成或取消后的回调
/// @note 如果处于非转场过程中,也会执行 animation ,随后执行 completion,业务无需关心是否处于转场过程中。
- (void)qmui_animateAlongsideTransition:(void (^ __nullable)(id <UIViewControllerTransitionCoordinatorContext>context))animation
completion:(void (^ __nullable)(id <UIViewControllerTransitionCoordinatorContext>context))completion;
@end
@interface QMUIHelper (ViewController)
/**
* viewController
* @warning nil
*/
+ (nullable UIViewController *)visibleViewController;
@end
NS_ASSUME_NONNULL_END