美文网首页
iOS UIView动画效果来电提醒直播送礼

iOS UIView动画效果来电提醒直播送礼

作者: 弹吉他的少年 | 来源:发表于2020-12-17 12:57 被阅读0次

    前言

    • 简单的来电提醒动画效果,直播送礼显示

    . Demo地址

    xxxx.gif

    API & Property

    /// 最大显示个数,默认3个
    @property(nonatomic,assign)NSInteger maxCount;
    /// 自动消失时间,默认5s
    @property(nonatomic,assign)CGFloat vanishTime;
    /// 是否允许重复显示,默认NO
    @property(nonatomic,assign)BOOL repetition;
    /// 点击控件是否消失,默认NO
    @property(nonatomic,assign)BOOL tapVanish;
    /// 创建单例
    + (instancetype)kj_shareInstance;
    /// 添加来电消息,重复条件默认根据 userid 判断
    - (void)kj_addCallNotify:(void(^)(KJCallNotifyInfo *info))block RepetitionCondition:(bool(^_Nullable)(KJCallNotifyInfo *info))condition;
    /// 点击事件
    - (void)kj_tapBlock:(void(^)(KJCallNotifyInfo *info))block;
    

    简单介绍思路

    KJCallNotifyInfo数据模型

    声明一个接受外界的数据模型,暂时我只需要图片地址,名字,唯一id(需要再添加就完事)

    @interface KJCallNotifyInfo : NSObject
    @property(nonatomic,strong)NSString *imageUrl;
    @property(nonatomic,strong)NSString *name;
    @property(nonatomic,strong)NSString *userid;
    @end
    

    单例模式

    由于这玩意需要一直存在并且放在最顶层,所以我采用单例来设计

    static KJCallNotifyView *_instance = nil;
    + (instancetype)kj_shareInstance{
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            if (_instance == nil) {
                _instance = [[KJCallNotifyView alloc] initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH)];
                [kKeyWindow addSubview:_instance];
            }
        });
        return _instance;
    }
    

    当然你也可以不使用该单例,则按下面方式

    __block KJCallNotifyView *view = [[KJCallNotifyView alloc]initWithFrame:CGRectMake(0, 64, kScreenW, kScreenH-64)];
    [self.view addSubview:view];
    view.maxCount = 5;
    view.vanishTime = 5;
    [view kj_tapBlock:^(KJCallNotifyInfo * _Nonnull info) {
            
    }];
    
    __block NSInteger index = 1000;
    NSArray *names = @[@"Sone",@"痛苦的信仰",@"X"];
    [button kj_addAction:^(UIButton * _Nonnull kButton) {
        [view kj_addCallNotify:^(KJCallNotifyInfo * _Nonnull info) {
            info.imageUrl = @"xxsf";
            info.userid = [NSString stringWithFormat:@"%ld",index];
            info.name = names[1];
        } RepetitionCondition:nil];
    }];
    

    手势穿透处理

    不影响后面的交互效果

    - (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event{
        NSInteger count = self.subviews.count;
        for (int i = 0; i < count; i++){
            UIView *childView = self.subviews[count - 1 - I];
            CGPoint childPoint = [self convertPoint:point toView:childView];
            UIView *view = [childView hitTest:childPoint withEvent:event];
            if (view) return view;
        }
        return nil;
    }
    

    KJCallView

    来电样式UI处理

    @implementation KJCallView
    - (instancetype)kj_initWithFrame:(CGRect)frame Name:(NSString*)name{
        if (self==[super initWithFrame:frame]) {
            self.centerX = kScreenW/2;
            self.backgroundColor = UIColor.whiteColor;
            self.cornerRadius = kAutoH(48)/2;
            self.shadowColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0.16];
            self.shadowOffset = CGSizeMake(0,3);
            self.shadowRadius = 6;
            self.shadowOpacity = 1;
            CGFloat height = self.height;
            self.imageView = [[UIImageView alloc]initWithFrame:CGRectMake(5, 5, height-10, height-10)];
            self.imageView.cornerRadius = (height-10)/2;
            [self addSubview:self.imageView];
            self.button = [UIButton kj_createButton:^(id<KJQuickCreateHandle>  _Nonnull handle) {
                handle.kj_frame(self.width-18-8, 0, 18, 18).kj_add(self);
                handle.kj_imageName(@"xxx").kj_fontSize(14).kj_textColor(UIColor.blackColor);
            }];
            self.button.centerY = self.height/2;
            self.label = [UILabel kj_createLabel:^(id<KJQuickCreateHandle>  _Nonnull handle) {
                handle.kj_add(self);
                handle.kj_text(name).kj_font([UIFont fontWithName:@"PingFang SC" size:14]);
                handle.kj_textColor([UIColor colorWithRed:51/255.0 green:51/255.0 blue:51/255.0 alpha:1.0]);
            }];
            CGFloat width = [self.label kj_calculateWidth];
            CGFloat maxw = self.button.x - self.imageView.maxX - 10 - 23 - 10;
            if (width>=maxw) width = maxw;
            self.label.frame = CGRectMake(self.imageView.maxX+10, 0, width, self.height);
            self.tvImageView = [[UIImageView alloc]initWithFrame:CGRectMake(self.label.maxX+2.5, 0, 23, 22)];
            self.tvImageView.image = kGetImage(@"wode_nor");
            self.tvImageView.centerY = self.height/2;
            [self addSubview:self.tvImageView];
        }
        return self;
    }
    @end
    

    点击事件

    - (void)kj_tapBlock:(void(^)(KJCallNotifyInfo *info))block{
        self.tapblock = block;
    }
    

    点击回调,传递出来处理点击的相关逻辑

    添加来电消息

    介绍主要方法和核心点,
    displayCount:当前显示的UI个数属性
    temps:存储模型数据
    viewTemps:存储来电显示UI数据
    kj_addCallNotify:RepetitionCondition::添加来电消息
    @synchronized (@(self.displayCount)):互斥锁,保证正常运行
    kj_viewIndex:Info::创建来电UI
    kj_displayEnd::显示结束
    kj_autoVanish::自动消失动画
    kj_vanish::点叉消失动画
    kj_changeIndex:Y::递归修改来电坐标

    一、kj_addCallNotify:RepetitionCondition:

    添加来电消息,self.repetition控制是否重复显示,内部条件根据userid来判断是否重复

    - (void)kj_addCallNotify:(void(^)(KJCallNotifyInfo *))block RepetitionCondition:(bool(^_Nullable)(KJCallNotifyInfo *))condition{
        KJCallNotifyInfo *info = [KJCallNotifyInfo new];
        if (block) block(info);
        if (self.repetition == NO) {
            __block bool skip = false;
            if (condition) {
                for (KJCallNotifyInfo *_info in self.temps) {
                    skip = condition(_info);
                    if (skip) break;
                }
            }else{
                [self.temps enumerateObjectsUsingBlock:^(KJCallNotifyInfo * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
                    if ([info.userid isEqualToString:obj.userid]) {
                        skip = true;*stop = YES;
                    }
                }];
            }
            if (skip) return;
            [self.temps addObject:info];
        }
        @synchronized (@(self.displayCount)) {
            self.displayCount++;
            KJCallView *view = [self kj_viewIndex:self.displayCount Info:info];
            [self.viewTemps addObject:view];
            [self addSubview:view];
            if (self.displayCount > self.maxCount) {
                KJCallView *fristView = self.viewTemps.firstObject;
                [self kj_autoVanish:fristView];
                [self kj_displayEnd:fristView];
            }
        }
    }
    

    二、kj_viewIndex:Info:

    创建UI控件,添加计时器view.timer来管理自动消失

    - (KJCallView*)kj_viewIndex:(NSInteger)index Info:(KJCallNotifyInfo*)info{
        CGFloat y = kAutoH(17) + (index-1) * kAutoH(58) + kSTATUSBAR_HEIGHT - 20;
        __block KJCallView *view = [[KJCallView alloc]kj_initWithFrame:CGRectMake(0, y, kAutoW(170), kAutoH(48)) Name:info.name];
        view.tag = 520 + index - 1;
        view.info = info;
        view.imageView.image = [UIImage imageNamed:info.imageUrl];
        _weakself;
        void (^kRemove)(bool tapX) = ^(bool tapX){
            if (tapX) {
                [weakself kj_vanish:view];
            }else{
                [weakself kj_autoVanish:view];
            }
            [weakself kj_displayEnd:view];
        };
        [view kj_AddTapGestureRecognizerBlock:^(UIView * _Nonnull __view, UIGestureRecognizer * _Nonnull gesture) {
            if (weakself.tapblock) {
                weakself.tapblock(view.info);
                if (weakself.tapVanish) {
                    [weakself kj_vanish:view];
                    [weakself kj_displayEnd:view];
                }
            }
        }];
        [view.button kj_addAction:^(UIButton * _Nonnull kButton) {
            kRemove(true);
        }];
        view.timer = [NSTimer kj_scheduledNoImmediateTimerWithTimeInterval:self.vanishTime Block:^(NSTimer * _Nonnull timer) {
            kRemove(false);
        }];
        [[NSRunLoop mainRunLoop] addTimer:view.timer forMode:NSRunLoopCommonModes];
        [view.timer fire];
        return view;
    }
    

    三、kj_displayEnd:

    显示结束,清理数据,关闭计时器,显示个数处理

    - (void)kj_displayEnd:(KJCallView*)view{
        [view kj_invalidateTimer];
        [self.viewTemps removeObject:view];
        if (self.repetition == NO) {
            [self.temps removeObject:view.info];
        }
        @synchronized (@(self.displayCount)) {
            self.displayCount--;
        }
    }
    

    四、kj_autoVanish:

    自动消失处理

    - (void)kj_autoVanish:(KJCallView*)view{
        [UIView animateWithDuration:.5 animations:^{
            [self kj_changeIndex:0 Y:-kAutoH(48)];
        } completion:^(BOOL finished) {
            [view removeFromSuperview];
        }];
    }
    

    五、kj_vanish:

    点叉消失处理,当前点击控件消失,其余依次补位

    - (void)kj_vanish:(KJCallView*)view{
        [UIView animateWithDuration:.5 animations:^{
            view.hidden = 0;
            if (view.tag == 520) {
                [self kj_changeIndex:0 Y:-kAutoH(48)];
            }else{
                [self kj_changeIndex:view.tag-520 Y:view.y];
            }
        } completion:^(BOOL finished) {
            [view removeFromSuperview];
        }];
    }
    

    六、kj_changeIndex:Y:

    递归来处理补位

    - (void)kj_changeIndex:(NSInteger)index Y:(CGFloat)y{
        KJCallView *view = self.viewTemps[index];
        view.tag = 520 + index - 1;
        CGFloat xy = view.y;view.y = y;
        if (index+1<self.viewTemps.count) [self kj_changeIndex:index+1 Y:xy];
    }
    

    使用示例

    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view.
        
        UIButton *button = [UIButton kj_createButtonWithFontSize:15 Title:@"测试来电" TextColor:UIColor.orangeColor];
        button.frame = CGRectMake(0, 0, 100, 50);
        button.centerX = kScreenW/2;
        button.centerY = kScreenH - 100;
        button.borderWidth = 1;
        button.borderColor = UIColor.orangeColor;
        [self.view addSubview:button];
        
        __block NSInteger index = 520;
        NSArray *names = @[@"Sone",@"痛苦的信仰",@"X",@"yang"];
        [button kj_addAction:^(UIButton * _Nonnull kButton) {
            [[KJCallNotifyView kj_shareInstance] kj_addCallNotify:^(KJCallNotifyInfo * _Nonnull info) {
                info.imageUrl = @"xxsf";
                info.userid = [NSString stringWithFormat:@"%ld",index++];
                info.name = names[index%4];
            } RepetitionCondition:^bool(KJCallNotifyInfo * _Nonnull info) {
                if ([info.name isEqualToString:names[index%4]]) {
                    return true;
                }
                return false;
            }];
        }];
        [KJCallNotifyView kj_shareInstance].maxCount = 5;
        [KJCallNotifyView kj_shareInstance].vanishTime = 7;
        [KJCallNotifyView kj_shareInstance].repetition = YES;
        [[KJCallNotifyView kj_shareInstance] kj_tapBlock:^(KJCallNotifyInfo * _Nonnull info) {
            NSLog(@"-----%@",info);
            [self.navigationController popViewControllerAnimated:YES];
        }];
    }
    
    备注:本文用到的部分函数方法和Demo,均来自三方库KJEmitterView,如有需要的朋友可自行pod 'KJEmitterView'引入即可

    来电提醒小控件介绍就到此完毕,后面有相关再补充,写文章不容易,还请点个小星星传送门

    相关文章

      网友评论

          本文标题:iOS UIView动画效果来电提醒直播送礼

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