iOS 懸浮球效果實現,懸浮按鈕,拖拽,貼邊,隱藏,顯示,旋轉屏幕適配

来源:https://www.cnblogs.com/longyongping/archive/2022/08/19/16601562.html
-Advertisement-
Play Games

1.懸浮球與設備劉海的安全距離無論是橫屏還是豎屏,懸浮球距離有劉海的一邊會留出安全距離設備方向的上下兩邊,也有安全距離 2.貼邊吸附方向和距離懸浮球只能貼設備方向的左右兩邊,需要貼上下兩邊自行調整距離邊緣的數值自行調整 3.切換橫豎屏,懸浮球自適應懸浮球位置切換橫豎屏後,等比例轉換的。 4.隱藏和顯 ...


1.懸浮球與設備劉海的安全距離
無論是橫屏還是豎屏,懸浮球距離有劉海的一邊會留出安全距離
設備方向的上下兩邊,也有安全距離

2.貼邊吸附方向和距離
懸浮球只能貼設備方向的左右兩邊,需要貼上下兩邊自行調整
距離邊緣的數值自行調整

3.切換橫豎屏,懸浮球自適應
懸浮球位置切換橫豎屏後,等比例轉換的。

4.隱藏和顯示
拖到屏幕中間ImageView範圍內可以隱藏懸浮窗,在範圍內會由藍色變紅色,可自定義圖片或者大小

使用說明:

懸浮球點擊事件代理方法
- (void)suspendViewButtonClick:(UIButton*)sender;
懸浮球在ImageView範圍內提示是否隱藏懸浮窗
- (void)showHideAlertView;
顯示懸浮窗
- (void)showSuspendView;
隱藏懸浮窗
- (void)dismissSuspendView;

 

demo下載地址:

https://github.com/longypjiangxi/XLUIDragButton

簡書地址:

https://www.jianshu.com/p/30aeb1d506d3

 

 

#import <UIKit/UIKit.h>
 
NS_ASSUME_NONNULL_BEGIN
@protocol SuspendViewDelegate <NSObject>
- (void)suspendViewButtonClick:(UIButton*)sender;
- (void)showHideAlertView;
@end
@interface SuspendView : UIView
{
    CGPoint lastPoint;/**存儲懸浮球最後的移動完位置*/
    BOOL isChangePosition;/**懸浮球是否改變了位置*/
    CGFloat changeHig;//按鈕高度位置比例
    CGFloat changeWid;//按鈕寬度位置比例
 
}
@property (nonatomic, retain) UIButton *btn;/**<#name#>*/
@property (nonatomic, strong) NSTimer *_Nullable timer;
@property (nonatomic, retain) UIImageView *imageView;
@property (nonatomic, assign) UIInterfaceOrientation orientation;
@property (nonatomic, weak) id<SuspendViewDelegate> delegate;
- (void)showSuspendView;
- (void)dismissSuspendView;
@end
 
NS_ASSUME_NONNULL_END





#import "SuspendView.h"
 
#define SCREEN_WIDTH    [UIScreen mainScreen].bounds.size.width
#define SCREEN_HEIGHT   [UIScreen mainScreen].bounds.size.height
#define ViewSize 50
#define KHeightFit(w)           (((w) / 667.0) * SCREEN_HEIGHT)
 
#define LRString [NSString stringWithFormat:@"%s", __FILE__].lastPathComponent
#define DLog(...) {\
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];\
[dateFormatter setDateFormat:@"YYYY-MM-dd hh:mm:ss"];\
NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];\
printf("%s %s 第%d行:%s\n\n",[dateString UTF8String],[LRString UTF8String] ,__LINE__, [[NSString stringWithFormat:__VA_ARGS__] UTF8String]);}
 
