ios浮窗侧边键 (ios主屏幕浮窗)

可以拖动并且可以指定贴左还是贴右边, 直接上代码。

LMYHomeServicesButton.h

//
//  LMYHomeServicesButton.h
//  LMY
//
//  Created by 刘明洋 on 2018/1/28.
//  Copyright © 2018年 lmy. All rights reserved.
//

#import <UIKit/UIKit.h>

typedef NS_ENUM(NSInteger, LMYAssistiveTouchType)
{
    LMYAssistiveTypeNone = 0,   //自动识别贴边
    LMYAssistiveTypeNearLeft,   //拖动停止之后,自动向左贴边
    LMYAssistiveTypeNearRight,  //拖动停止之后,自动向右贴边
};

@interface LMYHomeServicesButton : UIButton


typedef void (^floatBtnClick)(UIButton *sender);

//任何模式都显示floatBtn
+ (void)show;

//移除
+ (void)hidden;

//按钮点击事件
@property (nonatomic, copy)floatBtnClick btnClick;

@end

LMYHomeServicesButton.m

//
//  LMYHomeServicesButton.m
//  LMY
//
//  Created by 刘明洋 on 2018/1/28.
//  Copyright © 2018年 lmy. All rights reserved.
//

#import "LMYHomeServicesButton.h"

@interface LMYHomeServicesButton()

@property (nonatomic, assign, getter=isBuildShowDate) BOOL buildShowDate;

//Build号
@property(nonatomic, copy)NSString *buildStr;

@property(nonatomic, assign)BOOL isShow;
@end

@implementation LMYHomeServicesButton{
    
    LMYAssistiveTouchType  _type;
    //拖动按钮的起始坐标点
    CGPoint _touchPoint;
    
    //起始按钮的x,y值
    CGFloat _touchBtnX;
    CGFloat _touchBtnY;

}

static LMYHomeServicesButton *_floatBtn;

static CGFloat floatBtnW = 120;
static CGFloat floatBtnH = 49;

#define screenW  [UIScreen mainScreen].bounds.size.width
#define screenH  [UIScreen mainScreen].bounds.size.height

//系统默认build
#define MNFloatBtnSystemBuild [[[NSBundle mainBundle]infoDictionary]valueForKey:@"CFBundleVersion"]
//系统默认version
#define MNFloatBtnSystemVersion [[[NSBundle mainBundle]infoDictionary]valueForKey:@"CFBundleShortVersionString"]

#pragma mark - lazy
- (NSString *)buildStr{
    if (!_buildStr) {
        _buildStr = MNFloatBtnSystemBuild;
    }
    return _buildStr;
}

#pragma mark - private Method
+ (void)show{
    [self showWithType:LMYAssistiveTypeNone];
}

+ (void)hidden{
    [_floatBtn removeFromSuperview];
}

+ (void)showWithType:(LMYAssistiveTouchType)type{
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        LMYHomeServicesButton * floatBtn = [[self alloc]initWithType:LMYAssistiveTypeNearRight frame:CGRectMake(10, 300, floatBtnW, floatBtnH)];
        [[UIApplication sharedApplication].keyWindow addSubview:floatBtn];
        //让floatBtn在最上层(即便以后还有keywindow add subView,也会在 floatBtn下)
        [[UIApplication sharedApplication].keyWindow bringSubviewToFront:floatBtn];
    });
}


- (instancetype)initWithType:(LMYAssistiveTouchType)type
                       frame:(CGRect)frame{
    NSString *title = [NSString stringWithFormat:@"Ver:%@ \nBuild:%@\n查看更多",MNFloatBtnSystemVersion, self.buildStr];


    if (self = [super initWithFrame:frame]) {
        _type = type;

        //UIbutton的换行显示
        self.titleLabel.lineBreakMode = NSLineBreakByWordWrapping;
        self.backgroundColor = [UIColor redColor];
        self.titleLabel.font = [UIFont systemFontOfSize:13];
        [self setTitle:title forState:UIControlStateNormal];

        [self addTarget:self action:@selector(p_clickBtn:) forControlEvents:UIControlEventTouchUpInside];

    }
    return self;
}


- (void)p_clickBtn:(UIButton *)sender{
    
    if (_btnClick) {
        _btnClick(sender);
    }
}


#pragma mark - button move
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event{
    
    [super touchesBegan:touches withEvent:event];
    
    //按钮刚按下的时候,获取此时的起始坐标
    UITouch *touch = [touches anyObject];
    _touchPoint = [touch locationInView:self];
    
    _touchBtnX = self.frame.origin.x;
    _touchBtnY = self.frame.origin.y;
}

