iOS仿微信悬浮窗

作者: wmz啊 | 来源:发表于2019-11-18 00:18 被阅读0次

    仿微信悬浮窗,可直接协议加入悬浮窗或者直接调用方法注册,可自定义转场动画

    Github地址(WMZFloatView)

    演示

    myFloat.gif

    用法1 在Appdelegate中注册 传入对应控制器的className

     //只带控制器的className 
     [[WMZFloatManage shareInstance] registerControllers:@[@"ViewController"]];
      //带其他配置(标题和图片)
    [[WMZFloatManage shareInstance]    registerControllers:@[@{@"controllerName":@"ViewController",@"icon":@"float_circle_full"}]];
    

    用法2 实现协议 WMZFloatViewProtocol 即可

     //可选实现协议的方法 传入标题和图片
      - (NSDictionary *)floatViewConfig{
        return @{@"name":@"实际显示在悬浮窗的标题",@"icon":@"float_image"};
     }
    

    用法3 改变转场动画 传入继承UIViewControllerAnimatedTransitioning协议的类即可

    //自定义push动画
    @property(nonatomic,strong)NSObject<UIViewControllerAnimatedTransitioning> *pushAnimal;
    //自定义pop动画
    @property(nonatomic,strong)NSObject<UIViewControllerAnimatedTransitioning>  *popAnimal;
    

    依赖

    无任何依赖

    讲解

    来说下我的实现思路

    1 浮动框

    1 实现一个悬浮窗的单例管理器,继承UINavigationControllerDelegate,UIGestureRecognizerDelegate

    2 监听侧滑手势是否开始

      //监听侧滑手势开始
    - (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer{
    if ([gestureRecognizer isKindOfClass:[UIScreenEdgePanGestureRecognizer class]]&&self.nowVC.navigationController.viewControllers.count>1) {
        //判断是否实现了协议 加入可悬浮
        BOOL isConform = [self.nowVC conformsToProtocol:@protocol(WMZFloatViewProtocol)];
        NSString *tmpName = NSStringFromClass([self.nowVC class]);
        if (isConform) {
            if ([self.reginerVCName indexOfObject:tmpName] == NSNotFound) {
                NSMutableDictionary *mdic = [NSMutableDictionary new];
                [mdic setObject:tmpName forKey:@"controllerName"];
                //实现了配置的协议 加入配置
                if ([self.nowVC respondsToSelector:@selector(floatViewConfig)]) {
                    NSDictionary *dic = [self.nowVC performSelector:@selector(floatViewConfig)];
                    [dic enumerateKeysAndObjectsUsingBlock:^(id  _Nonnull key, id  _Nonnull obj, BOOL * _Nonnull stop) {
                        [mdic setObject:obj forKey:key];
                    }];
                }
                [self.reginerVCName addObject:tmpName];
                [self.reginerVCConfig setObject:mdic forKey:tmpName];
            }
        }
        //达到可悬浮的条件
        if ([self.reginerVCName indexOfObject:tmpName] != NSNotFound && [self.cacheKey indexOfObject:[self getKey:self.nowVC]] == NSNotFound){
            self.edge = (UIScreenEdgePanGestureRecognizer *) gestureRecognizer;
            [self.link addToRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes];
            [faloatWindow addSubview:self.floatView];
            self.normalRect = self.floatView.frame;
            CGRect rect = self.floatView.frame;
            rect.origin.x = FloatWidth;
            rect.origin.y = FloatHeight;
            self.floatView.frame = rect;
            self.floatView.full = (self.cacheKey.count>=5);
        }
        
    }
    return YES;
    

    }

    3 监听侧滑触碰点是否碰到悬浮窗

     //圆心到点的距离>?半径
     + (BOOL)point:(CGPoint)point inCircleRect:(CGRect)rect {
         CGFloat radius = rect.size.height;
         CGPoint center = CGPointMake(rect.origin.x + radius, rect.origin.y + radius);
         double dx = fabs(point.x - center.x);
         double dy = fabs(point.y - center.y);
         double dis = hypot(dx, dy);
         return dis <= radius;
     }
    

    2 悬浮窗图案 1~5

     NSDictionary *dic = @{
        @(1):@[
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize*0.15, panSize*0.15, width, height)],
                    @"cornerRadius":@(height/2)
                }
        ],
        @(2):@[
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize*scale-panSize/6, panSize*scale , width, height)],
                    @"pathAngle":@(M_PI_4)
                },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize*scale-panSize/6+panSize*scale-4, panSize*scale , width, height)],
                    @"cornerRadius":@(height/2)
                }
        ],
        @(3):@[
              @{
                @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale/2, panSize*scale, width, height)],
                @"pathAngle":@(M_PI_4),
                @"toValue":@(M_PI_2+M_PI_4)
              },
              @{
                @"frame":[NSValue valueWithCGRect:CGRectMake(panSize*scale,panSize*scale  + height -4, width, height)],
                @"pathAngle":@(M_PI_4),
                @"toValue":@(M_PI*2),
                @"fromValue":@(M_PI)
              },
              @{
                @"frame":[NSValue valueWithCGRect:CGRectMake(panSize*scale +width  -2, panSize*scale + height -4, width, height)],
                @"pathAngle":@(M_PI_4),
                @"toValue":@(-M_PI_2-M_PI_4)
                },
        ],
        @(4):@[
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale/2, panSize*scale , width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(M_PI_2+M_PI_4)
                },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale,panSize*scale + height-5, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(M_PI_4),
                },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale + width +2, panSize*scale + height-7, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(-M_PI_2-M_PI_4)
                    },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale/2+2, panSize*scale  + height*2 -7-5, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(-M_PI_4)
                },
        ],
        @(5):@[
    
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale/2, panSize*scale, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(M_PI_2+M_PI_4),
                    @"controlPoint":[NSValue valueWithCGPoint:CGPointMake(width/3, height/3)]
                },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale/2-panSize*scale/2,panSize*scale + height -5, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(M_PI_4+M_PI_4/2),
                    @"controlPoint":[NSValue valueWithCGPoint:CGPointMake(width/3, height/3)]
                },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2 +3 ,panSize*scale + height -5 -2, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(-M_PI_2-M_PI_4),
                    @"controlPoint":[NSValue valueWithCGPoint:CGPointMake(width/3, height/3)]
                    },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale+3, panSize*scale + height*2 -5 -2 -1, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(2*M_PI),
                    @"fromValue":@(M_PI),
                    @"controlPoint":[NSValue valueWithCGPoint:CGPointMake(width/3, height/3)]
                },
                @{
                    @"frame":[NSValue valueWithCGRect:CGRectMake(panSize/2-panSize*scale+3 + width -2,  panSize*scale + height*2 -5 -2 -1-1, width, height)],
                    @"pathAngle":@(M_PI_4),
                    @"toValue":@(-M_PI_2/3-M_PI_4),
                    @"controlPoint":[NSValue valueWithCGPoint:CGPointMake(width/3, height/3)]
                },
        ],
    };
    
    NSArray *config = dic[@(data.count)];
    
     //创建图片
    NSMutableArray *imageArr = [NSMutableArray new];
    for (NSString *key in data) {
        UIImageView *image = [UIImageView new];
        NSDictionary *detailDic = [cache objectForKey:key];
        if (detailDic[@"icon"]) {
            image.image = [UIImage imageNamed:detailDic[@"icon"]];
        }else{
            image.backgroundColor = FloatShowColor;
        }
        image.layer.masksToBounds = YES;
        [imageArr addObject:image];
        [self addSubview:image];
        [self bringSubviewToFront:image];
    }
    
    CFTimeInterval time = ((data.count == normalCount)?0.01:1);
    
     //图片绘制图案和动画
    for (int i = 0; i<imageArr.count; i++) {
        UIImageView *image = imageArr[i];
        NSDictionary *frameDic = config[i];
        image.frame = [frameDic[@"frame"] CGRectValue];
        if (frameDic[@"cornerRadius"]) {
            image.layer.cornerRadius = [frameDic[@"cornerRadius"] floatValue];
        }
        if (frameDic[@"pathAngle"]) {
            CGPoint point = [frameDic[@"controlPoint"] CGPointValue];
            CAShapeLayer *layer = [CAShapeLayer layer];
            layer.path = [self getPathWithRadius:image.frame.size.height/2 center:CGPointMake(image.frame.size.width/2, image.frame.size.height/2) angle:[frameDic[@"pathAngle"] doubleValue] controlPoint:point].CGPath;
            layer.frame = image.bounds;
            if (frameDic[@"toValue"]) {
                double toValue = [frameDic[@"toValue"] doubleValue];
                double fromValue =  [frameDic[@"fromValue"] doubleValue];
                [layer addAnimation:[self getAnimationWithValue:toValue fromValue:fromValue duration:time] forKey:nil];
            }
            image.layer.mask = layer;
            
        }
    }
    

    Github地址(WMZFloatView)
    有什么问题欢迎给我提issue,欢迎star

    相关文章

      网友评论

        本文标题:iOS仿微信悬浮窗

        本文链接:https://www.haomeiwen.com/subject/wawpictx.html