分享一個(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)系作者
  • 序言:七十年代末夺姑,一起剝皮案震驚了整個(gè)濱河市墩邀,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌盏浙,老刑警劉巖眉睹,帶你破解...
    沈念sama閱讀 206,602評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異废膘,居然都是意外死亡竹海,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,442評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門丐黄,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)斋配,“玉大人,你說(shuō)我怎么就攤上這事灌闺〖枵” “怎么了?”我有些...
    開(kāi)封第一講書人閱讀 152,878評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵菩鲜,是天一觀的道長(zhǎng)园细。 經(jīng)常有香客問(wèn)我,道長(zhǎng)接校,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,306評(píng)論 1 279
  • 正文 為了忘掉前任狮崩,我火速辦了婚禮蛛勉,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘睦柴。我一直安慰自己诽凌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,330評(píng)論 5 373
  • 文/花漫 我一把揭開(kāi)白布坦敌。 她就那樣靜靜地躺著侣诵,像睡著了一般痢法。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上杜顺,一...
    開(kāi)封第一講書人閱讀 49,071評(píng)論 1 285
  • 那天财搁,我揣著相機(jī)與錄音,去河邊找鬼躬络。 笑死尖奔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的穷当。 我是一名探鬼主播提茁,決...
    沈念sama閱讀 38,382評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼馁菜!你這毒婦竟也來(lái)了茴扁?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,006評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤汪疮,失蹤者是張志新(化名)和其女友劉穎丹弱,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體铲咨,經(jīng)...
    沈念sama閱讀 43,512評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡躲胳,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,965評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了纤勒。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片坯苹。...
    茶點(diǎn)故事閱讀 38,094評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖摇天,靈堂內(nèi)的尸體忽然破棺而出粹湃,到底是詐尸還是另有隱情,我是刑警寧澤泉坐,帶...
    沈念sama閱讀 33,732評(píng)論 4 323
  • 正文 年R本政府宣布为鳄,位于F島的核電站,受9級(jí)特大地震影響腕让,放射性物質(zhì)發(fā)生泄漏孤钦。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,283評(píng)論 3 307
  • 文/蒙蒙 一纯丸、第九天 我趴在偏房一處隱蔽的房頂上張望偏形。 院中可真熱鬧,春花似錦觉鼻、人聲如沸俊扭。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,286評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)萨惑。三九已至捐康,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間庸蔼,已是汗流浹背解总。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,512評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留朱嘴,地道東北人倾鲫。 一個(gè)月前我還...
    沈念sama閱讀 45,536評(píng)論 2 354
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像萍嬉,于是被迫代替她去往敵國(guó)和親乌昔。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,828評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容