即時(shí)通訊整個(gè)頁(yè)面的搭建(一)

前言

最近公司要做IM, 先后試了環(huán)信和極光的IM, 當(dāng)然UI也是用他們的, 后來(lái)溝通不符合公司的要求就不用了, 然后用朋友公司搭建的服務(wù)器, 隨之而來(lái)的界面也就要自己寫(xiě)(想用環(huán)信Demo來(lái)著, 想想還是自己寫(xiě)吧, 畢竟這是一次挑戰(zhàn)) 不廢話,直接上項(xiàng)目:FMChatUI 歡迎前來(lái)評(píng)論交流, 感覺(jué)還可以就star?? 下面就開(kāi)始 這篇先講一下整體的一個(gè)思路(項(xiàng)目中的類的作用)

整個(gè)結(jié)構(gòu)

Controller里只有控制器, 顯示消息的

整個(gè)項(xiàng)目用的第三方庫(kù)是轉(zhuǎn)碼MP3的時(shí)候用的 lame


lame

消息的Model類:


MessageItem

IMBaseItem包含消息的頭像名字時(shí)間等等信息, 擁有著IMMessageBody屬性 IMMessageBody包含了正文的類型,是文本還是圖片, 視頻的鏈接, 本地緩存的名字等等

IMBaseItemTool是為了將服務(wù)器返回的數(shù)據(jù)包裝成模型寫(xiě)的一個(gè)類, 不侵入到IMBaseItem

下面看看Tools里的

tool

看文件名應(yīng)該就能知道啥作用了??

View

整個(gè)的文件數(shù)就這么多了

說(shuō)說(shuō)控制器的吧
控制器里的代碼主要就是加載數(shù)據(jù),顯示數(shù)據(jù),沒(méi)有復(fù)雜的邏輯

剛進(jìn)入這個(gè)控制器的時(shí)候就是加載數(shù)據(jù), 加載本地的還是服務(wù)器的取決實(shí)現(xiàn)的內(nèi)容,可以直接加載本地的,我的demo里就是這么寫(xiě)的,demo里是采用KVO刷新列表的,其實(shí)當(dāng)時(shí)我是想,這個(gè)數(shù)組改變就刷新列表,但是當(dāng)控制器擁有這個(gè)數(shù)組時(shí),加入模型的時(shí)候, KVO并不會(huì)執(zhí)行,簡(jiǎn)單說(shuō)一下KVO監(jiān)聽(tīng)數(shù)組的變化刷新列表的小技巧:

KVO監(jiān)聽(tīng)數(shù)組

  • 將數(shù)組(既然觀察數(shù)組要變化,當(dāng)然是可變數(shù)組了)作為一個(gè)屬性
@property (nonatomic, strong) NSMutableArray *dataArray;
  • 注冊(cè)觀察者和實(shí)現(xiàn)觀察者方法,如果是UITableviewController,可以這樣寫(xiě)
[self addObserver:self forKeyPath:@"dataArray" options:NSKeyValueObservingOptionNew context:NULL];
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{ 
        NSLog(@"keypath ==%@ object ==%@" ,keyPath, object );
}
  • 使用下面這樣的方法來(lái)給數(shù)組添加數(shù)據(jù)或刪除數(shù)據(jù)
[[self mutableArrayValueForKey:@"dataArray"] addObject:@"adfasdf"];
  • 移除觀察者
-(void)dealloc{
 [self removeObserver:self forKeyPath:@"dataArray" context:NULL];
}

這樣就管插入就好了,會(huì)自動(dòng)刷新,不過(guò)這個(gè)在IM里似乎有一點(diǎn)小問(wèn)題,插入歷史數(shù)據(jù)的時(shí)候, 還是定位在插入前最頂部的那一行, 我這里是才用了保存一個(gè)值, 當(dāng)你需要插入的時(shí)候 這個(gè)值指定,刷新完之后,列表滾動(dòng)到某一行

連續(xù)播放未讀語(yǔ)音

demo里可以連續(xù)播放未讀的語(yǔ)音
具體點(diǎn)擊了哪一行,用代理回調(diào)的
上代碼先:


#pragma mark - 語(yǔ)音Cell點(diǎn)擊的回調(diào)
- (void)IMBaseCellClickAudioCell:(IMBaseCell *)cell{
    
    NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
    
    [self playAudioWithIndexPath:indexPath autoNext:YES];
    
}
/**
 *  準(zhǔn)備播放
 *
 *  @param indexPath 播放的哪一行
 *  @param next      是否播放下一行未讀
 */