@implementation SuspendView
 
 
- (instancetype)init{
    self = [super init];
    if (self) {
        self.backgroundColor = UIColor.redColor;
        self.layer.masksToBounds = YES;
        self.layer.cornerRadius = ViewSize/2;
        self.alpha = 0.5;
        
        //獲取設備方向
        self.orientation = [[UIApplication sharedApplication] statusBarOrientation];
        if (self.orientation == UIInterfaceOrientationLandscapeRight){//橫向home鍵在右側,設備左轉,劉海在左邊
            self.frame = CGRectMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, KHeightFit(80) + ViewSize/2, ViewSize, ViewSize);
        }else{
            self.frame = CGRectMake(SCREEN_WIDTH - ViewSize/2, KHeightFit(80) + ViewSize/2, ViewSize, ViewSize);
        }
        
        self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
        self.btn.frame = CGRectMake(5, 5, 40, 40);
        self.btn.backgroundColor = UIColor.greenColor;
        self.btn.layer.cornerRadius = 20;
        [self.btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:self.btn];
        //獲取按鈕與屏幕初始寬高比例
        [self changeCoordinateScale];
        //是否改變了懸浮窗初始位置
        isChangePosition = NO;
        
        //添加手勢
        UIPanGestureRecognizer *panRcognize=[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
        [panRcognize setMinimumNumberOfTouches:1];
        [panRcognize setEnabled:YES];
        [panRcognize delaysTouchesEnded];
        [panRcognize cancelsTouchesInView];
        [self addGestureRecognizer:panRcognize];
       
        //監聽屏幕旋轉
        [[NSNotificationCenter defaultCenter] addObserver:self
                                                 selector:@selector(didChangeStatusBarOrientation)
                                                     name:UIApplicationDidChangeStatusBarOrientationNotification
                                                   object:nil];
    }
    return self;
}
 
- (void)didChangeStatusBarOrientation {
 
    self.orientation = [UIApplication sharedApplication].statusBarOrientation;
    self.imageView.frame = CGRectMake((SCREEN_WIDTH - 50)/2, (SCREEN_HEIGHT - 50)/2, 50, 50);
//    DLog(@"===%zd=====%zd",[[UIDevice currentDevice] orientation],[UIApplication sharedApplication].statusBarOrientation);
    //請註意,UIInterfaceOrientationAndScapeLeft等於UIDeviceOrientation AndScapeRight(反之亦然)。
    //這是因為向左旋轉設備需要向右旋轉內容。
    /**
     UIInterfaceOrientationUnknown            = UIDeviceOrientationUnknown,
     UIInterfaceOrientationPortrait           = UIDeviceOrientationPortrait,
     UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
     UIInterfaceOrientationLandscapeLeft      = UIDeviceOrientationLandscapeRight,
     UIInterfaceOrientationLandscapeRight     = UIDeviceOrientationLandscapeLeft
     */
    
    /**
     UIDeviceOrientationUnknown,
     UIDeviceOrientationPortrait,            // Device oriented vertically, home button on the bottom
     UIDeviceOrientationPortraitUpsideDown,  // Device oriented vertically, home button on the top
     UIDeviceOrientationLandscapeLeft,       // Device oriented horizontally, home button on the right
     UIDeviceOrientationLandscapeRight,      // Device oriented horizontally, home button on the left
     UIDeviceOrientationFaceUp,              // Device oriented flat, face up
     UIDeviceOrientationFaceDown             // Device oriented flat, face down
     */
    switch ([UIDevice currentDevice].orientation)
    {
        case UIDeviceOrientationPortraitUpsideDown:
           // DLog(@"設備倒垂直,home在上")
            [self locationChange:@"Down"];
            break;
        case UIDeviceOrientationLandscapeLeft:{
          //  DLog(@"設備橫屏,左轉,home在右")
            [self locationChange:@"left"];
        }
            break;
        case UIDeviceOrientationLandscapeRight:{
//            DLog(@"設備橫屏,右轉,home在左")
            [self locationChange:@"right"];
        }
            break;
        case UIDeviceOrientationPortrait:{
//            DLog(@"設備垂直,home在下");
            [self locationChange:@"Portrait"];
        }
            break;
        default:
            break;
    }
}
//根據屏幕寬高改變按鈕位置比例
- (void)locationChange:(NSString *)message{
//    NSLog(@"changeHig == %f,changeWid == %f",changeHig,changeWid);
    if (SCREEN_HEIGHT > SCREEN_WIDTH) {
        //屏幕方向上
        if ([message isEqualToString:@"Portrait"]) {
            NSLog(@"安全區在上邊");
            self.center = CGPointMake(changeWid * SCREEN_WIDTH, changeHig * SCREEN_HEIGHT);
        }else{//下
            NSLog(@"安全區在下邊");
            self.center = CGPointMake(changeWid * SCREEN_WIDTH, changeHig * SCREEN_HEIGHT - [self vg_safeDistanceTop]);
        }
    }else{
        if ([message isEqualToString:@"left"]) {//左
            NSLog(@"安全區在左邊");
            self.center = CGPointMake(changeWid * SCREEN_WIDTH + [self vg_safeDistanceTop] + ViewSize, changeHig * SCREEN_HEIGHT);
        }else{//右
            NSLog(@"安全區在右邊");
            self.center = CGPointMake(changeWid * SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize, changeHig * SCREEN_HEIGHT);
        }
    }
//    NSLog(@"lastPoint == %@, self.center == %@",NSStringFromCGPoint(lastPoint),NSStringFromCGPoint(self.center));
 
    [self changeCoordinateScale];
    
}
//旋轉屏幕後修改懸浮窗相對於屏幕的寬高比例以及坐標位置
- (void)changeCoordinateScale{
    changeHig = self.center.y/SCREEN_HEIGHT;
    changeWid = self.center.x/SCREEN_WIDTH;
    //判斷設備旋轉方向
    if (self.orientation == UIInterfaceOrientationLandscapeRight) {//橫向home鍵在右側,設備左轉,劉海在左邊,劉海在左邊
        //判斷懸浮窗坐標x在屏幕的左邊還是右邊
        if (self.center.x > SCREEN_WIDTH/2) {//大於中心x,在右邊
            //修改懸浮窗的坐標在最右邊
            self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
        }else{
            //修改懸浮窗的坐標在最左邊
            self.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20, self.center.y);
        }
    }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//橫向home鍵在左側,設備右轉,劉海在右邊
        if (self.center.x > SCREEN_WIDTH/2) {//大於中心x,在右邊
            //修改懸浮窗的坐標在最右邊,留出頂部安全距離
            self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, self.center.y);
        }else{
            //修改懸浮窗的坐標在最左邊
            self.center = CGPointMake(0, self.center.y);
        }
    }else{
        //大於中心x,在右邊
        if (self.center.x > SCREEN_WIDTH/2) {
            self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
        }else{
            self.center = CGPointMake(0, self.center.y);
        }
    }