- (void)touchesMoved:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
    
    UITouch *touch = [touches anyObject];
    CGPoint currentPosition = [touch locationInView:self];
    
    //偏移量(当前坐标 - 起始坐标 = 偏移量)
    CGFloat offsetX = currentPosition.x - _touchPoint.x;
    CGFloat offsetY = currentPosition.y - _touchPoint.y;
    
    //移动后的按钮中心坐标
    CGFloat centerX = self.center.x + offsetX;
    CGFloat centerY = self.center.y + offsetY;
    self.center = CGPointMake(centerX, centerY);
    
    //父试图的宽高
    CGFloat superViewWidth = self.superview.frame.size.width;
    CGFloat superViewHeight = self.superview.frame.size.height;
    CGFloat btnX = self.frame.origin.x;
    CGFloat btnY = self.frame.origin.y;
    CGFloat btnW = self.frame.size.width;
    CGFloat btnH = self.frame.size.height;
    
    //x轴左右极限坐标
    if (btnX > superViewWidth){
        //按钮右侧越界
        CGFloat centerX = superViewWidth - btnW/2;
        self.center = CGPointMake(centerX, centerY);
    }else if (btnX < 0){
        //按钮左侧越界
        CGFloat centerX = btnW * 0.5;
        self.center = CGPointMake(centerX, centerY);
    }
    
    //默认都是有导航条的,有导航条的,父试图高度就要被导航条占据,固高度不够
    CGFloat defaultNaviHeight = 64;
    CGFloat judgeSuperViewHeight = superViewHeight - defaultNaviHeight;
    
    //y轴上下极限坐标
    if (btnY <= 0){
        //按钮顶部越界
        centerY = btnH * 0.7;
        self.center = CGPointMake(centerX, centerY);
    }
    else if (btnY > judgeSuperViewHeight){
        //按钮底部越界
        CGFloat y = superViewHeight - btnH * 0.5;
        self.center = CGPointMake(btnX, y);
    }
}

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event{
    
    CGFloat btnWidth = self.frame.size.width;
    CGFloat btnHeight = self.frame.size.height;
    CGFloat btnY = self.frame.origin.y;
    CGFloat btnX = self.frame.origin.x;
    
    CGFloat minDistance = 2;
    
    //结束move的时候,计算移动的距离是>最低要求,如果没有,就调用按钮点击事件
    BOOL isOverX = fabs(btnX - _touchBtnX) > minDistance;
    BOOL isOverY = fabs(btnY - _touchBtnY) > minDistance;
    
    if (isOverX || isOverY) {
        //超过移动范围就不响应点击 - 只做移动操作
        [self touchesCancelled:touches withEvent:event];
    }else{
        [super touchesEnded:touches withEvent:event];
    }
    
    //按钮靠近右侧
    switch (_type) {
            
        case LMYAssistiveTypeNone:{
            
            //自动识别贴边
            if (self.center.x >= self.superview.frame.size.width/2) {
                
                [UIView animateWithDuration:0.5 animations:^{
                    //按钮靠右自动吸边
                    CGFloat btnX = self.superview.frame.size.width - btnWidth;
                    self.frame = CGRectMake(btnX, btnY, btnWidth, btnHeight);
                }];
            }else{
                
                [UIView animateWithDuration:0.5 animations:^{
                    //按钮靠左吸边
                    CGFloat btnX = 0;
                    self.frame = CGRectMake(btnX, btnY, btnWidth, btnHeight);
                }];
            }
            break;
        }
        case LMYAssistiveTypeNearLeft:{
            [UIView animateWithDuration:0.5 animations:^{
                //按钮靠左吸边
                CGFloat btnX = 0;
                self.frame = CGRectMake(btnX, btnY, btnWidth, btnHeight);
            }];
            break;
        }
        case LMYAssistiveTypeNearRight:{
            [UIView animateWithDuration:0.5 animations:^{
                //按钮靠右自动吸边
                CGFloat btnX = self.superview.frame.size.width - btnWidth;
                self.frame = CGRectMake(btnX, btnY, btnWidth, btnHeight);
            }];
        }
    }
}


@end


使用

//
//  ViewController.m
//  lmy
//
//  Created by lmy on 2019/10/27.
//  Copyright © 2019 lmy. All rights reserved.
//

#import "ViewController.h"
#import "LMYHomeServicesButton.h"


@interface ViewController ()
@property(nonatomic,strong)UIImage * objImage;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
}

- (void)viewDidAppear:(BOOL)animated{
    [super viewDidAppear:animated];

    [LMYHomeServicesButton show];
}
@end