├── SuspendViewDemo
├── SuspendViewDemo
│ ├── Assets.xcassets
│ │ ├── Contents.json
│ │ ├── AccentColor.colorset
│ │ │ └── Contents.json
│ │ └── AppIcon.appiconset
│ │ │ └── Contents.json
│ ├── ViewController.h
│ ├── AppDelegate.h
│ ├── Info.plist
│ ├── main.m
│ ├── AppDelegate.m
│ ├── SuspendView.h
│ ├── Base.lproj
│ │ ├── Main.storyboard
│ │ └── LaunchScreen.storyboard
│ ├── ViewController.m
│ └── SuspendView.m
└── SuspendViewDemo.xcodeproj
│ ├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ ├── xcuserdata
│ │ └── lyp.xcuserdatad
│ │ │ └── UserInterfaceState.xcuserstate
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
│ ├── xcuserdata
│ └── lyp.xcuserdatad
│ │ └── xcschemes
│ │ └── xcschememanagement.plist
│ ├── xcshareddata
│ └── xcschemes
│ │ └── SuspendViewDemo.xcscheme
│ └── project.pbxproj
└── README.md
/SuspendViewDemo/SuspendViewDemo/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | //
4 | //
5 | // Created by LYP on 2022/8/4.
6 | //
7 |
8 | #import
9 |
10 | @interface ViewController : UIViewController
11 |
12 |
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo.xcodeproj/project.xcworkspace/xcuserdata/lyp.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/longypjiangxi/XLUIDragButton/HEAD/SuspendViewDemo/SuspendViewDemo.xcodeproj/project.xcworkspace/xcuserdata/lyp.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | //
4 | //
5 | // Created by LYP on 2022/8/4.
6 | //
7 |
8 | #import
9 |
10 | @interface AppDelegate : UIResponder
11 |
12 | @property (strong, nonatomic) UIWindow * window;
13 | @end
14 |
15 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # SuspendViewDemo
2 |
3 | iOS-OC 全局悬浮球效果实现,悬浮按钮,拖拽拖动,贴边吸附,隐藏和显示,切换横竖屏适配,坐标转换
4 |
5 | 麻烦动动发财的小手点个Star💗
6 |
7 | demo演示,gif图,代码功能介绍,以下为作者原文地址,有问题请私信或评论
8 |
9 | 简书地址:https://www.jianshu.com/p/30aeb1d506d3
10 |
11 | 博客地址:https://www.cnblogs.com/longyongping/p/16601562.html
12 |
13 | CSDN地址:https://blog.csdn.net/qq_37926094/article/details/126467828
14 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | NSAppTransportSecurity
6 |
7 | NSAllowsArbitraryLoads
8 |
9 |
10 | UIViewControllerBasedStatusBarAppearance
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | //
4 | //
5 | // Created by LYP on 2022/8/4.
6 | //
7 |
8 | #import
9 | #import "AppDelegate.h"
10 |
11 | int main(int argc, char * argv[]) {
12 | NSString * appDelegateClassName;
13 | @autoreleasepool {
14 | // Setup code that might create autoreleased objects goes here.
15 | appDelegateClassName = NSStringFromClass([AppDelegate class]);
16 | }
17 | return UIApplicationMain(argc, argv, nil, appDelegateClassName);
18 | }
19 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | //
4 | //
5 | // Created by LYP on 2022/8/4.
6 | //
7 |
8 | #import "AppDelegate.h"
9 | #import "ViewController.h"
10 | @interface AppDelegate ()
11 |
12 | @end
13 |
14 | @implementation AppDelegate
15 |
16 |
17 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
18 | self.window=[[UIWindow alloc]initWithFrame:[UIScreen mainScreen].bounds];
19 | self.window.rootViewController = [[ViewController alloc]init];
20 | [self.window makeKeyAndVisible];
21 |
22 | return YES;
23 | }
24 |
25 | @end
26 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo.xcodeproj/xcuserdata/lyp.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | SuspendViewDemo.xcscheme_^#shared#^_
8 |
9 | orderHint
10 | 1
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | 3406E61D289BACF4006722D7
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/SuspendView.h:
--------------------------------------------------------------------------------
1 | //
2 | // SuspendView.h
3 | //
4 | //
5 | // Created by LYP on 2022/8/10.
6 | //
7 |
8 | #import
9 |
10 | NS_ASSUME_NONNULL_BEGIN
11 | @protocol SuspendViewDelegate
12 | //点击事件
13 | - (void)suspendViewButtonClick:(UIButton*)sender;
14 | //显示是否隐藏提示框
15 | - (void)showHideAlertView;
16 | @end
17 | @interface SuspendView : UIView
18 | {
19 | CGPoint lastPoint;/**存储悬浮球最后的移动完位置*/
20 | BOOL isChangePosition;/**悬浮球是否改变了位置*/
21 | CGFloat changeHig;//按钮高度位置比例
22 | CGFloat changeWid;//按钮宽度位置比例
23 |
24 | }
25 | @property (nonatomic, retain) UIButton *btn;/**<#name#>*/
26 | @property (nonatomic, strong) NSTimer *_Nullable timer;
27 | @property (nonatomic, retain) UIImageView *imageView;
28 | @property (nonatomic, assign) UIInterfaceOrientation orientation;
29 | @property (nonatomic, weak) id delegate;
30 | //隐藏&显示
31 | - (void)showSuspendView;
32 | - (void)dismissSuspendView;
33 | @end
34 |
35 | NS_ASSUME_NONNULL_END
36 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo.xcodeproj/xcshareddata/xcschemes/SuspendViewDemo.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | //
4 | //
5 | // Created by LYP on 2022/8/4.
6 | //
7 |
8 | #import "ViewController.h"
9 | #import "SuspendView.h"
10 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
11 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
12 |
13 | @interface ViewController ()
14 |
15 | @property (nonatomic, retain) UIButton *loginBtn;/**<#name#>*/
16 | @property (nonatomic, retain) UIButton *signOutBtn;/**<#name#>*/
17 | @property (nonatomic, retain) UIButton *menuBtn;/**<#name#>*/
18 | @property (nonatomic, retain) SuspendView *suspendView;/**<#name#>*/
19 | @property (nonatomic, strong) NSTimer* timer;/**<#name#>*/
20 | @end
21 |
22 | @implementation ViewController
23 |
24 | - (void)viewDidLoad {
25 | [super viewDidLoad];
26 | // Do any additional setup after loading the view.
27 |
28 | self.view.backgroundColor = [UIColor grayColor];
29 | [self.view addSubview:self.menuBtn];
30 |
31 | _timer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:false block:^(NSTimer * _Nonnull timer) {
32 | [[UIApplication sharedApplication].keyWindow addSubview:self.suspendView];
33 | [self->_timer invalidate];
34 | self->_timer = nil;
35 | }];
36 |
37 | [self configSYSDKNotification];
38 |
39 | }
40 |
41 | - (void)uploadViewFrame{
42 | self.menuBtn.frame = CGRectMake((SCREEN_WIDTH - 150)/2, 100, 150, 80);
43 | }
44 |
45 | #pragma mark ========================= SuspendViewDelegate =========================
46 | - (void)suspendViewButtonClick:(nonnull UIButton *)sender {
47 | NSLog(@"按钮点击事件");
48 | }
49 |
50 | - (void)showHideAlertView{
51 | UIAlertController * alert = [UIAlertController alertControllerWithTitle:@"提示" message:@"是否隐藏悬浮窗" preferredStyle:UIAlertControllerStyleAlert];
52 | // 增加取消按钮;
53 | [alert addAction:[UIAlertAction actionWithTitle:@"否" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
54 | NSLog(@"不隐藏");
55 | }]];
56 | // 增加确定按钮;
57 | [alert addAction:[UIAlertAction actionWithTitle:@"是" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
58 | [self.suspendView dismissSuspendView];
59 | }]];
60 | [self presentViewController:alert animated:true completion:nil];
61 | }
62 |
63 | #pragma mark ========================= 通知 =========================
64 | - (void)configSYSDKNotification{
65 |
66 | [[NSNotificationCenter defaultCenter] addObserver:self
67 | selector:@selector(didChangeStatusBarOrientation)
68 | name:UIApplicationDidChangeStatusBarOrientationNotification
69 | object:nil];
70 | }
71 |
72 |
73 | - (void)didChangeStatusBarOrientation {
74 | /**
75 | UIDeviceOrientationUnknown,
76 | UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom
77 | UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top
78 | UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right
79 | UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left
80 | UIDeviceOrientationFaceUp, // Device oriented flat, face up
81 | UIDeviceOrientationFaceDown // Device oriented flat, face down
82 | */
83 | switch ([UIDevice currentDevice].orientation)
84 | {
85 | case UIDeviceOrientationPortraitUpsideDown:
86 | // NSLog(@"faceBar在下面");
87 | break;
88 | case UIDeviceOrientationLandscapeLeft:
89 | // NSLog(@"faceBar在左边");
90 | break;
91 | case UIDeviceOrientationLandscapeRight:
92 | // NSLog(@"faceBar在右边");
93 | break;
94 | case UIDeviceOrientationPortrait:
95 | // NSLog(@"faceBar在上边");
96 | break;
97 | default: // as UIInterfaceOrientationPortrait
98 | // NSLog(@"faceBar在上边");
99 | break;
100 | }
101 |
102 | [self uploadViewFrame];
103 | }
104 |
105 | #pragma mark ========================= Click =========================
106 |
107 | - (void)menuBtnClick:(UIButton *)button{
108 | [self.suspendView showSuspendView];
109 | }
110 |
111 | #pragma mark ========================= 懒加载 =========================
112 |
113 | - (SuspendView *)suspendView {
114 | if (!_suspendView) {
115 | _suspendView = [[SuspendView alloc] init];
116 | _suspendView.delegate = self;
117 | }
118 | return _suspendView;
119 | }
120 |
121 | - (UIButton *)menuBtn{
122 | if(!_menuBtn){
123 | _menuBtn = [UIButton buttonWithType:UIButtonTypeCustom];
124 | _menuBtn.frame = CGRectMake((SCREEN_WIDTH - 150)/2, 100, 150, 80);
125 | _menuBtn.layer.cornerRadius = 40;
126 | [_menuBtn setBackgroundColor: UIColor.whiteColor];
127 | [_menuBtn setTitle:@"显示悬浮窗" forState:UIControlStateNormal];
128 | [_menuBtn setTitleColor:UIColor.blackColor forState:UIControlStateNormal];
129 | [_menuBtn addTarget:self action:@selector(menuBtnClick:) forControlEvents:UIControlEventTouchUpInside];
130 | }
131 | return _menuBtn;
132 | }
133 |
134 | @end
135 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 55;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | 3406E623289BACF4006722D7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 3406E622289BACF4006722D7 /* AppDelegate.m */; };
11 | 3406E629289BACF4006722D7 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 3406E628289BACF4006722D7 /* ViewController.m */; };
12 | 3406E62C289BACF4006722D7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3406E62A289BACF4006722D7 /* Main.storyboard */; };
13 | 3406E62E289BACF6006722D7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 3406E62D289BACF6006722D7 /* Assets.xcassets */; };
14 | 3406E631289BACF6006722D7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 3406E62F289BACF6006722D7 /* LaunchScreen.storyboard */; };
15 | 3406E634289BACF6006722D7 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 3406E633289BACF6006722D7 /* main.m */; };
16 | 34977F9528A3561E0045D8EE /* SuspendView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34977F9428A3561E0045D8EE /* SuspendView.m */; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXCopyFilesBuildPhase section */
20 | 3406E641289BB3BE006722D7 /* CopyFiles */ = {
21 | isa = PBXCopyFilesBuildPhase;
22 | buildActionMask = 2147483647;
23 | dstPath = "";
24 | dstSubfolderSpec = 10;
25 | files = (
26 | );
27 | runOnlyForDeploymentPostprocessing = 0;
28 | };
29 | /* End PBXCopyFilesBuildPhase section */
30 |
31 | /* Begin PBXFileReference section */
32 | 3406E61E289BACF4006722D7 /* SuspendViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SuspendViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; };
33 | 3406E621289BACF4006722D7 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
34 | 3406E622289BACF4006722D7 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
35 | 3406E627289BACF4006722D7 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
36 | 3406E628289BACF4006722D7 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
37 | 3406E62B289BACF4006722D7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
38 | 3406E62D289BACF6006722D7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
39 | 3406E630289BACF6006722D7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
40 | 3406E632289BACF6006722D7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
41 | 3406E633289BACF6006722D7 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
42 | 34977F9328A3561E0045D8EE /* SuspendView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SuspendView.h; sourceTree = ""; };
43 | 34977F9428A3561E0045D8EE /* SuspendView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SuspendView.m; sourceTree = ""; };
44 | /* End PBXFileReference section */
45 |
46 | /* Begin PBXFrameworksBuildPhase section */
47 | 3406E61B289BACF4006722D7 /* Frameworks */ = {
48 | isa = PBXFrameworksBuildPhase;
49 | buildActionMask = 2147483647;
50 | files = (
51 | );
52 | runOnlyForDeploymentPostprocessing = 0;
53 | };
54 | /* End PBXFrameworksBuildPhase section */
55 |
56 | /* Begin PBXGroup section */
57 | 3406E615289BACF4006722D7 = {
58 | isa = PBXGroup;
59 | children = (
60 | 3406E620289BACF4006722D7 /* SuspendViewDemo */,
61 | 3406E61F289BACF4006722D7 /* Products */,
62 | );
63 | sourceTree = "";
64 | };
65 | 3406E61F289BACF4006722D7 /* Products */ = {
66 | isa = PBXGroup;
67 | children = (
68 | 3406E61E289BACF4006722D7 /* SuspendViewDemo.app */,
69 | );
70 | name = Products;
71 | sourceTree = "";
72 | };
73 | 3406E620289BACF4006722D7 /* SuspendViewDemo */ = {
74 | isa = PBXGroup;
75 | children = (
76 | 3406E621289BACF4006722D7 /* AppDelegate.h */,
77 | 3406E622289BACF4006722D7 /* AppDelegate.m */,
78 | 3406E627289BACF4006722D7 /* ViewController.h */,
79 | 3406E628289BACF4006722D7 /* ViewController.m */,
80 | 34977F9328A3561E0045D8EE /* SuspendView.h */,
81 | 34977F9428A3561E0045D8EE /* SuspendView.m */,
82 | 3406E62A289BACF4006722D7 /* Main.storyboard */,
83 | 3406E62D289BACF6006722D7 /* Assets.xcassets */,
84 | 3406E62F289BACF6006722D7 /* LaunchScreen.storyboard */,
85 | 3406E632289BACF6006722D7 /* Info.plist */,
86 | 3406E633289BACF6006722D7 /* main.m */,
87 | );
88 | path = SuspendViewDemo;
89 | sourceTree = "";
90 | };
91 | /* End PBXGroup section */
92 |
93 | /* Begin PBXNativeTarget section */
94 | 3406E61D289BACF4006722D7 /* SuspendViewDemo */ = {
95 | isa = PBXNativeTarget;
96 | buildConfigurationList = 3406E637289BACF6006722D7 /* Build configuration list for PBXNativeTarget "SuspendViewDemo" */;
97 | buildPhases = (
98 | 3406E61A289BACF4006722D7 /* Sources */,
99 | 3406E61B289BACF4006722D7 /* Frameworks */,
100 | 3406E61C289BACF4006722D7 /* Resources */,
101 | 3406E641289BB3BE006722D7 /* CopyFiles */,
102 | );
103 | buildRules = (
104 | );
105 | dependencies = (
106 | );
107 | name = SuspendViewDemo;
108 | productName = SuspendViewDemo;
109 | productReference = 3406E61E289BACF4006722D7 /* SuspendViewDemo.app */;
110 | productType = "com.apple.product-type.application";
111 | };
112 | /* End PBXNativeTarget section */
113 |
114 | /* Begin PBXProject section */
115 | 3406E616289BACF4006722D7 /* Project object */ = {
116 | isa = PBXProject;
117 | attributes = {
118 | BuildIndependentTargetsInParallel = 1;
119 | LastUpgradeCheck = 1340;
120 | TargetAttributes = {
121 | 3406E61D289BACF4006722D7 = {
122 | CreatedOnToolsVersion = 13.4;
123 | };
124 | };
125 | };
126 | buildConfigurationList = 3406E619289BACF4006722D7 /* Build configuration list for PBXProject "SuspendViewDemo" */;
127 | compatibilityVersion = "Xcode 13.0";
128 | developmentRegion = en;
129 | hasScannedForEncodings = 0;
130 | knownRegions = (
131 | en,
132 | Base,
133 | );
134 | mainGroup = 3406E615289BACF4006722D7;
135 | productRefGroup = 3406E61F289BACF4006722D7 /* Products */;
136 | projectDirPath = "";
137 | projectRoot = "";
138 | targets = (
139 | 3406E61D289BACF4006722D7 /* SuspendViewDemo */,
140 | );
141 | };
142 | /* End PBXProject section */
143 |
144 | /* Begin PBXResourcesBuildPhase section */
145 | 3406E61C289BACF4006722D7 /* Resources */ = {
146 | isa = PBXResourcesBuildPhase;
147 | buildActionMask = 2147483647;
148 | files = (
149 | 3406E631289BACF6006722D7 /* LaunchScreen.storyboard in Resources */,
150 | 3406E62E289BACF6006722D7 /* Assets.xcassets in Resources */,
151 | 3406E62C289BACF4006722D7 /* Main.storyboard in Resources */,
152 | );
153 | runOnlyForDeploymentPostprocessing = 0;
154 | };
155 | /* End PBXResourcesBuildPhase section */
156 |
157 | /* Begin PBXSourcesBuildPhase section */
158 | 3406E61A289BACF4006722D7 /* Sources */ = {
159 | isa = PBXSourcesBuildPhase;
160 | buildActionMask = 2147483647;
161 | files = (
162 | 3406E629289BACF4006722D7 /* ViewController.m in Sources */,
163 | 3406E623289BACF4006722D7 /* AppDelegate.m in Sources */,
164 | 3406E634289BACF6006722D7 /* main.m in Sources */,
165 | 34977F9528A3561E0045D8EE /* SuspendView.m in Sources */,
166 | );
167 | runOnlyForDeploymentPostprocessing = 0;
168 | };
169 | /* End PBXSourcesBuildPhase section */
170 |
171 | /* Begin PBXVariantGroup section */
172 | 3406E62A289BACF4006722D7 /* Main.storyboard */ = {
173 | isa = PBXVariantGroup;
174 | children = (
175 | 3406E62B289BACF4006722D7 /* Base */,
176 | );
177 | name = Main.storyboard;
178 | sourceTree = "";
179 | };
180 | 3406E62F289BACF6006722D7 /* LaunchScreen.storyboard */ = {
181 | isa = PBXVariantGroup;
182 | children = (
183 | 3406E630289BACF6006722D7 /* Base */,
184 | );
185 | name = LaunchScreen.storyboard;
186 | sourceTree = "";
187 | };
188 | /* End PBXVariantGroup section */
189 |
190 | /* Begin XCBuildConfiguration section */
191 | 3406E635289BACF6006722D7 /* Debug */ = {
192 | isa = XCBuildConfiguration;
193 | buildSettings = {
194 | ALWAYS_SEARCH_USER_PATHS = NO;
195 | CLANG_ANALYZER_NONNULL = YES;
196 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
197 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
198 | CLANG_ENABLE_MODULES = YES;
199 | CLANG_ENABLE_OBJC_ARC = YES;
200 | CLANG_ENABLE_OBJC_WEAK = YES;
201 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
202 | CLANG_WARN_BOOL_CONVERSION = YES;
203 | CLANG_WARN_COMMA = YES;
204 | CLANG_WARN_CONSTANT_CONVERSION = YES;
205 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
206 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
207 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
208 | CLANG_WARN_EMPTY_BODY = YES;
209 | CLANG_WARN_ENUM_CONVERSION = YES;
210 | CLANG_WARN_INFINITE_RECURSION = YES;
211 | CLANG_WARN_INT_CONVERSION = YES;
212 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
213 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
214 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
215 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
216 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
217 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
218 | CLANG_WARN_STRICT_PROTOTYPES = YES;
219 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
220 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
221 | CLANG_WARN_UNREACHABLE_CODE = YES;
222 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
223 | COPY_PHASE_STRIP = NO;
224 | DEBUG_INFORMATION_FORMAT = dwarf;
225 | ENABLE_STRICT_OBJC_MSGSEND = YES;
226 | ENABLE_TESTABILITY = YES;
227 | GCC_C_LANGUAGE_STANDARD = gnu11;
228 | GCC_DYNAMIC_NO_PIC = NO;
229 | GCC_NO_COMMON_BLOCKS = YES;
230 | GCC_OPTIMIZATION_LEVEL = 0;
231 | GCC_PREPROCESSOR_DEFINITIONS = (
232 | "DEBUG=1",
233 | "$(inherited)",
234 | );
235 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
236 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
237 | GCC_WARN_UNDECLARED_SELECTOR = YES;
238 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
239 | GCC_WARN_UNUSED_FUNCTION = YES;
240 | GCC_WARN_UNUSED_VARIABLE = YES;
241 | IPHONEOS_DEPLOYMENT_TARGET = 15.5;
242 | MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
243 | MTL_FAST_MATH = YES;
244 | ONLY_ACTIVE_ARCH = YES;
245 | SDKROOT = iphoneos;
246 | };
247 | name = Debug;
248 | };
249 | 3406E636289BACF6006722D7 /* Release */ = {
250 | isa = XCBuildConfiguration;
251 | buildSettings = {
252 | ALWAYS_SEARCH_USER_PATHS = NO;
253 | CLANG_ANALYZER_NONNULL = YES;
254 | CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
255 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
256 | CLANG_ENABLE_MODULES = YES;
257 | CLANG_ENABLE_OBJC_ARC = YES;
258 | CLANG_ENABLE_OBJC_WEAK = YES;
259 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
260 | CLANG_WARN_BOOL_CONVERSION = YES;
261 | CLANG_WARN_COMMA = YES;
262 | CLANG_WARN_CONSTANT_CONVERSION = YES;
263 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
264 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
265 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
266 | CLANG_WARN_EMPTY_BODY = YES;
267 | CLANG_WARN_ENUM_CONVERSION = YES;
268 | CLANG_WARN_INFINITE_RECURSION = YES;
269 | CLANG_WARN_INT_CONVERSION = YES;
270 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
271 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
272 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
273 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
274 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
275 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
276 | CLANG_WARN_STRICT_PROTOTYPES = YES;
277 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
278 | CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
279 | CLANG_WARN_UNREACHABLE_CODE = YES;
280 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
281 | COPY_PHASE_STRIP = NO;
282 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
283 | ENABLE_NS_ASSERTIONS = NO;
284 | ENABLE_STRICT_OBJC_MSGSEND = YES;
285 | GCC_C_LANGUAGE_STANDARD = gnu11;
286 | GCC_NO_COMMON_BLOCKS = YES;
287 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
288 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
289 | GCC_WARN_UNDECLARED_SELECTOR = YES;
290 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
291 | GCC_WARN_UNUSED_FUNCTION = YES;
292 | GCC_WARN_UNUSED_VARIABLE = YES;
293 | IPHONEOS_DEPLOYMENT_TARGET = 15.5;
294 | MTL_ENABLE_DEBUG_INFO = NO;
295 | MTL_FAST_MATH = YES;
296 | SDKROOT = iphoneos;
297 | VALIDATE_PRODUCT = YES;
298 | };
299 | name = Release;
300 | };
301 | 3406E638289BACF6006722D7 /* Debug */ = {
302 | isa = XCBuildConfiguration;
303 | buildSettings = {
304 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
305 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
306 | CODE_SIGN_STYLE = Automatic;
307 | CURRENT_PROJECT_VERSION = 1;
308 | DEVELOPMENT_TEAM = PH5NS9QCQ7;
309 | ENABLE_BITCODE = YES;
310 | EXCLUDED_ARCHS = "";
311 | FRAMEWORK_SEARCH_PATHS = (
312 | "$(inherited)",
313 | "$(PROJECT_DIR)/SuspendViewDemo/SDK",
314 | "\"$(SRCROOT)/SuspendViewDemo/SDK/SYSDK.framework\"",
315 | );
316 | GENERATE_INFOPLIST_FILE = YES;
317 | INFOPLIST_FILE = SuspendViewDemo/Info.plist;
318 | INFOPLIST_KEY_CFBundleDisplayName = "悬浮窗";
319 | INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "允许应用程序访问您的相册,以便保存图片到相册";
320 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
321 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
322 | INFOPLIST_KEY_UIMainStoryboardFile = Main;
323 | INFOPLIST_KEY_UIStatusBarHidden = YES;
324 | INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
325 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
326 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
327 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
328 | LD_RUNPATH_SEARCH_PATHS = (
329 | "$(inherited)",
330 | "@executable_path/Frameworks",
331 | );
332 | LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/SuspendViewDemo/SDK/SYSDK.framework\"";
333 | MARKETING_VERSION = 1.0;
334 | ONLY_ACTIVE_ARCH = YES;
335 | OTHER_LDFLAGS = "-ObjC";
336 | PRODUCT_BUNDLE_IDENTIFIER = com.long.SuspendViewDemo;
337 | PRODUCT_NAME = "$(TARGET_NAME)";
338 | SWIFT_EMIT_LOC_STRINGS = YES;
339 | TARGETED_DEVICE_FAMILY = "1,2";
340 | VALIDATE_WORKSPACE = YES;
341 | };
342 | name = Debug;
343 | };
344 | 3406E639289BACF6006722D7 /* Release */ = {
345 | isa = XCBuildConfiguration;
346 | buildSettings = {
347 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
348 | ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
349 | CODE_SIGN_STYLE = Automatic;
350 | CURRENT_PROJECT_VERSION = 1;
351 | DEVELOPMENT_TEAM = PH5NS9QCQ7;
352 | ENABLE_BITCODE = YES;
353 | EXCLUDED_ARCHS = "";
354 | FRAMEWORK_SEARCH_PATHS = (
355 | "$(inherited)",
356 | "$(PROJECT_DIR)/SuspendViewDemo/SDK",
357 | "\"$(SRCROOT)/SuspendViewDemo/SDK/SYSDK.framework\"",
358 | );
359 | GENERATE_INFOPLIST_FILE = YES;
360 | INFOPLIST_FILE = SuspendViewDemo/Info.plist;
361 | INFOPLIST_KEY_CFBundleDisplayName = "悬浮窗";
362 | INFOPLIST_KEY_NSPhotoLibraryAddUsageDescription = "允许应用程序访问您的相册,以便保存图片到相册";
363 | INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
364 | INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
365 | INFOPLIST_KEY_UIMainStoryboardFile = Main;
366 | INFOPLIST_KEY_UIStatusBarHidden = YES;
367 | INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
368 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
369 | INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
370 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
371 | LD_RUNPATH_SEARCH_PATHS = (
372 | "$(inherited)",
373 | "@executable_path/Frameworks",
374 | );
375 | LIBRARY_SEARCH_PATHS = "\"$(SRCROOT)/SuspendViewDemo/SDK/SYSDK.framework\"";
376 | MARKETING_VERSION = 1.0;
377 | ONLY_ACTIVE_ARCH = NO;
378 | OTHER_LDFLAGS = "-ObjC";
379 | PRODUCT_BUNDLE_IDENTIFIER = com.long.SuspendViewDemo;
380 | PRODUCT_NAME = "$(TARGET_NAME)";
381 | SWIFT_EMIT_LOC_STRINGS = YES;
382 | TARGETED_DEVICE_FAMILY = "1,2";
383 | VALIDATE_WORKSPACE = YES;
384 | };
385 | name = Release;
386 | };
387 | /* End XCBuildConfiguration section */
388 |
389 | /* Begin XCConfigurationList section */
390 | 3406E619289BACF4006722D7 /* Build configuration list for PBXProject "SuspendViewDemo" */ = {
391 | isa = XCConfigurationList;
392 | buildConfigurations = (
393 | 3406E635289BACF6006722D7 /* Debug */,
394 | 3406E636289BACF6006722D7 /* Release */,
395 | );
396 | defaultConfigurationIsVisible = 0;
397 | defaultConfigurationName = Release;
398 | };
399 | 3406E637289BACF6006722D7 /* Build configuration list for PBXNativeTarget "SuspendViewDemo" */ = {
400 | isa = XCConfigurationList;
401 | buildConfigurations = (
402 | 3406E638289BACF6006722D7 /* Debug */,
403 | 3406E639289BACF6006722D7 /* Release */,
404 | );
405 | defaultConfigurationIsVisible = 0;
406 | defaultConfigurationName = Release;
407 | };
408 | /* End XCConfigurationList section */
409 | };
410 | rootObject = 3406E616289BACF4006722D7 /* Project object */;
411 | }
412 |
--------------------------------------------------------------------------------
/SuspendViewDemo/SuspendViewDemo/SuspendView.m:
--------------------------------------------------------------------------------
1 | //
2 | // SuspendView.m
3 | //
4 | //
5 | // Created by LYP on 2022/8/10.
6 | //
7 |
8 | #import "SuspendView.h"
9 |
10 | #define SCREEN_WIDTH [UIScreen mainScreen].bounds.size.width
11 | #define SCREEN_HEIGHT [UIScreen mainScreen].bounds.size.height
12 | #define ViewSize 50
13 | #define KHeightFit(w) (((w) / 667.0) * SCREEN_HEIGHT)
14 |
15 | #define LRString [NSString stringWithFormat:@"%s", __FILE__].lastPathComponent
16 | #define DLog(...) {\
17 | NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];\
18 | [dateFormatter setDateFormat:@"YYYY-MM-dd hh:mm:ss"];\
19 | NSString *dateString = [dateFormatter stringFromDate:[NSDate date]];\
20 | printf("%s %s 第%d行:%s\n\n",[dateString UTF8String],[LRString UTF8String] ,__LINE__, [[NSString stringWithFormat:__VA_ARGS__] UTF8String]);}
21 |
22 | @implementation SuspendView
23 |
24 |
25 | - (instancetype)init{
26 | self = [super init];
27 | if (self) {
28 | self.backgroundColor = UIColor.redColor;
29 | self.layer.masksToBounds = YES;
30 | self.layer.cornerRadius = ViewSize/2;
31 | self.alpha = 0.5;
32 |
33 | //获取设备方向
34 | self.orientation = [[UIApplication sharedApplication] statusBarOrientation];
35 | if (self.orientation == UIInterfaceOrientationLandscapeRight){//横向home键在右侧,设备左转,刘海在左边
36 | self.frame = CGRectMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, KHeightFit(80) + ViewSize/2, ViewSize, ViewSize);
37 | }else{
38 | self.frame = CGRectMake(SCREEN_WIDTH - ViewSize/2, KHeightFit(80) + ViewSize/2, ViewSize, ViewSize);
39 | }
40 |
41 | self.btn = [UIButton buttonWithType:UIButtonTypeCustom];
42 | self.btn.frame = CGRectMake(5, 5, 40, 40);
43 | self.btn.backgroundColor = UIColor.greenColor;
44 | self.btn.layer.cornerRadius = 20;
45 | [self.btn addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
46 | [self addSubview:self.btn];
47 | //获取按钮与屏幕初始宽高比例
48 | [self changeCoordinateScale];
49 | //是否改变了悬浮窗初始位置
50 | isChangePosition = NO;
51 |
52 | //添加手势
53 | UIPanGestureRecognizer *panRcognize=[[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePanGesture:)];
54 | [panRcognize setMinimumNumberOfTouches:1];
55 | [panRcognize setEnabled:YES];
56 | [panRcognize delaysTouchesEnded];
57 | [panRcognize cancelsTouchesInView];
58 | [self addGestureRecognizer:panRcognize];
59 |
60 | //监听屏幕旋转
61 | [[NSNotificationCenter defaultCenter] addObserver:self
62 | selector:@selector(didChangeStatusBarOrientation)
63 | name:UIApplicationDidChangeStatusBarOrientationNotification
64 | object:nil];
65 | }
66 | return self;
67 | }
68 |
69 | - (void)didChangeStatusBarOrientation {
70 |
71 | self.orientation = [UIApplication sharedApplication].statusBarOrientation;
72 | self.imageView.frame = CGRectMake((SCREEN_WIDTH - 50)/2, (SCREEN_HEIGHT - 50)/2, 50, 50);
73 | // DLog(@"===%zd=====%zd",[[UIDevice currentDevice] orientation],[UIApplication sharedApplication].statusBarOrientation);
74 | //请注意,UIInterfaceOrientationAndScapeLeft等于UIDeviceOrientation AndScapeRight(反之亦然)。
75 | //这是因为向左旋转设备需要向右旋转内容。
76 | /**
77 | UIInterfaceOrientationUnknown = UIDeviceOrientationUnknown,
78 | UIInterfaceOrientationPortrait = UIDeviceOrientationPortrait,
79 | UIInterfaceOrientationPortraitUpsideDown = UIDeviceOrientationPortraitUpsideDown,
80 | UIInterfaceOrientationLandscapeLeft = UIDeviceOrientationLandscapeRight,
81 | UIInterfaceOrientationLandscapeRight = UIDeviceOrientationLandscapeLeft
82 | */
83 |
84 | /**
85 | UIDeviceOrientationUnknown,
86 | UIDeviceOrientationPortrait, // Device oriented vertically, home button on the bottom
87 | UIDeviceOrientationPortraitUpsideDown, // Device oriented vertically, home button on the top
88 | UIDeviceOrientationLandscapeLeft, // Device oriented horizontally, home button on the right
89 | UIDeviceOrientationLandscapeRight, // Device oriented horizontally, home button on the left
90 | UIDeviceOrientationFaceUp, // Device oriented flat, face up
91 | UIDeviceOrientationFaceDown // Device oriented flat, face down
92 | */
93 | switch ([UIDevice currentDevice].orientation)
94 | {
95 | case UIDeviceOrientationPortraitUpsideDown:
96 | // DLog(@"设备倒垂直,home在上")
97 | [self locationChange:@"Down"];
98 | break;
99 | case UIDeviceOrientationLandscapeLeft:{
100 | // DLog(@"设备横屏,左转,home在右")
101 | [self locationChange:@"left"];
102 | }
103 | break;
104 | case UIDeviceOrientationLandscapeRight:{
105 | // DLog(@"设备横屏,右转,home在左")
106 | [self locationChange:@"right"];
107 | }
108 | break;
109 | case UIDeviceOrientationPortrait:{
110 | // DLog(@"设备垂直,home在下");
111 | [self locationChange:@"Portrait"];
112 | }
113 | break;
114 | default:
115 | break;
116 | }
117 | }
118 | //根据屏幕宽高改变按钮位置比例
119 | - (void)locationChange:(NSString *)message{
120 | // NSLog(@"changeHig == %f,changeWid == %f",changeHig,changeWid);
121 | if (SCREEN_HEIGHT > SCREEN_WIDTH) {
122 | //屏幕方向上
123 | if ([message isEqualToString:@"Portrait"]) {
124 | NSLog(@"安全区在上边");
125 | self.center = CGPointMake(changeWid * SCREEN_WIDTH, changeHig * SCREEN_HEIGHT);
126 | }else{//下
127 | NSLog(@"安全区在下边");
128 | self.center = CGPointMake(changeWid * SCREEN_WIDTH, changeHig * SCREEN_HEIGHT - [self vg_safeDistanceTop]);
129 | }
130 | }else{
131 | if ([message isEqualToString:@"left"]) {//左
132 | NSLog(@"安全区在左边");
133 | self.center = CGPointMake(changeWid * SCREEN_WIDTH + [self vg_safeDistanceTop] + ViewSize, changeHig * SCREEN_HEIGHT);
134 | }else{//右
135 | NSLog(@"安全区在右边");
136 | self.center = CGPointMake(changeWid * SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize, changeHig * SCREEN_HEIGHT);
137 | }
138 | }
139 | // NSLog(@"lastPoint == %@, self.center == %@",NSStringFromCGPoint(lastPoint),NSStringFromCGPoint(self.center));
140 |
141 | [self changeCoordinateScale];
142 |
143 | }
144 | //旋转屏幕后修改悬浮窗相对于屏幕的宽高比例以及坐标位置
145 | - (void)changeCoordinateScale{
146 | changeHig = self.center.y/SCREEN_HEIGHT;
147 | changeWid = self.center.x/SCREEN_WIDTH;
148 | //判断设备旋转方向
149 | if (self.orientation == UIInterfaceOrientationLandscapeRight) {//横向home键在右侧,设备左转,刘海在左边,刘海在左边
150 | //判断悬浮窗坐标x在屏幕的左边还是右边
151 | if (self.center.x > SCREEN_WIDTH/2) {//大于中心x,在右边
152 | //修改悬浮窗的坐标在最右边
153 | self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
154 | }else{
155 | //修改悬浮窗的坐标在最左边
156 | self.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20, self.center.y);
157 | }
158 | }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//横向home键在左侧,设备右转,刘海在右边
159 | if (self.center.x > SCREEN_WIDTH/2) {//大于中心x,在右边
160 | //修改悬浮窗的坐标在最右边,留出顶部安全距离
161 | self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, self.center.y);
162 | }else{
163 | //修改悬浮窗的坐标在最左边
164 | self.center = CGPointMake(0, self.center.y);
165 | }
166 | }else{
167 | //大于中心x,在右边
168 | if (self.center.x > SCREEN_WIDTH/2) {
169 | self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
170 | }else{
171 | self.center = CGPointMake(0, self.center.y);
172 | }
173 | }
174 | // NSLog(@"changeHig == %f,changeWid == %f",changeHig,changeWid);
175 | // NSLog(@"设备宽度 == %f, 设备高度== %f, 按钮坐标==%@",SCREEN_WIDTH,SCREEN_HEIGHT,NSStringFromCGPoint(self.center));
176 | }
177 | - (void)showSuspendView{
178 | self.hidden = NO;
179 | NSLog(@"显示悬浮窗");
180 | }
181 | - (void)dismissSuspendView{
182 | self.hidden = YES;
183 | NSLog(@"隐藏悬浮窗");
184 | }
185 | /// 悬浮窗按钮点击放法
186 | /// @param button 点击之后完全显示悬浮窗,改变按钮位置
187 | - (void)btnClick:(UIButton *)button{
188 | if (self.delegate && [self.delegate respondsToSelector:@selector(suspendViewButtonClick:)]) {
189 | [self.delegate suspendViewButtonClick:button];
190 | }
191 | // DLog(@"lastPoint == %@",NSStringFromCGPoint(lastPoint));
192 | //如果没有改变过位置,lastPoint初始值(0,0)
193 | //判断是否移动过悬浮窗
194 | if (!isChangePosition) {
195 | //悬浮窗初始位置在右上角,只有屏幕向右旋转,才需要留出iphone刘海的位置,设备左转刘海在左边,所以不需要做判断
196 | if (self.orientation == UIInterfaceOrientationLandscapeLeft) {//横向home键在左侧,设备右转,刘海在右边
197 | //修改点击后悬浮窗的位置,留出安全距离
198 | [UIView animateWithDuration:0.5 animations:^{
199 | self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20 - 20, self.center.y);
200 | }];
201 | }else{
202 | [UIView animateWithDuration:0.5 animations:^{
203 | self.center = CGPointMake(SCREEN_WIDTH - ViewSize, self.center.y);
204 | }];
205 | }
206 | }else{
207 | // 判断最后的坐标是靠左还是靠右
208 | if (self.orientation == UIInterfaceOrientationLandscapeRight) {//横向home键在右侧,设备左转,刘海在左边
209 | if (self.center.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
210 | [UIView animateWithDuration:0.5 animations:^{
211 | self.center = CGPointMake(SCREEN_WIDTH - ViewSize, self.center.y);
212 | }];
213 | }else{
214 | //左转刘海在左边,留出安全距离
215 | [UIView animateWithDuration:0.5 animations:^{
216 | self.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20 + 20, self.center.y);
217 | }];
218 | }
219 | }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//横向home键在左侧,设备右转,刘海在右边
220 | if (self.center.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧,留出刘海安全距离
221 | [UIView animateWithDuration:0.5 animations:^{
222 | self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20 - 20, self.center.y);
223 | }];
224 | }else{//左侧显示
225 | [UIView animateWithDuration:0.5 animations:^{
226 | self.center = CGPointMake(ViewSize, self.center.y);
227 | }];
228 | }
229 | }else{
230 | if (self.center.x < SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
231 | [UIView animateWithDuration:0.5 animations:^{
232 | self.center = CGPointMake(ViewSize, self.center.y);
233 | }];
234 | }else{
235 | [UIView animateWithDuration:0.5 animations:^{
236 | self.center = CGPointMake(SCREEN_WIDTH - ViewSize, self.center.y);
237 | }];
238 | }
239 | }
240 |
241 | }
242 |
243 | self.alpha = 1;
244 | //三秒后隐藏悬浮窗,贴边展示一半
245 | self.timer = [NSTimer scheduledTimerWithTimeInterval:3 target:self selector:@selector(timerAction) userInfo:nil repeats:NO];
246 | }
247 |
248 | - (void)timerAction{
249 | //隐藏悬浮球
250 | self.alpha = 0.5;
251 | //判断是否移动过悬浮窗
252 | if (!isChangePosition) {
253 | //悬浮窗初始位置在右上角,只有屏幕向右旋转,才需要留出iphone刘海的位置,设备左转刘海在左边,所以不需要做判断
254 | if (self.orientation == UIInterfaceOrientationLandscapeLeft) {//横向home键在左侧,设备右转,刘海在右边
255 | [UIView animateWithDuration:0.5 animations:^{
256 | self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, self.center.y);
257 | }];
258 | }else{
259 | [UIView animateWithDuration:0.5 animations:^{
260 | self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
261 | }];
262 | }
263 |
264 | }else{
265 | if (self.orientation == UIInterfaceOrientationLandscapeRight) {//横向home键在右侧,设备左转,刘海在左边
266 | if (self.center.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
267 | [UIView animateWithDuration:0.5 animations:^{
268 | self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
269 | }];
270 | }else{
271 | //悬浮窗在屏幕左侧,留出刘海安全距离
272 | [UIView animateWithDuration:0.5 animations:^{
273 | self.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20, self.center.y);
274 | }];
275 | }
276 | }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//横向home键在左侧,设备右转,刘海在右边
277 | if (self.center.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
278 | //悬浮窗在屏幕左侧,留出刘海安全距离
279 | [UIView animateWithDuration:0.5 animations:^{
280 | self.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, self.center.y);
281 | }];
282 | }else{
283 | [UIView animateWithDuration:0.5 animations:^{
284 | self.center = CGPointMake(0, self.center.y);
285 | }];
286 | }
287 |
288 | }else{
289 | if (self.center.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
290 | [UIView animateWithDuration:0.5 animations:^{
291 | self.center = CGPointMake(SCREEN_WIDTH, self.center.y);
292 | }];
293 | }else{
294 | [UIView animateWithDuration:0.5 animations:^{
295 | self.center = CGPointMake(0, self.center.y);
296 | }];
297 | }
298 |
299 | }
300 | }
301 | //销毁定时器
302 | [self.timer invalidate];
303 | self.timer = nil;
304 | }
305 |
306 |
307 | /// pan手势
308 | /// @param recognizer recognizer description
309 | - (void)handlePanGesture:(UIPanGestureRecognizer *)recognizer
310 | {
311 | //移动状态
312 | UIGestureRecognizerState recState = recognizer.state;
313 | isChangePosition = YES;
314 |
315 | switch (recState) {
316 | case UIGestureRecognizerStateBegan:
317 | self.alpha = 1;
318 | self.imageView.hidden = NO;
319 | break;
320 | case UIGestureRecognizerStateChanged://移动中
321 | {
322 | self.alpha = 1;
323 | CGPoint translation = [recognizer translationInView:self];
324 | recognizer.view.center = CGPointMake(recognizer.view.center.x + translation.x, recognizer.view.center.y + translation.y);
325 |
326 | CGRect rect = [self convertRect:self.frame toView:self];
327 | if (CGRectIntersectsRect(self.imageView.frame, rect)) {//在范围内
328 | self.imageView.backgroundColor = UIColor.redColor;
329 | }else{
330 | self.imageView.backgroundColor = UIColor.blueColor;
331 | }
332 | }
333 | break;
334 | case UIGestureRecognizerStateEnded://移动结束
335 | {
336 | self.alpha = 0.5;
337 | CGPoint stopPoint = CGPointMake(0, SCREEN_HEIGHT / 2);
338 | //判断按钮贴靠在屏幕的左边还是右边
339 | if (recognizer.view.center.x < SCREEN_WIDTH / 2) {
340 | stopPoint = CGPointMake(ViewSize/2, recognizer.view.center.y);
341 | }else{
342 | //贴靠在右边
343 | stopPoint = CGPointMake(SCREEN_WIDTH - ViewSize/2,recognizer.view.center.y);
344 | }
345 | DLog(@"stopPoint == %@",NSStringFromCGPoint(stopPoint));
346 |
347 | if (stopPoint.y - ViewSize/2 <= 0) {
348 | DLog(@"上");
349 | //加上电池栏的高度
350 | if (stopPoint.x - ViewSize/2 <= SCREEN_WIDTH/2) {
351 | stopPoint = CGPointMake(0, stopPoint.y + [self vg_safeDistanceTop] + ViewSize);
352 | DLog(@"左上");
353 | }else{
354 | DLog(@"右上");
355 | stopPoint = CGPointMake(SCREEN_WIDTH, stopPoint.y + [self vg_safeDistanceTop] + ViewSize);
356 | }
357 | }
358 | //如果按钮超出屏幕边缘
359 | if (stopPoint.y + ViewSize + 20 >= SCREEN_HEIGHT) {
360 | DLog(@"下");
361 | //减去底部状态栏的高度
362 | if (stopPoint.x - ViewSize/2 <= SCREEN_WIDTH/2) {
363 | DLog(@"左下");
364 | stopPoint = CGPointMake(0, stopPoint.y - [self vg_safeDistanceBottom] - ViewSize/2);
365 | }else{
366 | DLog(@"右下");
367 | stopPoint = CGPointMake(SCREEN_WIDTH, stopPoint.y - [self vg_safeDistanceBottom] - ViewSize/2);
368 | }
369 | // DLog(@"超出屏幕下方");
370 | }
371 |
372 | if (stopPoint.x - ViewSize/2 <= 0) {
373 | DLog(@"左");
374 | // stopPoint = CGPointMake(ViewSize/2, stopPoint.y);
375 | //缩进去一半
376 | stopPoint = CGPointMake(0, stopPoint.y);
377 | }
378 | if (stopPoint.x + ViewSize/2 >= SCREEN_WIDTH) {
379 | DLog(@"右");
380 | // stopPoint = CGPointMake(SCREEN_WIDTH - ViewSize/2, stopPoint.y);
381 | stopPoint = CGPointMake(SCREEN_WIDTH, stopPoint.y);
382 | }
383 |
384 | //保存最后的位置
385 | lastPoint = stopPoint;
386 |
387 | //隐藏悬浮球
388 | CGRect rect = [self convertRect:self.frame toView:self];
389 | if (CGRectIntersectsRect(self.imageView.frame, rect)) {//在范围内
390 | DLog(@"悬浮窗在中心imageview内,提示是否隐藏悬浮窗");
391 | // [self showAlertView];
392 | [self.delegate showHideAlertView];
393 | }
394 | // NSLog(@"self.orientation == %ld",(long)self.orientation);
395 | if (self.orientation == UIInterfaceOrientationLandscapeRight) {//横向home键在右侧,设备左转,刘海在左边
396 | if (stopPoint.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
397 | [UIView animateWithDuration:0.5 animations:^{
398 | recognizer.view.center = CGPointMake(SCREEN_WIDTH, stopPoint.y);
399 | }];
400 | }else{
401 | //悬浮窗在屏幕左侧,留出刘海安全距离
402 | [UIView animateWithDuration:0.5 animations:^{
403 | recognizer.view.center = CGPointMake([self vg_safeDistanceTop] + ViewSize + 20, stopPoint.y);
404 | }];
405 | }
406 | }else if(self.orientation == UIInterfaceOrientationLandscapeLeft){//横向home键在左侧,设备右转,刘海在右边
407 | if (stopPoint.x > SCREEN_WIDTH/2) {//悬浮窗在屏幕右侧
408 | //悬浮窗在屏幕左侧,留出刘海安全距离
409 | [UIView animateWithDuration:0.5 animations:^{
410 | recognizer.view.center = CGPointMake(SCREEN_WIDTH - [self vg_safeDistanceTop] - ViewSize - 20, stopPoint.y);
411 | }];
412 | }else{
413 | [UIView animateWithDuration:0.5 animations:^{
414 | recognizer.view.center = CGPointMake(0, stopPoint.y);
415 | }];
416 | }
417 |
418 | }else{
419 | [UIView animateWithDuration:0.5 animations:^{
420 | recognizer.view.center = stopPoint;
421 | }];
422 | }
423 | [self changeCoordinateScale];
424 |
425 | self.imageView.hidden = YES;
426 |
427 | }
428 | break;
429 |
430 | default:
431 | break;
432 | }
433 |
434 | [recognizer setTranslation:CGPointMake(0, 0) inView:self];
435 | }
436 |
437 | //获取头部安全区高度
438 | - (CGFloat)vg_safeDistanceTop {
439 | if (@available(iOS 13.0, *)) {
440 | NSSet *set = [UIApplication sharedApplication].connectedScenes;
441 | UIWindowScene *windowScene = [set anyObject];
442 | UIWindow *window = windowScene.windows.firstObject;
443 | return window.safeAreaInsets.top;
444 | } else if (@available(iOS 11.0, *)) {
445 | UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
446 | return window.safeAreaInsets.top;
447 | }
448 | return 0;
449 | }
450 |
451 | //获取设备底部安全区高度
452 | - (CGFloat)vg_safeDistanceBottom {
453 | if (@available(iOS 13.0, *)) {
454 | NSSet *set = [UIApplication sharedApplication].connectedScenes;
455 | UIWindowScene *windowScene = [set anyObject];
456 | UIWindow *window = windowScene.windows.firstObject;
457 | return window.safeAreaInsets.bottom;
458 | } else if (@available(iOS 11.0, *)) {
459 | UIWindow *window = [UIApplication sharedApplication].windows.firstObject;
460 | return window.safeAreaInsets.bottom;
461 | }
462 | return 0;
463 | }
464 |
465 | - (UIImageView *)imageView{
466 | if (!_imageView) {
467 | _imageView = [[UIImageView alloc]initWithFrame:CGRectMake((SCREEN_WIDTH - 50)/2, (SCREEN_HEIGHT - 50)/2, 50, 50)];
468 | _imageView.backgroundColor = UIColor.blueColor;
469 | _imageView.hidden = YES;
470 | [[UIApplication sharedApplication].keyWindow addSubview:_imageView];
471 | }
472 | return _imageView;
473 | }
474 |
475 | @end
476 |
--------------------------------------------------------------------------------