//    NSLog(@"changeHig == %f,changeWid == %f",changeHig,changeWid);
//    NSLog(@"設備寬度 == %f, 設備高度== %f, 按鈕坐標==%@",SCREEN_WIDTH,SCREEN_HEIGHT,NSStringFromCGPoint(self.center));
}
- (void)showSuspendView{
    self.hidden = NO;
    NSLog(@"顯示懸浮窗");
}
- (void)dismissSuspendView{
    self.hidden = YES;
    NSLog(@"隱藏懸浮窗");
}
/// 懸浮窗按鈕點擊放法
/// @param button 點擊之後完全顯示懸浮窗,改變按鈕位置
- (void)btnClick:(UIButton *)button{
    if (self.delegate && [self.delegate respondsToSelector:@selector(suspendViewButtonClick:)]) {
        [self.delegate suspendViewButtonClick:button];
    }
//    DLog(@"lastPoint == %@",NSStringFromCGPoint(lastPoint));
    //如果沒有改變過位置,lastPoint初始值(0,0)
    //判斷是否移動過懸浮窗
    if (!isChangePosition) {
        //懸浮窗初始位置在右上角,只有屏幕向右旋轉,才需要留出iphone劉海的位置,設備左轉劉海在左邊,所以不需要做判斷
        if (self.orientation == UIInterfaceOrientationLandscapeLeft) {//橫向home鍵在左側,設備右轉,劉海在右邊
            //修改點擊後懸浮窗的位置,留出安全距離
            [UIView animateWithDuration:0.5 animations:^{
                self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20 - 20, self.center.y);
            }];
        }else{
            [UIView animateWithDuration:0.5 animations:^{
                self.center = CGPointMake(SCREEN_WIDTH - ViewSize, self.center.y);
            }];
        }
    }else{
//        判斷最後的坐標是靠左還是靠右
        if (self.orientation == UIInterfaceOrientationLandscapeRight) {//橫向home鍵在右側,設備左轉,劉海在左邊
            if (self.center.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(SCREEN_WIDTH - ViewSize, self.center.y);
                }];
            }else{
                //左轉劉海在左邊,留出安全距離
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20 + 20, self.center.y);
                }];
            }
        }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//橫向home鍵在左側,設備右轉,劉海在右邊
            if (self.center.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側,留出劉海安全距離
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20 - 20, self.center.y);
                }];
            }else{//左側顯示
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(ViewSize, self.center.y);
                }];
            }
        }else{
            if (self.center.x < SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(ViewSize, self.center.y);
                }];
            }else{
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(SCREEN_WIDTH - ViewSize, self.center.y);
                }];
            }
        }
        
    }
    
    self.alpha = 1;
    //三秒後隱藏懸浮窗,貼邊展示一半
    self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:NO];
}
 
