分享一個(gè)自己寫的 AlertView

這個(gè)仿寫自今日頭條應(yīng)用內(nèi)推送提示的AlertView,請(qǐng)先看效果圖,如下

shili.gif


彈窗的消失有這幾種方法:
  • 點(diǎn)擊右上角的關(guān)閉符號(hào)
  • 左右滑動(dòng)一定范圍
  • 調(diào)用系統(tǒng)的 dismiss 方法。

使用到的主要方法:
  • UIViewspring 動(dòng)畫
  • 通過(guò)runtime 對(duì)UITapGestrueRecognize的封裝
  • GCD定時(shí)器

請(qǐng)看主要代碼
  • 手勢(shì)操作部分
#pragma mark -- 配置手勢(shì)操作
- (void)recognizeConfigs{
    __weak typeof(self) weakSelf = self;
    UIPanGestureRecognizer *panGestrue = [UIPanGestureRecognizer recognizeWithAction:^(id gestrueRecognize) {
        UIPanGestureRecognizer *recognizer = (UIPanGestureRecognizer *)gestrueRecognize;
        CGPoint translation     = [recognizer translationInView:self];
        CGPoint viewNewPoint    = CGPointMake(recognizer.view.center.x + translation.x,recognizer.view.center.y + translation.y);
        CGFloat y = isIphoneX?(kScreenHeight - ( 34 + 49 + 10 + AlertHeight/2)):(kScreenHeight - (49 + 10 + AlertHeight/2));
        //TODO:給拖拽控件設(shè)置范圍
        viewNewPoint.y          = y;//固定 y 值,控件只能在水平方向上移動(dòng)
        recognizer.view.center  = viewNewPoint;
        [recognizer setTranslation:CGPointZero inView:[UIApplication sharedApplication].keyWindow];
        
        switch (recognizer.state) {
            case UIGestureRecognizerStateBegan:
                {
                    NSLog(@"手勢(shì)已經(jīng)開(kāi)始");
                    if (weakSelf.gestrueDidStart) {
                        weakSelf.gestrueDidStart();//手勢(shì)開(kāi)始時(shí),暫停定時(shí)器
                    }
                }
                break;
            case UIGestureRecognizerStateEnded:
                {
                    NSLog(@"手勢(shì)已經(jīng)結(jié)束");
                    if (recognizer.view.center.x < 30 || recognizer.view.center.x > kScreenWidth - 30) {
                        [self dismissWithNoAnimation];
                        if (weakSelf.gestrueDidEndWithTimerInvalidate) {//手勢(shì)結(jié)束,且 alert 消失,此時(shí)銷毀定時(shí)器
                            weakSelf.gestrueDidEndWithTimerInvalidate();
                        }
                    }else{
                        [UIView animateWithDuration:0.5
                                         animations:^{
                                             recognizer.view.center = CGPointMake(kScreenWidth/2, self.center.y);
                                         }];
                        if (weakSelf.gestrueDidEnd) {//手勢(shì)結(jié)束,但 alert 沒(méi)有消失,此時(shí)繼續(xù)開(kāi)始計(jì)時(shí)操作
                            weakSelf.gestrueDidEnd();
                        }
                    }
                }
                break;
            default:
                break;
        }
    }];
    panGestrue.cancelsTouchesInView = NO;
    [self addGestureRecognizer:panGestrue];
}
  • 彈窗的dismiss部分
#pragma mark -- 延遲執(zhí)行的 dismiss,延遲時(shí)間由使用者自己設(shè)定
+ (void)dismissAlertWithDelay:(NSTimeInterval)delayTime complete:(void (^)(void))complete{
    BottomAlertView *bSelf = [BottomAlertView shareView];
    __weak typeof(bSelf) weakSelf = bSelf;
    /*
     *每次啟動(dòng)定時(shí)器,先銷毀之前的定時(shí)器
     */
//    if (bSelf.timer) {
//        dispatch_cancel(bSelf.timer);
//    }
    if (delayTime < 1) {
        delayTime = 1;
    }
    
  /*
   *GCD定時(shí)器
   */
    __block NSTimeInterval userDelayTime = delayTime;
    dispatch_queue_t queue = dispatch_get_main_queue();
    bSelf.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
    dispatch_time_t start = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.0 * NSEC_PER_SEC));
    uint64_t interval = (uint64_t)(1.0 * NSEC_PER_SEC);
    dispatch_source_set_timer(bSelf.timer, start, interval, 0);
    dispatch_source_set_event_handler(bSelf.timer, ^{
        NSLog(@"=== %f ===",userDelayTime);
        if (userDelayTime == 0) {
            // 取消定時(shí)器
            dispatch_cancel(weakSelf.timer);
            [weakSelf.baseView dismiss];
            if (complete) {
                complete();
            }
        }
        userDelayTime--;
    });
    
    // 啟動(dòng)定時(shí)器
    dispatch_resume(bSelf.timer);
    
    [bSelf.baseView setGestrueDidStart:^{
        //手勢(shì)開(kāi)始,暫停定時(shí)器
        dispatch_suspend(weakSelf.timer);
    }];
    [bSelf.baseView setGestrueDidEnd:^{
        //手勢(shì)結(jié)束,但 alert 沒(méi)有消失,此時(shí)啟動(dòng)定時(shí)器
        dispatch_resume(weakSelf.timer);
    }];
    [bSelf.baseView setGestrueDidEndWithTimerInvalidate:^{
        //手勢(shì)結(jié)束,alert 也已經(jīng)消失,此時(shí)銷毀定時(shí)器
        dispatch_cancel(weakSelf.timer);
        if (complete) {
            complete();
        }
    }];
}

在上面,我通過(guò)block來(lái)監(jiān)聽(tīng)手勢(shì)的狀態(tài),通過(guò)這種狀態(tài)來(lái)控制定時(shí)器對(duì)象的暫停、開(kāi)啟以及取消。
關(guān)于NSTimerGCD定時(shí)器,GCD 定時(shí)器使用步驟比較復(fù)雜,但是相比NSTimer,計(jì)時(shí)更加準(zhǔn)確,且更方便對(duì)定時(shí)器對(duì)象進(jìn)行暫停等操作。


順便說(shuō)一下,在UIView動(dòng)畫的block回調(diào)中為什么不需要使用weakSelf

block本身不被self持有,而被別的對(duì)象持有,同時(shí)不產(chǎn)生循環(huán)引用的時(shí)候,就不需要使用weakself了.最常見(jiàn)的代碼就是UIView的動(dòng)畫代碼,我們?cè)谑褂?code>UIView的 animationWithDuration:animation方法做動(dòng)畫的時(shí)候,并不需要使用weakself,因?yàn)橐贸钟嘘P(guān)系是:

  • UIView的某個(gè)負(fù)責(zé)動(dòng)畫的對(duì)象持有了block,block本身持有了self
  • self并不持有block,所以就沒(méi)有循環(huán)引用產(chǎn)生,因此就不需要使用weakSelf

有感興趣的小伙伴,可以去我的 github下載這個(gè) demo,你們也可以根據(jù)自己的需求來(lái)進(jìn)一步改寫。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容