您好,登錄后才能下訂單哦!
這篇文章將為大家詳細講解有關iOS如何實現搭建聊天頁面,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。
功能分析,模仿QQ聊天頁面
輸入框失去第一響應的情況:
1:點擊頁面
2:下滑頁面
輸入框成為第一響應的情況:
1:開始輸入
2:上滑頁面最底部
控制器
// // WDPersonMessageDetailVC.m // WestDevelopment // // Created by wangtao on 2017/6/23. // Copyright © 2017年 xikaijinfu. All rights reserved. // #import "WDPersonMessageDetailVC.h" #import "WDPersonMessageDetailCell.h" #import "WDPersonMessageFooterCell.h" #import "WDPersonMessageDetailModel.h" #import <IQKeyboardManager.h> @interface WDPersonMessageDetailVC () @property (nonatomic, weak) WDPersonMessageFooterCell *textfieldView; @end @implementation WDPersonMessageDetailVC - (void)scrollViewDidScroll:(UIScrollView *)scrollView { CGFloat contentOffsetY = scrollView.contentOffset.y; // 頁面下滑,并且輸入框還是第一響應的時候,控制器要失去第一響應 if (contentOffsetY > 10) { if (self.textfieldView.isFirst) { [self clickSelf]; } } // 頁面上滑,控制器成為第一響應 if (contentOffsetY < - 10) { self.textfieldView.isFirst = YES; } } - (void)viewDidAppear:(BOOL)animated { [super viewDidAppear:animated]; // 關閉IQ鍵盤 [IQKeyboardManager sharedManager].enable = NO; [IQKeyboardManager sharedManager].enableAutoToolbar = NO; } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; [self.view endEditing:YES]; } - (void)viewDidDisappear:(BOOL)animated { [super viewDidDisappear:animated]; [IQKeyboardManager sharedManager].enableAutoToolbar = YES; [IQKeyboardManager sharedManager].enable = YES; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } - (void)loadView { UIScrollView *view = [[UIScrollView alloc] init]; view.frame = CGRectMake(0, 0, kMainScreenWidth, kMainScreenHeight); self.view = view; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. [IQKeyboardManager sharedManager].enable = NO; [IQKeyboardManager sharedManager].enableAutoToolbar = NO; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillHide:) name:UIKeyboardWillHideNotification object:nil]; // 旋轉tableView self.tableView.transform = CGAffineTransformMakeScale (1, -1); self.tableView.tableHeaderView.transform = CGAffineTransformMakeScale (1, -1); self.tableView.tableFooterView.transform = CGAffineTransformMakeScale (1, -1); self.view.backgroundColor = WTHexColor(0xeaeaea); self.tableView.backgroundColor = WTHexColor(0xeaeaea); self.tableView.scrollIndicatorInsets = UIEdgeInsetsMake(50, 0, 0, 0); [self.tableView registerClass:[WDPersonMessageDetailCell class] forCellReuseIdentifier:WDPersonMessageDetailCellID]; [self.tableView registerClass:[WDPersonMessageFooterCell class] forHeaderFooterViewReuseIdentifier:WDPersonMessageFooterCellID]; [self.tableView wt_addTapTarget:self action:@selector(clickSelf)]; [self addFooter]; } //鍵盤彈出時把消息列表tableView的高度設為(屏幕高度 - 輸入框高度 - 鍵盤高度),同時輸入框上移; //鍵盤消失時再把tableView的高度設為(屏幕高度 - 輸入框的高度),同時輸入框下移。 //這樣可以完美解決聊天列表的上面的消息無法顯示問題和鍵盤遮擋問題。 - (void)keyboardWillShow:(NSNotification*)notification { // 0.取出鍵盤動畫的時間 CGFloat duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; // 1.取得鍵盤最后的frame CGRect keyboardFrame = [notification.userInfo[UIKeyboardFrameEndUserInfoKey] CGRectValue]; // 2.計算控制器的view需要平移的距離 CGFloat transformY = keyboardFrame.origin.y - self.view.frame.size.height; // 3.執行動畫 NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0]; [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:NO]; WTWS(weakSelf); dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.05 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ [UIView animateWithDuration:duration animations:^{ weakSelf.tableView.frame = CGRectMake(0, 0, kMainScreenWidth, kMainScreenHeight - keyboardFrame.size.height - 64); weakSelf.inputView.transform = CGAffineTransformMakeTranslation(0, transformY); }]; }); } - (void)keyboardWillHide:(NSNotification*)notification { CGFloat duration = [notification.userInfo[UIKeyboardAnimationDurationUserInfoKey] doubleValue]; [UIView animateWithDuration:duration animations:^{ self.tableView.frame = CGRectMake(0, 0, kMainScreenWidth, kMainScreenHeight); self.view.transform = CGAffineTransformIdentity; }]; } //失去第一響應 - (void)clickSelf { [[NSNotificationCenter defaultCenter] postNotificationName:kMessageState object:@(YES)]; } - (void)addHeader { __unsafe_unretained __typeof(self) weakSelf = self; self.tableView.mj_header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{ [weakSelf loadData]; }]; [self.tableView.mj_header beginRefreshing]; } //關閉下拉和上拉控件的文字展示 - (void)addFooter { // [self addHeader]; [self loadData]; MJRefreshAutoNormalFooter *footer = [MJRefreshAutoNormalFooter footerWithRefreshingTarget:self refreshingAction:@selector(loadMoreData)]; [footer setTitle:@"" forState:MJRefreshStateIdle]; [footer setTitle:@"" forState:MJRefreshStatePulling]; [footer setTitle:@"" forState:MJRefreshStateRefreshing]; [footer setTitle:@"" forState:MJRefreshStateWillRefresh]; [footer setTitle:@"" forState:MJRefreshStateNoMoreData]; self.tableView.mj_footer = footer; } - (void)loadData { self.page = 1; NSDictionary *par = @{ kToken : [WTAccount shareAccount].token, kUserId : [WTAccount shareAccount].uid, kCurrentPage : @(self.page), kFriendId : self.friendId, }; [WDNetwork postkMyMessageDetailPhoneWithParameters:par modelClass:[WDPersonMessageDetailModel class] responseBlock:^(id dataObject, NSError *error) { if (!error && [[dataObject class] isSubclassOfClass:[NSArray class]]) { NSArray* reversedArray = [[dataObject reverseObjectEnumerator] allObjects]; self.dataArray = [NSMutableArray arrayWithArray:reversedArray]; [self.tableView reloadData]; self.page ++; if ([dataObject count] < 20) { [self.tableView.mj_header endRefreshing]; [self.tableView.mj_footer endRefreshingWithNoMoreData]; } else { [self.tableView.mj_header endRefreshing]; [self.tableView.mj_footer endRefreshing]; } } else { [self.tableView.mj_header endRefreshing]; [self.tableView.mj_footer endRefreshingWithNoMoreData]; } }]; } - (void)loadMoreData { NSDictionary *par = @{ kToken : [WTAccount shareAccount].token, kUserId : [WTAccount shareAccount].uid, kCurrentPage : @(self.page), kFriendId : self.friendId, }; [WDNetwork postkMyMessageDetailPhoneWithParameters:par modelClass:[WDPersonMessageDetailModel class] responseBlock:^(id dataObject, NSError *error) { if (!error && [[dataObject class] isSubclassOfClass:[NSArray class]]) { NSArray* reversedArray = [[dataObject reverseObjectEnumerator] allObjects]; [self.dataArray addObjectsFromArray:reversedArray]; [self.tableView reloadData]; self.page ++; if ([dataObject count] < 20) { [self.tableView.mj_footer endRefreshingWithNoMoreData]; } else { [self.tableView.mj_footer endRefreshing]; } } else { [self.tableView.mj_footer endRefreshingWithNoMoreData]; } }]; } - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { return 50; } - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { return CGFLOAT_MIN; } - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { WDPersonMessageFooterCell *footer = [tableView dequeueReusableHeaderFooterViewWithIdentifier:WDPersonMessageFooterCellID]; self.textfieldView = footer; footer.contentView.transform = CGAffineTransformMakeScale (1, -1); WTWS(weakSelf); footer.clickSenderText = ^(NSString *text) { NSDictionary *par = @{ kToken : [WTAccount shareAccount].token, kUserId : [WTAccount shareAccount].uid, kComment : text, kFlag : @(11), kFriendId : weakSelf.friendId, }; [WDNetwork postkAddCommentPhoneWithParameters:par modelClass:[NSNull class] responseBlock:^(id dataObject, NSError *error) { if (!error && ([[dataObject objectForKey:kCode] integerValue] == 200)) { [weakSelf loadData]; weakSelf.textfieldView.sendSucceed = YES; } else if (!error && [dataObject objectForKey:kMsg]) { } }]; }; footer.resignFirstRes = ^{ weakSelf.tableView.frame = CGRectMake(0, 0, kMainScreenWidth, kMainScreenHeight - 64); weakSelf.view.transform = CGAffineTransformIdentity; }; return footer; } - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { return 1; } - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { return self.dataArray.count; } - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { WDPersonMessageDetailModel *model = self.dataArray[indexPath.row]; return model.height; } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { WDPersonMessageDetailCell *cell = [tableView dequeueReusableCellWithIdentifier:WDPersonMessageDetailCellID forIndexPath:indexPath]; cell.model = self.dataArray[indexPath.row]; cell.contentView.transform = CGAffineTransformMakeScale (1, -1); return cell; } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
輸入框 UITableViewHeaderFooterView
// // WDPersonMessageFooterCell.h // WestDevelopment // // Created by wangtao on 2017/6/26. // Copyright © 2017年 xikaijinfu. All rights reserved. // #import "WDBaseTVHeaderFooterView.h" typedef void(^ClickSender_t)(NSString *text); typedef void(^ResignFirstResponder)(); @interface WDPersonMessageFooterCell : WDBaseTVHeaderFooterView @property (nonatomic, copy) ClickSender_t clickSenderText; @property (nonatomic, copy) ResignFirstResponder resignFirstRes; @property (nonatomic, assign) BOOL isFirst; @property (nonatomic, assign) BOOL sendSucceed; @end
// // WDPersonMessageFooterCell.m // WestDevelopment // // Created by wangtao on 2017/6/26. // Copyright © 2017年 xikaijinfu. All rights reserved. // #import "WDPersonMessageFooterCell.h" @interface WDPersonMessageFooterCell () <UITextFieldDelegate> @property (nonatomic, weak) UITextField *textField; @property (nonatomic, weak) UIView *line; @end @implementation WDPersonMessageFooterCell @synthesize isFirst = _isFirst; - (void)setupAll { self.contentView.backgroundColor = WTHexColor(0xf2f2f2); UITextField *textField = [[UITextField alloc] init]; textField.backgroundColor = kWhiteColor; [self.contentView addSubview:textField]; textField.delegate = self; self.textField = textField; textField.layer.cornerRadius = 3; textField.layer.masksToBounds = YES; textField.returnKeyType = UIReturnKeySend; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(messageState:) name:kMessageState object:nil]; UIView *line = [[UIView alloc] init]; line.backgroundColor = WTHexColor(0xdddddd); [self.contentView addSubview:line]; self.line = line; } - (void)messageState:(NSNotification *)noti { NSInteger state = [[noti object] boolValue]; if (state) { [self.textField resignFirstResponder]; if (self.resignFirstRes) { self.resignFirstRes(); } } } - (BOOL)textFieldShouldReturn:(UITextField *)textField { if (self.clickSenderText) { self.clickSenderText(self.textField.text); } return YES; } - (void)setIsFirst:(BOOL)isFirst { _isFirst = isFirst; if (isFirst) { [self.textField becomeFirstResponder]; } else { [self.textField resignFirstResponder]; } } - (BOOL)isFirst { if ([self.textField isFirstResponder]) { return YES; } return NO; } - (void)setSendSucceed:(BOOL)sendSucceed { self.textField.text = @""; } - (void)layoutSubviews { [super layoutSubviews]; CGFloat padding = 10; self.textField.frame = CGRectMake(padding, padding, self.wt_width - padding * 2, self.wt_height - padding * 2); self.line.frame = CGRectMake(0, 0, self.wt_width, .5); } @end
消息cell
// // WDPersonMessageDetailCell.m // WestDevelopment // // Created by wangtao on 2017/6/23. // Copyright © 2017年 xikaijinfu. All rights reserved. // #import "WDPersonMessageDetailCell.h" #import "WDPersonMessageDetailModel.h" @interface WDPersonMessageDetailCell () @property (nonatomic, weak) UILabel *time; @property (nonatomic, weak) UIImageView *icon; @property (nonatomic, weak) UILabel *detail; @property (nonatomic, weak) UIView *baseView; @end @implementation WDPersonMessageDetailCell - (void)setupAll { self.selectionStyle = UITableViewCellSelectionStyleNone; self.backgroundColor = WTHexColor(0xeaeaea); self.contentView.backgroundColor = WTHexColor(0xeaeaea); UILabel *time = [UILabel labelWithText:@"" textColor:WTHexColor(0xaaaaaa) textAlignment:NSTextAlignmentCenter font:12 backgroundColor:kClearColor]; [self.contentView addSubview:time]; self.time = time; UIImageView *icon = [[UIImageView alloc] init]; [self.contentView addSubview:icon]; icon.image = [UIImage imageNamed:kDefault]; self.icon = icon; self.icon.layer.cornerRadius = 35 / 2; self.icon.layer.masksToBounds = YES; UIView *baseView = [[UIView alloc] init]; [self.contentView addSubview:baseView]; self.baseView = baseView; baseView.layer.masksToBounds = YES; baseView.layer.cornerRadius = 4; UILabel *detail = [UILabel labelWithText:@"" textColor:kBlackColor textAlignment:NSTextAlignmentLeft font:13 backgroundColor:kClearColor]; [baseView addSubview:detail]; self.detail = detail; detail.numberOfLines = 0; } - (void)setModel:(WDPersonMessageDetailModel *)model { _model = model; if ([model.isShow isEqualToString:@"1"]) { self.time.text = model.addTime; self.time.hidden = NO; self.time.frame = CGRectMake(0, 0, kMainScreenWidth, 20); } else { self.time.text = @""; self.time.hidden = YES; self.time.frame = CGRectZero; } self.time.text = model.addTime; [self.icon wt_setImageWithUrlString:model.headImg placeholderString:@"me_icon"]; self.detail.text = model.comment; if ([model.userId isEqualToString:[WTAccount shareAccount].uid]) { self.detail.textColor = kBlackColor; self.baseView.backgroundColor = kWhiteColor; self.icon.frame = CGRectMake(kPadding, self.time.wt_bottom + kPadding, 35, 35); self.baseView.frame = CGRectMake(self.icon.wt_right + kPadding, self.icon.wt_top, model.commentW, model.commentH); self.detail.frame = CGRectMake(kPadding, kPadding, model.commentW - kPadding * 2, model.commentH - kPadding * 2); } else { self.detail.textColor = kWhiteColor; self.baseView.backgroundColor = kHomeColor; self.icon.frame = CGRectMake(kMainScreenWidth - 35 - kPadding, self.time.wt_bottom + kPadding, 35, 35); self.baseView.frame = CGRectMake(self.icon.wt_left - kPadding - model.commentW, self.icon.wt_top, model.commentW, model.commentH); self.detail.frame = CGRectMake(kPadding, kPadding, model.commentW - kPadding * 2, model.commentH - kPadding * 2); } } @end
模型
// // WDPersonMessageDetailModel.m // WestDevelopment // // Created by wangtao on 2017/6/23. // Copyright © 2017年 xikaijinfu. All rights reserved. // #import "WDPersonMessageDetailModel.h" @implementation WDPersonMessageDetailModel - (CGFloat)commentW { if (_commentW == 0) { _commentW = [self.comment wt_calculateStringSizeWithFontOfSize:13 maxWidth:kMainScreenWidth / 2].width + 20; } return _commentW; } - (CGFloat)commentH { if (_commentH == 0) { CGFloat textH = [self.comment wt_calculateStringSizeWithFontOfSize:13 maxWidth:kMainScreenWidth / 2].height; // 一行字體是15高,一行的情況就和頭像一樣高 _commentH = (textH < 20) ? 35 : (textH + 20); } return _commentH; } - (CGFloat)height { if (_height == 0) { _height = self.commentH + 20; if ([self.isShow isEqualToString:@"1"]) { _height += 20; } } return _height; } @end
關于“iOS如何實現搭建聊天頁面”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,使各位可以學到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。