- (void)timerAction{
    //隱藏懸浮球
    self.alpha = 0.5;
    //判斷是否移動過懸浮窗
    if (!isChangePosition) {
        //懸浮窗初始位置在右上角,只有屏幕向右旋轉,才需要留出iphone劉海的位置,設備左轉劉海在左邊,所以不需要做判斷
        if (self.orientation == UIInterfaceOrientationLandscapeLeft) {//橫向home鍵在左側,設備右轉,劉海在右邊
            [UIView animateWithDuration:0.5 animations:^{
                self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, self.center.y);
            }];
        }else{
            [UIView animateWithDuration:0.5 animations:^{
                self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
            }];
        }
       
    }else{
        if (self.orientation == UIInterfaceOrientationLandscapeRight) {//橫向home鍵在右側,設備左轉,劉海在左邊
            if (self.center.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
                }];
            }else{
                //懸浮窗在屏幕左側,留出劉海安全距離
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20, self.center.y);
                }];
            }
        }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//橫向home鍵在左側,設備右轉,劉海在右邊
            if (self.center.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                //懸浮窗在屏幕左側,留出劉海安全距離
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, self.center.y);
                }];
            }else{
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(0, self.center.y);
                }];
            }
            
        }else{
            if (self.center.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
                }];
            }else{
                [UIView animateWithDuration:0.5 animations:^{
                    self.center = CGPointMake(0, self.center.y);
                }];
            }
            
        }
    }
    //銷毀定時器
    [self.timer invalidate];
    self.timer = nil;
}
 
 
/// pan手勢
/// @param recognizer recognizer description
- (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer
{
    //移動狀態
    UIGestureRecognizerState recState =  recognizer.state;
    isChangePosition = YES;
    
    switch (recState) {
        case UIGestureRecognizerStateBegan:
            self.alpha = 1;
            self.imageView.hidden = NO;
            break;
        case UIGestureRecognizerStateChanged://移動中
        {
            self.alpha = 1;
            CGPoint translation = [recognizer translationInView:self];
            recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
            
            CGRect rect = [self convertRect:self.frame toView:self];
            if (CGRectIntersectsRect(self.imageView.frame, rect)) {//在範圍內
                self.imageView.backgroundColor = UIColor.redColor;
            }else{
                self.imageView.backgroundColor = UIColor.blueColor;
            }
        }
            break;
        case UIGestureRecognizerStateEnded://移動結束
        {
            self.alpha = 0.5;
            CGPoint stopPoint = CGPointMake(0, SCREEN_HEIGHT / 2);
            //判斷按鈕貼靠在屏幕的左邊還是右邊
            if (recognizer.view.center.x < SCREEN_WIDTH / 2) {
                stopPoint = CGPointMake(ViewSize/2, recognizer.view.center.y);
            }else{
                //貼靠在右邊
                stopPoint = CGPointMake(SCREEN_WIDTH - ViewSize/2,recognizer.view.center.y);
            }
            DLog(@"stopPoint == %@",NSStringFromCGPoint(stopPoint));
            
            if (stopPoint.y - ViewSize/2 <= 0) {
                DLog(@"上");
                //加上電池欄的高度
                if (stopPoint.x - ViewSize/2 <= SCREEN_WIDTH/2) {
                    stopPoint = CGPointMake(0, stopPoint.y + [self vg_safeDistanceTop] + ViewSize);
                    DLog(@"左上");
                }else{
                    DLog(@"右上");
                    stopPoint = CGPointMake(SCREEN_WIDTH, stopPoint.y + [self vg_safeDistanceTop] + ViewSize);
                }
            }
            //如果按鈕超出屏幕邊緣
            if (stopPoint.y + ViewSize + 20 >= SCREEN_HEIGHT) {
                DLog(@"下");
                //減去底部狀態欄的高度
                if (stopPoint.x - ViewSize/2 <= SCREEN_WIDTH/2) {
                    DLog(@"左下");
                    stopPoint = CGPointMake(0, stopPoint.y - [self vg_safeDistanceBottom] - ViewSize/2);
                }else{
                    DLog(@"右下");
                    stopPoint = CGPointMake(SCREEN_WIDTH, stopPoint.y - [self vg_safeDistanceBottom] - ViewSize/2);
                }
//                DLog(@"超出屏幕下方");
            }
            
            if (stopPoint.x - ViewSize/2 <= 0) {
                DLog(@"左");
//                stopPoint = CGPointMake(ViewSize/2, stopPoint.y);
                //縮進去一半
                stopPoint = CGPointMake(0, stopPoint.y);
            }
            if (stopPoint.x + ViewSize/2 >= SCREEN_WIDTH) {
                DLog(@"右");
//                stopPoint = CGPointMake(SCREEN_WIDTH - ViewSize/2, stopPoint.y);
                stopPoint = CGPointMake(SCREEN_WIDTH, stopPoint.y);
            }
            
            //保存最後的位置
            lastPoint = stopPoint;
           
            //隱藏懸浮球
            CGRect rect = [self convertRect:self.frame toView:self];
            if (CGRectIntersectsRect(self.imageView.frame, rect)) {//在範圍內
                DLog(@"懸浮窗在中心imageview內,提示是否隱藏懸浮窗");
//                [self showAlertView];
                [self.delegate showHideAlertView];
            }
//            NSLog(@"self.orientation == %ld",(long)self.orientation);
            if (self.orientation == UIInterfaceOrientationLandscapeRight) {//橫向home鍵在右側,設備左轉,劉海在左邊
                if (stopPoint.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                    [UIView animateWithDuration:0.5 animations:^{
                        recognizer.view.center = CGPointMake(SCREEN_WIDTH, stopPoint.y);
                    }];
                }else{
                    //懸浮窗在屏幕左側,留出劉海安全距離
                    [UIView animateWithDuration:0.5 animations:^{
                        recognizer.view.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20, stopPoint.y);
                    }];
                }
            }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//橫向home鍵在左側,設備右轉,劉海在右邊
                if (stopPoint.x > SCREEN_WIDTH/2) {//懸浮窗在屏幕右側
                    //懸浮窗在屏幕左側,留出劉海安全距離
                    [UIView animateWithDuration:0.5 animations:^{
                        recognizer.view.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, stopPoint.y);
                    }];
                }else{
                    [UIView animateWithDuration:0.5 animations:^{
                        recognizer.view.center = CGPointMake(0, stopPoint.y);
                    }];
                }
                
            }else{
                [UIView animateWithDuration:0.5 animations:^{
                    recognizer.view.center = stopPoint;
                }];
            }
            [self changeCoordinateScale];
        
            self.imageView.hidden = YES;
            
        }
            break;
            
        default:
            break;
    }
    
    [recognizer setTranslation:CGPointMake(0, 0) inView:self];
}
 
