123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- //
- // NIMSessionLayout.m
- // NIMKit
- //
- // Created by chris on 2016/11/8.
- // Copyright © 2016年 NetEase. All rights reserved.
- //
- #import "NIMSessionLayoutImpl.h"
- #import "UITableView+NIMScrollToBottom.h"
- #import "NIMMessageCell.h"
- #import "NIMGlobalMacro.h"
- #import "NIMSessionTableAdapter.h"
- #import "UIView+NIM.h"
- #import "NIMKitKeyboardInfo.h"
- @interface NIMSessionLayoutImpl()
- {
- NSMutableArray *_inserts;
- CGFloat _inputViewHeight;
- }
- @property (nonatomic,strong) UIRefreshControl *refreshControl;
- @property (nonatomic,strong) NIMSession *session;
- @property (nonatomic,strong) id<NIMSessionConfig> sessionConfig;
- @property (nonatomic,weak) id<NIMSessionLayoutDelegate> delegate;
- @end
- @implementation NIMSessionLayoutImpl
- - (instancetype)initWithSession:(NIMSession *)session
- config:(id<NIMSessionConfig>)sessionConfig
- {
- self = [super init];
- if (self) {
- _sessionConfig = sessionConfig;
- _session = session;
- _inserts = [[NSMutableArray alloc] init];
-
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(menuDidHide:) name:UIMenuControllerDidHideMenuNotification object:nil];
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillChangeFrame:) name:NIMKitKeyboardWillChangeFrameNotification object:nil];
- }
- return self;
- }
- - (void)dealloc
- {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- - (void)reloadTable
- {
- [self.tableView reloadData];
- }
- - (void)setTableView:(UITableView *)tableView
- {
- BOOL change = _tableView != tableView;
- if (change)
- {
- _tableView = tableView;
- [self setupRefreshControl];
- }
- }
- - (void)resetLayout
- {
- [self adjustInputView];
- [self adjustTableView];
- }
- - (void)layoutAfterRefresh
- {
- [self.refreshControl endRefreshing];
- [self.tableView reloadData];
- }
- - (void)adjustOffset:(NSInteger)row {
- if (row >= 0) {
- dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
- [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionTop animated:YES];
- });
- }
- }
- - (void)changeLayout:(CGFloat)inputViewHeight
- {
- BOOL change = _inputViewHeight != inputViewHeight;
- if (change)
- {
- _inputViewHeight = inputViewHeight;
- [self adjustInputView];
- [self adjustTableView];
- }
- }
- - (void)adjustInputView
- {
- UIView *superView = self.inputView.superview;
- UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
- if (@available(iOS 11.0, *))
- {
- safeAreaInsets = superView.safeAreaInsets;
- }
- self.inputView.nim_bottom = superView.nim_height - safeAreaInsets.bottom;
- }
- - (void)adjustTableView
- {
- //输入框是否弹起
- BOOL inputViewUp = NO;
- switch (self.inputView.status)
- {
- case NIMInputStatusText:
- inputViewUp = [NIMKitKeyboardInfo instance].isVisiable;
- break;
- case NIMInputStatusAudio:
- inputViewUp = NO;
- break;
- case NIMInputStatusMore:
- case NIMInputStatusEmoticon:
- inputViewUp = YES;
- default:
- break;
- }
- self.tableView.userInteractionEnabled = !inputViewUp;
- CGRect rect = self.tableView.frame;
-
- //tableview 的位置
- UIView *superView = self.tableView.superview;
- UIEdgeInsets safeAreaInsets = UIEdgeInsetsZero;
- if (@available(iOS 11.0, *))
- {
- safeAreaInsets = superView.safeAreaInsets;
- }
-
- CGFloat containerSafeHeight = self.tableView.superview.frame.size.height - safeAreaInsets.bottom;
-
- rect.size.height = containerSafeHeight - self.inputView.toolBar.nim_height;
-
-
- //tableview 的内容 inset
- UIEdgeInsets contentInsets = UIEdgeInsetsZero;
- CGFloat visiableHeight = 0;
- if (@available(iOS 11.0, *))
- {
- contentInsets = self.tableView.adjustedContentInset;
- }
- else
- {
- contentInsets = self.tableView.contentInset;
- }
- [self.tableView reloadData];
-
- //如果气泡过少,少于总高度,输入框视图需要顶到最后一个气泡的下面。
- visiableHeight = visiableHeight + self.tableView.contentSize.height + contentInsets.top + contentInsets.bottom;
- visiableHeight = MIN(visiableHeight, rect.size.height);
-
- rect.origin.y = containerSafeHeight - visiableHeight - self.inputView.nim_height;
- rect.origin.y = rect.origin.y > 0? 0 : rect.origin.y;
-
-
- BOOL tableChanged = !CGRectEqualToRect(self.tableView.frame, rect);
- if (tableChanged)
- {
- [self.tableView setFrame:rect];
- [self.tableView nim_scrollToBottom:YES];
- }
- }
- #pragma mark - Notification
- - (void)menuDidHide:(NSNotification *)notification
- {
- [UIMenuController sharedMenuController].menuItems = nil;
- }
- - (void)keyboardWillChangeFrame:(NSNotification *)notification
- {
- if (!self.tableView.window)
- {
- //如果当前视图不是顶部视图,则不需要监听
- return;
- }
- [self.inputView sizeToFit];
- }
- #pragma mark - Private
- - (void)calculateContent:(NIMMessageModel *)model{
- [model contentSize:self.tableView.nim_width];
- }
- - (void)setupRefreshControl
- {
- self.refreshControl = [[UIRefreshControl alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
- if (@available(iOS 10.0, *))
- {
- self.tableView.refreshControl = self.refreshControl;
- }
- else
- {
- [self.tableView addSubview: self.refreshControl];
- }
-
- [self.refreshControl addTarget:self action:@selector(headerRereshing:) forControlEvents:UIControlEventValueChanged];
-
- }
- - (void)headerRereshing:(id)sender
- {
- if ([self.delegate respondsToSelector:@selector(onRefresh)])
- {
- [self.delegate onRefresh];
- }
- }
- - (void)insert:(NSArray<NSIndexPath *> *)indexPaths animated:(BOOL)animated
- {
- if (!indexPaths.count)
- {
- return;
- }
- NSMutableArray *addIndexPathes = [NSMutableArray array];
- [indexPaths enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[obj integerValue] inSection:0];
- [addIndexPathes addObject:indexPath];
- }];
-
- // [self.tableView beginUpdates];
- // [self.tableView insertRowsAtIndexPaths:addIndexPathes withRowAnimation:UITableViewRowAnimationBottom];
- // [self.tableView endUpdates];
- [self.tableView reloadData];
- [UIView animateWithDuration:0.25 delay:0 options:7 animations:^{
- [self resetLayout];
- } completion:nil];
-
- [self.tableView nim_scrollToBottom:YES];
- }
- - (void)remove:(NSArray<NSIndexPath *> *)indexPaths
- {
- [self.tableView beginUpdates];
- [self.tableView deleteRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
- [self.tableView endUpdates];
- NSInteger row = [self.tableView numberOfRowsInSection:0] - 1;
- if (row > 0)
- {
- NSIndexPath *indexPath = [NSIndexPath indexPathForRow:row inSection:0];
- [self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:UITableViewScrollPositionBottom animated:YES];
- }
- }
- - (void)update:(NSIndexPath *)indexPath
- {
- NIMMessageCell *cell = (NIMMessageCell *)[self.tableView cellForRowAtIndexPath:indexPath];
- if (cell) {
- [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
- CGFloat scrollOffsetY = self.tableView.contentOffset.y;
- [self.tableView setContentOffset:CGPointMake(self.tableView.contentOffset.x, scrollOffsetY) animated:NO];
- }
- }
- - (BOOL)canInsertChatroomMessages
- {
- return !self.tableView.isDecelerating && !self.tableView.isDragging;
- }
- @end
|