iOS视图置顶方案

简介: iOS视图置顶方案

前言

视图置顶关于 bringSubviewToFront 和view.layer.zPosition的选择

  1. 使用bringSubviewToFront方法需要在重新刷新界面结构层次的时候调用;
  2. 使用view.layer.zPosition方法会获取不到view的点击事件

应用场景

1 、比如让日期控件置于窗口的最顶层

2、悬浮按钮(支持拖曳)

image.png

I 、bringSubviewToFront的用法

  • 让日期控件置于窗口的最顶层

PGDatePickManager https://kunnan.blog.csdn.net/article/details/119381308

@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、存在“待收货”记录时,显示“一键代收货”按钮 点击一键代收货:实现待发货的分配记录,都更新为“已收货”

image.png

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原文:https://blog.csdn.net/z929118967/article/details/105298711

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;
}

see also

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

  1. 在获取到window时最好使用[[UIApplication sharedApplication].delegate window]获取window
  2. 不要在keywindow为nil的时候给window上添加代码,例如添加弹窗。
目录
相关文章
|
6月前
|
存储 数据建模 数据库
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
105 0
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
4.1字符串加密字符串会暴露APP的很多关键信息,攻击者可以根据界面显示的字符串,快速找到相关逻辑的处理函数,从而进行分析破解。加密字符串可以增加攻击者阅读代码的难度以及根据字符串静态搜索的难度。
|
3月前
|
测试技术 Linux 虚拟化
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
详细的VMware虚拟机安装macOS Big Sur的保姆级教程,包括下载VMware和macOS镜像、图解安装步骤和遇到问题时的解决方案,旨在帮助读者顺利搭建macOS虚拟机环境。
135 3
iOS自动化测试方案(五):保姆级VMware虚拟机安装MacOS
|
3月前
|
测试技术 开发工具 iOS开发
iOS自动化测试方案(三):WDA+iOS自动化测试解决方案
这篇文章是iOS自动化测试方案的第三部分,介绍了在没有MacOS系统条件下,如何使用WDA(WebDriverAgent)结合Python客户端库facebook-wda和tidevice工具,在Windows系统上实现iOS应用的自动化测试,包括环境准备、问题解决和扩展应用的详细步骤。
250 1
iOS自动化测试方案(三):WDA+iOS自动化测试解决方案
|
3月前
|
测试技术 数据安全/隐私保护 iOS开发
iOS自动化测试方案(四):保姆级搭建iOS自动化开发环境
iOS自动化测试方案的第四部分,涵盖了基础环境准备、iPhone虚拟机设置、MacOS虚拟机与iPhone真机的连接,以及扩展问题和代码示例,确保读者能够顺利完成环境搭建并进行iOS自动化测试。
256 0
iOS自动化测试方案(四):保姆级搭建iOS自动化开发环境
|
3月前
|
测试技术 虚拟化 iOS开发
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
这篇文章是iOS自动化测试方案的第二部分,详细介绍了在Xcode开发者工具中构建WebDriverAgent(WDA)应用到iPhone的全过程,包括环境准备、解决构建过程中可能遇到的错误,以及最终成功安装WDA到设备的方法。
182 0
iOS自动化测试方案(二):Xcode开发者工具构建WDA应用到iphone
|
3月前
|
测试技术 开发工具 虚拟化
iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程
这篇文章提供了一份保姆级的教程,指导如何在MacOS虚拟机上安装Xcode,包括环境准备、基础软件安装以及USB扩展插件的使用,以实现iOS自动化测试方案的第一步。
113 0
iOS自动化测试方案(一):MacOS虚拟机保姆级安装Xcode教程
|
6月前
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
ios安全加固 ios 加固方案
89 1
ios安全加固 ios 加固方案
|
6月前
|
安全 数据安全/隐私保护 虚拟化
iOS应用加固方案解析:ipa加固安全技术全面评测
iOS应用加固方案解析:ipa加固安全技术全面评测
121 3
|
6月前
|
移动开发 安全 数据安全/隐私保护
【教程】Ipa Guard为iOS应用提供免费加密混淆方案
概述:使用ios加固工具对ios代码保护,保护ios项目中的核心代码,