//獲取頭部安全區高度
- (CGFloat)vg_safeDistanceTop {
    if (@available(iOS 13.0, *)) {
        NSSet *set = [UIApplication sharedApplication].connectedScenes;
        UIWindowScene *windowScene = [set anyObject];
        UIWindow *window = windowScene.windows.firstObject;
        return window.safeAreaInsets.top;
    } else if (@available(iOS 11.0, *)) {
        UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
        return window.safeAreaInsets.top;
    }
    return 0;
}
 
//獲取設備底部安全區高度
- (CGFloat)vg_safeDistanceBottom {
    if (@available(iOS 13.0, *)) {
        NSSet *set = [UIApplication sharedApplication].connectedScenes;
        UIWindowScene *windowScene = [set anyObject];
        UIWindow *window = windowScene.windows.firstObject;
        return window.safeAreaInsets.bottom;
    } else if (@available(iOS 11.0, *)) {
        UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
        return window.safeAreaInsets.bottom;
    }
    return 0;
}
 
- (UIImageView *)imageView{
    if (!_imageView) {
        _imageView = [[UIImageView alloc]initWithFrame:CGRectMake((SCREEN_WIDTH - 50)/2, (SCREEN_HEIGHT - 50)/2, 50, 50)];
        _imageView.backgroundColor = UIColor.blueColor;
        _imageView.hidden = YES;
        [[UIApplication sharedApplication].keyWindow addSubview:_imageView];
    }
    return _imageView;
}
 
