iOS小技能:视图置顶(让一个View至于最顶端, 避免被其他子视图遮盖住) 您所在的位置:网站首页 origin置于顶层 iOS小技能:视图置顶(让一个View至于最顶端, 避免被其他子视图遮盖住)

iOS小技能:视图置顶(让一个View至于最顶端, 避免被其他子视图遮盖住)

2023-09-27 14:52| 来源: 网络整理| 查看: 265

这是我参与11月更文挑战的第8天,活动详情查看:2021最后一次更文挑战。

前言

视图置顶的应用场景:

比如让日期控件置于窗口的最顶层 悬浮按钮(支持拖曳)

在这里插入图片描述

关于 bringSubviewToFront 和view.layer.zPosition的选择

1、使用bringSubviewToFront方法需要在重新刷新界面结构层次的时候调用;

2、使用view.layer.zPosition方法会获取不到view的点击事件

更多内容请关注#小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域。

I 视图置顶 1.1 方案一:bringSubviewToFront的用法 让日期控件置于窗口的最顶层

PGDatePickManager kunnan.blog.csdn.net/article/det…

mp.weixin.qq.com/s/rT4Iu_Fb8…

@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]; 1.2 方案二:同级Layer改变显示顺序 self.view.layer.zPosition self.view.layer.zPosition = MAXFLOAT; 999 II 案例: 悬浮按钮(支持拖曳)

下级订货单关于悬浮按钮的相关需求:

1、存在“待发货”记录时,显示“一键发货”按钮 点击一键发货:实现待发货的分配记录,都更新为待收货 2、存在“待收货”记录时,显示“一键代收货”按钮 点击一键代收货:实现待发货的分配记录,都更新为“已收货” 在这里插入图片描述

