This is the 8th day of my participation in the November Gwen Challenge. Check out the event details: The last Gwen Challenge 2021.
preface
Application scenarios of view top:
- For example, put the date control at the top of the window
- Hover button (support drag)
BringSubviewToFront and View.layer. zPosition
The bringSubviewToFront method needs to be called when the interface structure level is refreshed.
2, using the view.layer.zPosition method will not get the view click event
For more, check out # Applets: iOS Reverse, which presents valuable information only for you, focusing on the mobile technology research field.
View I is at the top
1.1 Solution 1: Usage of bringSubviewToFront
- Place the date control at the top of the window
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];
}
Copy the code
- listTableView
[self.superview.window addSubview:self.listTableView];
/// avoid being covered by other subviews
[self.superview.window bringSubviewToFront:self.listTableView];
CGRect frame = CGRectMake(CGRectGetMinX(self.frame), CGRectGetMaxY(self.frame), CGRectGetWidth(self.frame), 0);
// Coordinate conversion
CGRect convertRect= [self.superview convertRect:frame toView:self.superview.window];
[self.listTableView setFrame:convertRect];
Copy the code
1.2 Scheme 2: Change the display order of the Layer at the same level
- self.view.layer.zPosition
self.view.layer.zPosition = MAXFLOAT; 999
Copy the code
Case II: Hover button (support drag)
Related requirements of the hover button in the sub-order:
1. When there is a record of “Waiting for delivery”, the “one-click delivery” button will be displayed
Click one-button delivery: Realize the distribution record of pending goods and update it to be received. 2. When there is “pending goods” record, display “one-button collecting goods” button: Realize the distribution record of pending goods and update it to “received goods”
2.1 the principle
1, bringSubviewToFront 2, add move gesture can drag 3, use predicate to determine whether there is a specific condition of the data
// Add move gestures that can be dragged
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];
Copy the code
2.2 usage
@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:@" one-click \n delivery" forState:UIControlStateNormal];// Shipping purchase \n number of stores
tmpView.backgroundColor = rgb(255.54.87);
//
// tmpView.layer.cornerRadius = 14; // layoutsubview
// Set image display mode 1:
// tmpView.imageView.image = [UIImage imageNamed:@"icon_dayin"];
// Set image display mode 2:
// [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{
}
Copy the code
- The definition of 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
// Drag the direction of the view
typedef NS_ENUM(NSInteger, KNDragDirection) {
KNDragDirectionAny, /**< any direction */
KNDragDirectionHorizontal, /**< horizontal */
KNDragDirectionVertical, /**< vertical */
};
@interface KNFrontV : UIView
/** can be dragged, the default is YES YES, can drag NO, cannot drag */
@property (nonatomic.assign) BOOL dragEnable;
/** Active range, default is within the frame range of the superview (because it cannot be clicked after dragging out the superview) if set, it will be active within the given frame range if not set, it will be active within the superview range note: Setting frame to 0,0,0,0 indicates that the active range is the default superview frame. If you want to disable frame, set dragEnable to NO */
@property (nonatomic.assign) CGRect freeRect;
/** Drag direction, default is any, any direction */
@property (nonatomic.assign) KNDragDirection dragDirection;
Note: It is best not to use an internal imageView and button */
@property (nonatomic.strong) UIImageView *imageView;
Note: It is best not to use an internal imageView and button */ at the same time
@property (nonatomic.strong) UIButton *button;
IsKeepBounds = NO, it will automatically paste bounds to the nearest bounds isKeepBounds = NO, it will not paste bounds to the nearest bounds, it is free, Follow the finger to any position, but you cannot drag it out of the given range frame */
@property (nonatomic.assign) BOOL isKeepBounds;
/** Click the callback block */
@property (nonatomic.copy) void(^clickDragViewBlock)(KNFrontV *dragView);
/** Start dragging the callback block */
@property (nonatomic.copy) void(^beginDragBlock)(KNFrontV *dragView);
/** Drag the callback block */
@property (nonatomic.copy) void(^duringDragBlock)(KNFrontV *dragView);
/** Completes the drag callback block */
@property (nonatomic.copy) void(^endDragBlock)(KNFrontV *dragView);
@end
NS_ASSUME_NONNULL_END
Copy the code
- The realization of the 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(a)
@property (nonatomic.strong) UIView *contentViewForDrag;
/** contentView, named contentViewForDrag, because many other open source third-party libraries also have a contentView property, named contentViewForDrag to prevent collisions */
@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) {
// set freeRect-- scope of activity
}else{
If freeRect-- active range is not set, the default active range is set to the frame of the superview
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;// Drag is available by default
self.clipsToBounds = YES;
self.isKeepBounds = NO;
self.backgroundColor = [UIColor lightGrayColor];
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(clickDragView)];
[self addGestureRecognizer:singleTap];
// Add move gestures that can be dragged
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;
/ /}
/** drag event @param pan drag gesture */- (void)dragAction:(UIPanGestureRecognizer *)pan{
if(self.dragEnable==NO)return;
switch (pan.state) {
case UIGestureRecognizerStateBegan: {// Start dragging
if (self.beginDragBlock) {
self.beginDragBlock(self);
}
// Note that it is important to reset translation to 0 after the move is complete. Otherwise the translation will add up every time
[pan setTranslation:CGPointZero inView:self];
// Save the position of the touch starting point
self.startPoint = [pan translationInView:self];
break;
}
case UIGestureRecognizerStateChanged: {/ / drag
// Calculate displacement = current position - start position
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;
}
// Calculate the center point of the view after the move
CGPoint newCenter = CGPointMake(self.center.x + dx, self.center.y + dy);
/ / move the view
self.center = newCenter;
// Note that it is important to reset translation to 0 after the above move. Otherwise the translation will add up every time
[pan setTranslation:CGPointZero inView:self];
break;
}
case UIGestureRecognizerStateEnded: {// Drag to end
[self keepBounds];
if (self.endDragBlock) {
self.endDragBlock(self);
}
break;
}
default:
break; }}// Click the event- (void)clickDragView{
if (self.clickDragViewBlock) {
self.clickDragViewBlock(self); }}// Paste the boundary effect
- (void)keepBounds{
// Center judgment
float centerX = self.freeRect.origin.x+(self.freeRect.size.width - self.frame.size.width)/2;
CGRect rect = self.frame;
if (self.isKeepBounds==NO) {// There is no paste edge effect
if (self.frame.origin.x < self.freeRect.origin.x) {
CGContextRef context = UIGraphicsGetCurrentContext(a); [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(a); [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;
[UIViewcommitAnimations]; }}else if(self.isKeepBounds==YES) {// Automatic adhesive edge
if (self.frame.origin.x< centerX) {
CGContextRef context = UIGraphicsGetCurrentContext(a); [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(a); [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;
[UIViewcommitAnimations]; }}if (self.frame.origin.y < self.freeRect.origin.y) {
CGContextRef context = UIGraphicsGetCurrentContext(a); [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(a); [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;
[UIViewcommitAnimations]; }}@end
Copy the code
2.3 the use ofNSPredicate
Determine whether there is a record of goods pending receipt
/** Lower order 1, there is "to be shipped" record, display "one key delivery" button click one key delivery: to achieve the distribution record of the goods to be shipped, are updated to be received 2, there is "to be received" record, display "one key delivery" button click one key delivery: To realize the distribution record of pending goods, all updated as "received goods" my order exists "pending goods" record, display "one-button receive goods" button click one-button receive goods: to realize the distribution record of pending goods, all updated as "received goods" */
- (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];// Shipping purchase \n number of stores}} - (BOOL)isShoworangeView{
self.orangeViewM = [KNFrontVM new];
if(self.model.isLowerOrder){/ / at a lower level
// 1. When "Waiting for delivery" record exists, "one-click delivery" button will be displayed // Preferentially displayed
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"receivingState == %@".@ "0"];
NSArray *arFiltered = [ self.Detailmodels filteredArrayUsingPredicate:predicate];// Filter the maTemp array with a certain criteria (specific date), i.e., do a big data search.
if(arFiltered.count>0) {self.orangeViewM.isShow = YES;
self.orangeViewM.showStr = @" one-click \n delivery";
self.orangeViewM.type = ReceivingDelieverEnum4Deliever;
return self.orangeViewM.isShow;
}
// 2. If "Waiting for delivery" record exists, the "one-button collection" button will be displayed
predicate = [NSPredicate predicateWithFormat:@"receivingState == %@".@ "1"];
arFiltered = [ self.Detailmodels filteredArrayUsingPredicate:predicate];//
if(arFiltered.count>0) {self.orangeViewM.isShow = YES;
self.orangeViewM.showStr = @" one key \n collect goods";
self.orangeViewM.type = ReceivingDelieverEnum4ProReceiving; }}else{/ / at the corresponding level
// The "one click to receive" button is displayed when "Waiting to receive" record exists
NSPredicate* predicate = [NSPredicate predicateWithFormat:@"receivingState == %@".@ "1"];
NSArray *arFiltered = [ self.Detailmodels filteredArrayUsingPredicate:predicate];// Filter the maTemp array with a certain criteria (specific date), i.e., do a big data search.
if(arFiltered.count>0) {self.orangeViewM.isShow = YES;
self.orangeViewM.showStr = @" one key \n receive goods";
self.orangeViewM.type = ReceivingDelieverEnum4Receiving; }}return self.orangeViewM.isShow;
}
Copy the code
see also
For more, check out # Applets: iOS Reverse, which presents valuable information only for you, focusing on the mobile technology research field.
IOS view top application: adapt to iOS12 system date control is screened view occlusion problem
Mp.weixin.qq.com/s/rT4Iu_Fb8…
- It is recommended to use
[[UIApplication sharedApplication].delegate window]
Access to the window
In performing didFinishLaunchingWithOptions: when the proxy method, called window makeKeyAndVisible] [self.; Before the [UIApplication sharedApplication]. KeyWindow method, the window cannot be obtained, but delegate.window can be obtained at any time.
The best way to get a window is to use [[UIApplication sharedApplication]. Delegate Window]
Don’t add code to a window if keyWindow is nil, such as popovers.