@end

 

 

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、前言 在我們一般的web系統中必不可少的就是許可權的配置,也有經典的RBAC許可權模型,是基於角色的許可權控制。這是目前最常被開發者使用也是相對易用、通用許可權模型。當然SpringSecurity已經實現了許可權的校驗,但是不夠靈活,我們可以自己寫一下校驗條件,從而更加的靈活! 很多開源框架中也是用的比 ...
  • 數組實戰,程式員的基本功。 實戰需求: 輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有奇數位於數組的前半部分,所有偶數位於數組的後半部分。 實戰思路: 1、先聲明兩個數組,分別用於存儲奇數和偶數, 2、然後遍歷待排序的數組,根據是否可以被 2 整除,將數據分發到偶數和奇數數組, 3 ...
  • 大家好,我是痞子衡,是正經搞技術的痞子。今天痞子衡給大家分享的是IAR下調試信息輸出機制之半主機(Semihosting)。 在嵌入式世界里,輸出列印信息是一種非常常用的輔助調試手段,藉助列印信息,我們可以比較容易地定位和分析程式問題。在嵌入式應用設計里實現列印信息輸出的方式有很多,本系列將以 IA ...
  • Android逆向之脫殼 脫殼一般指去除加固包。 已知脫殼有三種手段: Xposed:例反射大師 VM:例blackdex Frida 每個手段都有不同的用法。 一般步驟 去除簽名驗證(大部分加殼都有驗證,推薦用np的modex3.0,推薦選精簡包) 脫殼 反射大師:需要xp框架。點擊反射大師,選擇 ...
  • 作者 魏國梁:位元組 Flutter Infra 工程師, Flutter Member,長期專註 Flutter 引擎技術 袁 欣:位元組 Flutter Infra 工程師, 長期關註渲染技術發展 謝昊辰:位元組 Flutter Infra 工程師,Impeller Contributor Impel ...
  • 哪個營銷任務、營銷渠道的引流用戶更多? 買量用戶的活躍、留存情況如何? 哪個營銷任務引流的用戶後續的加購、下單轉化最多? HMS Core分析服務作為廣告轉化跟蹤工具,廣告主可實現從“曝光、點擊、下載、激活、註冊、留存、收藏、加入購物車、下單、開始結算、支付成功、復購”的全鏈路監測,讓市場營銷同學從 ...
  • [Android開發學iOS系列] 工具篇: Xcode使用和快捷鍵 工欲善其事必先利其器. 編輯 Cmd + N: 新建文件 Option + Cmd + N: 新建文件夾 Cmd + / : 註釋 Ctrl + I: format indentation, (但是使用這個快捷鍵要小心, 可能會在 ...
  • 【導讀】 隨著音視頻內容品類的不斷豐富及音樂創作門檻不斷降低,大量用戶正熱切的參與到全民創作的大潮中。我們應該怎麼去擁抱移動端影音潛力市場?音頻編輯又可以有什麼新玩法? 本期直播《音隨我動,秒變音色造型師》聚焦音頻賽道,邀請了HMS Core音頻編輯服務產品經理以及創新娛樂類應用“唱鴨”的創始人做客 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...