这是我参与8月更文挑战的第6天,活动详情查看: 8月更文挑战” juejin.cn/post/698796… ”
前言
视图置顶关于 bringSubviewToFront 和view.layer.zPosition的选择
使用bringSubviewToFront方法需要在重新刷新界面结构层次的时候调用;
使用view.layer.zPosition方法会获取不到view的点击事件
应用场景
1 、比如让日期控件置于窗口的最顶层
2、悬浮按钮(支持拖曳)
I 、bringSubviewToFront的用法
- 让日期控件置于窗口的最顶层
PGDatePickManager kunnan.blog.csdn.net/article/det…
@implementation PGDatePickManager (ios12)
+ (void)load {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSArray *selStringsArray = @[@"viewWillLayoutSubviews"];
// @"reloadRowsAtIndexPaths:withRowAnimation:", @"deleteRowsAtIndexPaths:withRowAnimation:", @"insertRowsAtIndexPaths:withRowAnimation:"];
[selStringsArray enumerateObjectsUsingBlock:^(NSString *selString, NSUInteger idx, BOOL *stop) {
NSString *mySelString = [@"sd_" stringByAppendingString:selString];
Method originalMethod = class_getInstanceMethod(self, NSSelectorFromString(selString));
Method myMethod = class_getInstanceMethod(self, NSSelectorFromString(mySelString));
method_exchangeImplementations(originalMethod, myMethod);
}];
});
}
- (void)sd_viewWillLayoutSubviews{
[self sd_viewWillLayoutSubviews];
[UIApplication.sharedApplication.delegate.window bringSubviewToFront:self.view.superview];
}
- listTableView
[self.superview.window addSubview:self.listTableView];
/// 避免被其他子视图遮盖住
[self.superview.window bringSubviewToFront:self.listTableView];
CGRect frame = CGRectMake(CGRectGetMinX(self.frame), CGRectGetMaxY(self.frame), CGRectGetWidth(self.frame), 0);
//坐标转换
CGRect convertRect= [self.superview convertRect:frame toView:self.superview.window];
[self.listTableView setFrame:convertRect];
II、同级Layer改变显示顺序
- self.view.layer.zPosition
self.view.layer.zPosition = MAXFLOAT; 999
III 案例: 悬浮按钮(支持拖曳)
下级订货单关于悬浮按钮的相关需求:
1、存在“待发货”记录时,显示“一键发货”按钮 点击一键发货:实现待发货的分配记录,都更新为待收货 2、存在“待收货”记录时,显示“一键代收货”按钮 点击一键代收货:实现待发货的分配记录,都更新为“已收货”
3.1 原理
1 、bringSubviewToFront 2、添加移动手势可以拖动 3、使用谓词进行判断是否存在特定条件的数据
//添加移动手势可以拖动
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(dragAction:)];
self.panGestureRecognizer.minimumNumberOfTouches = 1;
self.panGestureRecognizer.maximumNumberOfTouches = 1;
self.panGestureRecognizer.delegate = self;
[self addGestureRecognizer:self.panGestureRecognizer];
3.2 用法
@property (strong, nonatomic) KNFrontV * orangeView;
@end
@implementation QCTRecordViewController
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.view bringSubviewToFront:self.orangeView];
[self.orangeView layoutIfNeeded];
self.orangeView.layer.cornerRadius =self.orangeView.height *0.5;
}
- (KNFrontV *)orangeView{
if (nil == _orangeView) {
KNFrontV *tmpView = [[KNFrontV alloc] initWithFrame:CGRectMake(0, 0 , kAdjustRatio(53), kAdjustRatio(53))];
_orangeView = tmpView;
[self.view addSubview:_orangeView];
__weak __typeof__(self) weakSelf = self;
tmpView.button.titleLabel.numberOfLines = 0;
tmpView.button.titleLabel.textAlignment = NSTextAlignmentCenter;
tmpView.button.titleLabel.font = [UIFont systemFontOfSize:15.0];
[tmpView.button setTitle:@"一键\n发货" forState:UIControlStateNormal];// 发货 购买\n开店数
tmpView.backgroundColor = rgb(255,54,87);
//
// tmpView.layer.cornerRadius = 14;// layoutsubview
//设置显示图片方式一:
// tmpView.imageView.image = [UIImage imageNamed:@"icon_dayin"];
//设置显示图片方式二:
// [logoView.button setBackgroundImage:[UIImage imageNamed:@"logo1024"] forState:UIControlStateNormal];
[_orangeView mas_makeConstraints:^(MASConstraintMaker *make) {
make.size.mas_equalTo(CGSizeMake(kAdjustRatio(53), kAdjustRatio(53)));
make.right.offset(kAdjustRatio(-20));
make.bottom.offset(kAdjustRatio(-90));
}];
tmpView.clickDragViewBlock = ^(KNFrontV *dragView){
[weakSelf setupclickDragViewBlock];
};
}
return _orangeView;
}
- (void)setupclickDragViewBlock{
}
- KNFrontV的定义
//
// KNFrontV.h
// Housekeeper
//
// Created by mac on 2021/5/6.
// Copyright © 2021 https://kunnan.blog.csdn.net/ . All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
// 拖曳view的方向
typedef NS_ENUM(NSInteger, KNDragDirection) {
KNDragDirectionAny, /**< 任意方向 */
KNDragDirectionHorizontal, /**< 水平方向 */
KNDragDirectionVertical, /**< 垂直方向 */
};
@interface KNFrontV : UIView
/**
是不是能拖曳,默认为YES
YES,能拖曳
NO,不能拖曳
*/
@property (nonatomic,assign) BOOL dragEnable;
/**
活动范围,默认为父视图的frame范围内(因为拖出父视图后无法点击,也没意义)
如果设置了,则会在给定的范围内活动
如果没设置,则会在父视图范围内活动
注意:设置的frame不要大于父视图范围
注意:设置的frame为0,0,0,0表示活动的范围为默认的父视图frame,如果想要不能活动,请设置dragEnable这个属性为NO
*/
@property (nonatomic,assign) CGRect freeRect;
/**
拖曳的方向,默认为any,任意方向
*/
@property (nonatomic,assign) KNDragDirection dragDirection;
/**
contentView内部懒加载的一个UIImageView
开发者也可以自定义控件添加到本view中
注意:最好不要同时使用内部的imageView和button
*/
@property (nonatomic,strong) UIImageView *imageView;
/**
contentView内部懒加载的一个UIButton
开发者也可以自定义控件添加到本view中
注意:最好不要同时使用内部的imageView和button
*/
@property (nonatomic,strong) UIButton *button;
/**
是不是总保持在父视图边界,默认为NO,没有黏贴边界效果
isKeepBounds = YES,它将自动黏贴边界,而且是最近的边界
isKeepBounds = NO, 它将不会黏贴在边界,它是free(自由)状态,跟随手指到任意位置,但是也不可以拖出给定的范围frame
*/
@property (nonatomic,assign) BOOL isKeepBounds;
/**
点击的回调block
*/
@property (nonatomic,copy) void(^clickDragViewBlock)(KNFrontV *dragView);
/**
开始拖动的回调block
*/
@property (nonatomic,copy) void(^beginDragBlock)(KNFrontV *dragView);
/**
拖动中的回调block
*/
@property (nonatomic,copy) void(^duringDragBlock)(KNFrontV *dragView);
/**
结束拖动的回调block
*/
@property (nonatomic,copy) void(^endDragBlock)(KNFrontV *dragView);
@end
NS_ASSUME_NONNULL_END
KNFrontV的完整实现请看CSDN原文:blog.csdn.net/z929118967/…
或者关注公众号:iOS逆向
3.3 使用 NSPredicate
判断是否存在“待收货”记录
/**
下级订货单
1、存在“待发货”记录时,显示“一键发货”按钮
点击一键发货:实现待发货的分配记录,都更新为待收货
2、存在“待收货”记录时,显示“一键代收货”按钮
点击一键代收货:实现待发货的分配记录,都更新为“已收货”
我的订货单
存在“待收货”记录时,显示“一键收货”按钮
点击一键收货:实现待发货的分配记录,都更新为“已收货”
*/
- (void) updateorangeView{
//
if(![self isShoworangeView]){
self.orangeView.hidden = YES;
}else{
[self orangeView];
self.orangeView.hidden = NO;
[self.orangeView.button setTitle:self.orangeViewM.showStr forState:UIControlStateNormal];// 发货 购买\n开店数
}
}
- (BOOL)isShoworangeView{
self.orangeViewM = [KNFrontVM new];
if(self.model.isLowerOrder){// 下级
// 1、存在“待发货”记录时,显示“一键发货”按钮// 优先显示
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"receivingState == %@", @"0"];
NSArray *arFiltered = [ self.Detailmodels filteredArrayUsingPredicate:predicate];//以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。
if(arFiltered.count>0){
self.orangeViewM.isShow = YES;
self.orangeViewM.showStr = @"一键\n发货";
self.orangeViewM.type = ReceivingDelieverEnum4Deliever;
return self.orangeViewM.isShow;
}
// 2、存在“待收货”记录时,显示“一键代收货”按钮
predicate = [NSPredicate predicateWithFormat:@"receivingState == %@", @"1"];
arFiltered = [ self.Detailmodels filteredArrayUsingPredicate:predicate];//
if(arFiltered.count>0){
self.orangeViewM.isShow = YES;
self.orangeViewM.showStr = @"一键\n代收货";
self.orangeViewM.type = ReceivingDelieverEnum4ProReceiving;
}
}else{// 本级
// 存在“待收货”记录时,显示“一键收货”按钮
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"receivingState == %@", @"1"];
NSArray *arFiltered = [ self.Detailmodels filteredArrayUsingPredicate:predicate];//以一定的条件(特定日期)过滤maTemp数组,即进行大数据搜索。
if(arFiltered.count>0){
self.orangeViewM.isShow = YES;
self.orangeViewM.showStr = @"一键\n收货";
self.orangeViewM.type = ReceivingDelieverEnum4Receiving;
}
}
return self.orangeViewM.isShow;
}
IV iOS视图置顶的应用
本文以
pod 'PGDatePicker' ,'2.6.9'·
为例子问题:iOS12系统上日期视图被筛选视图遮挡
思路:利用运行时API修改第三方SDK的内部实现
see also
- 推荐使用
[[UIApplication sharedApplication].delegate window]
获取window
在执行
didFinishLaunchingWithOptions:
这个代理方法时,调用[self.window makeKeyAndVisible]
;方法之前,通过[UIApplication sharedApplication].keyWindow 方法获取不到window, 但是无论何时都能获取到delegate.window。
在获取到window时最好使用[[UIApplication sharedApplication].delegate window]获取window
不要在keywindow为nil的时候给window上添加代码,例如添加弹窗。