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上添加代码,例如添加弹窗。
目录
相关文章
|
3月前
|
存储 数据建模 数据库
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
IOS开发数据存储:什么是 UserDefaults?有哪些替代方案?
39 0
|
5月前
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
4.1字符串加密字符串会暴露APP的很多关键信息,攻击者可以根据界面显示的字符串,快速找到相关逻辑的处理函数,从而进行分析破解。加密字符串可以增加攻击者阅读代码的难度以及根据字符串静态搜索的难度。
|
1月前
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
ios安全加固 ios 加固方案
26 1
ios安全加固 ios 加固方案
|
1月前
|
安全 数据安全/隐私保护 虚拟化
iOS应用加固方案解析:ipa加固安全技术全面评测
iOS应用加固方案解析:ipa加固安全技术全面评测
37 3
|
3月前
|
移动开发 前端开发 数据安全/隐私保护
【教程】Ipa Guard为iOS应用提供免费加密混淆方案
【教程】Ipa Guard为iOS应用提供免费加密混淆方案
25 0
|
3月前
|
安全 数据安全/隐私保护 虚拟化
iOS应用加固方案解析:ipa加固安全技术全面评测
iOS应用加固方案解析:ipa加固安全技术全面评测
71 0
|
3月前
|
移动开发 安全 数据安全/隐私保护
ios安全加固 ios 加固方案
ios安全加固 ios 加固方案
39 0
|
4月前
|
移动开发 安全 数据安全/隐私保护
【教程】Ipa Guard为iOS应用提供免费加密混淆方案
概述:使用ios加固工具对ios代码保护,保护ios项目中的核心代码,
|
6月前
|
安全 Go 数据安全/隐私保护
免费升级到 iOS 17 Developer Beta:官方Apple Store升级方案与爱思助手方法比较
免费升级到 iOS 17 Developer Beta:官方Apple Store升级方案与爱思助手方法比较
223 0
|
9月前
|
存储 iOS开发
iOS主线程耗时检测方案
找出那个拖后腿的凶手
126 1
iOS主线程耗时检测方案