2.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]; 2.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 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的实现 // // KNFrontV.m // Housekeeper // // Created by mac on 2021/5/6. // Copyright © 2021 https://kunnan.blog.csdn.net/ . All rights reserved. // #import "KNFrontV.h" @interface KNFrontV () @property (nonatomic,strong) UIView *contentViewForDrag; /** 内容view,命名为contentViewForDrag,因为很多其他开源的第三方的库,里面同样有contentView这个属性 ,这里特意命名为contentViewForDrag以防止冲突 */ @property (nonatomic,assign) CGPoint startPoint; @property (nonatomic,strong) UIPanGestureRecognizer *panGestureRecognizer; @property (nonatomic,assign) CGFloat previousScale; @end @implementation KNFrontV -(UIImageView *)imageView{ if (_imageView==nil) { _imageView = [[UIImageView alloc]init]; _imageView.userInteractionEnabled = YES; _imageView.clipsToBounds = YES; [self.contentViewForDrag addSubview:_imageView]; } return _imageView; } -(UIButton *)button{ if (_button==nil) { _button = [UIButton buttonWithType:UIButtonTypeCustom]; _button.clipsToBounds = YES; _button.userInteractionEnabled = NO; [self.contentViewForDrag addSubview:_button]; } return _button; } -(UIView *)contentViewForDrag{ if (_contentViewForDrag==nil) { _contentViewForDrag = [[UIView alloc]init]; _contentViewForDrag.clipsToBounds = YES; } return _contentViewForDrag; } - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { [self addSubview:self.contentViewForDrag]; [self setUp]; } return self; } - (instancetype)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { [self setUp]; } return self; } -(void)layoutSubviews{ [super layoutSubviews]; if (self.freeRect.origin.x!=0||self.freeRect.origin.y!=0||self.freeRect.size.height!=0||self.freeRect.size.width!=0) { //设置了freeRect--活动范围 }else{ //没有设置freeRect--活动范围,则设置默认的活动范围为父视图的frame self.freeRect = (CGRect){CGPointZero,self.superview.bounds.size}; } _imageView.frame = (CGRect){CGPointZero,self.bounds.size}; _button.frame = (CGRect){CGPointZero,self.bounds.size}; self.contentViewForDrag.frame = (CGRect){CGPointZero,self.bounds.size}; } -(void)setUp{ self.dragEnable = YES;//默认可以拖曳 self.clipsToBounds = YES; self.isKeepBounds = NO; self.backgroundColor = [UIColor lightGrayColor]; UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickDragView)]; [self addGestureRecognizer:singleTap]; //添加移动手势可以拖动 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]; } //-(BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{ // return self.dragEnable; //} /** 拖动事件 @param pan 拖动手势 */ -(void)dragAction:(UIPanGestureRecognizer *)pan{ if(self.dragEnable==NO)return; switch (pan.state) { case UIGestureRecognizerStateBegan:{//开始拖动 if (self.beginDragBlock) { self.beginDragBlock(self); } //注意完成移动后,将translation重置为0十分重要。否则translation每次都会叠加 [pan setTranslation:CGPointZero inView:self]; //保存触摸起始点位置 self.startPoint = [pan translationInView:self]; break; } case UIGestureRecognizerStateChanged:{//拖动中 //计算位移 = 当前位置 - 起始位置 if (self.duringDragBlock) { self.duringDragBlock(self); } CGPoint point = [pan translationInView:self]; float dx; float dy; switch (self.dragDirection) { case WMDragDirectionAny: dx = point.x - self.startPoint.x; dy = point.y - self.startPoint.y; break; case WMDragDirectionHorizontal: dx = point.x - self.startPoint.x; dy = 0; break; case WMDragDirectionVertical: dx = 0; dy = point.y - self.startPoint.y; break; default: dx = point.x - self.startPoint.x; dy = point.y - self.startPoint.y; break; } //计算移动后的view中心点 CGPoint newCenter = CGPointMake(self.center.x + dx, self.center.y + dy); //移动view self.center = newCenter; // 注意完成上述移动后,将translation重置为0十分重要。否则translation每次都会叠加 [pan setTranslation:CGPointZero inView:self]; break; } case UIGestureRecognizerStateEnded:{//拖动结束 [self keepBounds]; if (self.endDragBlock) { self.endDragBlock(self); } break; } default: break; } } //点击事件 -(void)clickDragView{ if (self.clickDragViewBlock) { self.clickDragViewBlock(self); } } //黏贴边界效果 - (void)keepBounds{ //中心点判断 float centerX = self.freeRect.origin.x+(self.freeRect.size.width - self.frame.size.width)/2; CGRect rect = self.frame; if (self.isKeepBounds==NO) {//没有黏贴边界的效果 if (self.frame.origin.x < self.freeRect.origin.x) { CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:@"leftMove" context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; rect.origin.x = self.freeRect.origin.x; self.frame = rect; [UIView commitAnimations]; } else if(self.freeRect.origin.x+self.freeRect.size.width < self.frame.origin.x+self.frame.size.width){ CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:@"rightMove" context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; rect.origin.x = self.freeRect.origin.x+self.freeRect.size.width-self.frame.size.width; self.frame = rect; [UIView commitAnimations]; } }else if(self.isKeepBounds==YES){//自动粘边 if (self.frame.origin.x< centerX) { CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:@"leftMove" context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; rect.origin.x = self.freeRect.origin.x; self.frame = rect; [UIView commitAnimations]; } else { CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:@"rightMove" context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; rect.origin.x =self.freeRect.origin.x+self.freeRect.size.width - self.frame.size.width; self.frame = rect; [UIView commitAnimations]; } } if (self.frame.origin.y < self.freeRect.origin.y) { CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:@"topMove" context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; rect.origin.y = self.freeRect.origin.y; self.frame = rect; [UIView commitAnimations]; } else if(self.freeRect.origin.y+self.freeRect.size.height< self.frame.origin.y+self.frame.size.height){ CGContextRef context = UIGraphicsGetCurrentContext(); [UIView beginAnimations:@"bottomMove" context:context]; [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; [UIView setAnimationDuration:0.5]; rect.origin.y = self.freeRect.origin.y+self.freeRect.size.height-self.frame.size.height; self.frame = rect; [UIView commitAnimations]; } } @end 2.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; } see also

更多内容请关注#小程序:iOS逆向,只为你呈现有价值的信息,专注于移动端技术研究领域。

iOS视图置顶的应用:适配iOS12系统上日期控件被筛选视图遮挡问题

mp.weixin.qq.com/s/rT4Iu_Fb8…

推荐使用[[UIApplication sharedApplication].delegate window]获取window

在执行 didFinishLaunchingWithOptions: 这个代理方法时,调用[self.window makeKeyAndVisible];方法之前,通过[UIApplication sharedApplication].keyWindow 方法获取不到window, 但是无论何时都能获取到delegate.window。

在获取到window时最好使用[[UIApplication sharedApplication].delegate window]获取window

不要在keywindow为nil的时候给window上添加代码,例如添加弹窗。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有