- (void)playAudioWithIndexPath:(NSIndexPath *)indexPath autoNext:(BOOL)next{
    
    IMBaseItem *message = [self.reloadTable mutableArrayValueForKey:@"messages"][indexPath.row];
    
    WeakSelf
    if (message.messageBody.locationPath && message.messageBody.locationPath.length > 0) {
        message.isPlaying = YES;
        [self reloadDataWithMessage:message isInser:NO];
        [[IMAudioTool shareAudioTool] playWithFileName:message.messageBody.locationPath returnBeforeFileName:^(NSString *beforeFileName) {
            [weakSelf cancelAudioPlayWithFileName:beforeFileName];
        } withFinishBlock:^(BOOL isFinish) {
            message.isPlaying = !isFinish;
            message.readState = IMMessageReaded;
            [weakSelf reloadDataWithMessage:message isInser:NO];
            if (next) {
                if ([weakSelf getNextIndexPathForUnReadAudioWithCurrentIndexPath:indexPath]) {
                    [weakSelf playAudioWithIndexPath:[weakSelf getNextIndexPathForUnReadAudioWithCurrentIndexPath:indexPath] autoNext:YES];
                }
            }
        }];
    } else {
        NSString *fileName = [NSString stringWithFormat:@"%d%d.mp3", (int)[[NSDate date] timeIntervalSince1970], arc4random() % 100000];
        WeakSelf
        [IMDownloadManager downLoadFileUrl:message.messageBody.voiceUrlString datePath:[IMBaseAttribute dataAudioPath] fileName:fileName completionHandler:^(BOOL isSuccess) {
            if (isSuccess) {
                message.messageBody.locationPath = fileName;
                [IMSQLiteTool updateMessage:message withKey:@"messageBody"];
                message.isPlaying = YES;
                [weakSelf reloadDataWithMessage:message isInser:NO];
                [[IMAudioTool shareAudioTool] playWithFileName:message.messageBody.locationPath returnBeforeFileName:^(NSString *beforeFileName) {
                    [weakSelf cancelAudioPlayWithFileName:beforeFileName];
                } withFinishBlock:^(BOOL isFinish) {
                    message.isPlaying = !isFinish;
                    message.readState = IMMessageReaded;
                    [weakSelf reloadDataWithMessage:message isInser:NO];
                    if (next) {
                        if ([weakSelf getNextIndexPathForUnReadAudioWithCurrentIndexPath:indexPath]) {
                            [weakSelf playAudioWithIndexPath:[weakSelf getNextIndexPathForUnReadAudioWithCurrentIndexPath:indexPath] autoNext:YES];
                        }
                    }
                }];
            } else {
                NSLog(@"播放失敗");
            }
        }];
    }
}
/**
 *  獲取下一行未讀的IndexPath
 *
 *  @param currentIndexPath 當(dāng)前播放的IndexPath
 *
 *  @return 下一行未讀的IndexPath
 */
- (NSIndexPath *)getNextIndexPathForUnReadAudioWithCurrentIndexPath:(NSIndexPath *)currentIndexPath{
    
    if (currentIndexPath.row < [self.reloadTable mutableArrayValueForKey:@"messages"].count - 1) {
        
        for (NSInteger i = currentIndexPath.row + 1; i < [self.reloadTable mutableArrayValueForKey:@"messages"].count - 1; i++) {
            
            IMBaseItem *item = [self.reloadTable mutableArrayValueForKey:@"messages"][i];
            
            if (item.messageType == IMMessageAudioType && item.readState == IMMessageUnRead) {
                
                NSIndexPath *indexPath = [NSIndexPath indexPathForRow:i inSection:0];
                
                return indexPath;
                
            } else {
                continue;
            }
        }
    }
    
    return nil;
}

各種判斷等等
這里要注意的就是點(diǎn)擊完播放, 并且語(yǔ)音開(kāi)始播放了, 沒(méi)有播放完畢的時(shí)候, 再點(diǎn)擊下一個(gè)語(yǔ)音的播放, 要獲取到上一個(gè)之前播放的語(yǔ)音, 并刷新列表

demo里有很多地方采用的是Block回調(diào), 代理也是完全可以實(shí)現(xiàn)的, 不過(guò)我覺(jué)得麻煩就這么寫(xiě)了,而且讓代碼高聚合

----------------------------- 先到這吧?? ----------------------------------
續(xù)篇:
即時(shí)通訊整個(gè)頁(yè)面的搭建(二)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市宋税,隨后出現(xiàn)的幾起案子岛请,更是在濱河造成了極大的恐慌奔害,老刑警劉巖,帶你破解...
    沈念sama閱讀 207,113評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件钞支,死亡現(xiàn)場(chǎng)離奇詭異绅作,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)昔案,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門尿贫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人爱沟,你說(shuō)我怎么就攤上這事帅霜。” “怎么了呼伸?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,340評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵身冀,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我括享,道長(zhǎng)搂根,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,449評(píng)論 1 279
  • 正文 為了忘掉前任铃辖,我火速辦了婚禮剩愧,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘娇斩。我一直安慰自己仁卷,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,445評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布犬第。 她就那樣靜靜地躺著锦积,像睡著了一般。 火紅的嫁衣襯著肌膚如雪歉嗓。 梳的紋絲不亂的頭發(fā)上丰介,一...
    開(kāi)封第一講書(shū)人閱讀 49,166評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音鉴分,去河邊找鬼哮幢。 笑死,一個(gè)胖子當(dāng)著我的面吹牛志珍,可吹牛的內(nèi)容都是我干的橙垢。 我是一名探鬼主播,決...
    沈念sama閱讀 38,442評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼伦糯,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼钢悲!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起舔株,我...
    開(kāi)封第一講書(shū)人閱讀 37,105評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎还棱,沒(méi)想到半個(gè)月后载慈,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,601評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡珍手,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,066評(píng)論 2 325
  • 正文 我和宋清朗相戀三年办铡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辞做。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,161評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡寡具,死狀恐怖秤茅,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情童叠,我是刑警寧澤框喳,帶...
    沈念sama閱讀 33,792評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站厦坛,受9級(jí)特大地震影響五垮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜杜秸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,351評(píng)論 3 307
  • 文/蒙蒙 一放仗、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧撬碟,春花似錦诞挨、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,352評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至顾稀,卻和暖如春达罗,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背静秆。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,584評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工粮揉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人抚笔。 一個(gè)月前我還...
    沈念sama閱讀 45,618評(píng)論 2 355
  • 正文 我出身青樓扶认,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親殊橙。 傳聞我的和親對(duì)象是個(gè)殘疾皇子辐宾,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,916評(píng)論 2 344

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