当我使用当前滚动位置滚动到顶部时,如何重新加载UITableView? (比如聊天应用)

时间:2016-02-13 12:41:39

标签: ios objective-c swift uitableview chat

我现在在聊天屏幕上工作(UITableView +输入TextField)。

当我滚动到顶部时,我希望我的UITableView重新加载更多聊天消息保持当前滚动位置(如果我更多地加载20条消息,我仍然会看到第21条消息。) KakaoTalk 应用正在执行此操作。在那个应用程序中,我可以无限滚动,因为滚动位置停留。(我的意思是我仍然看到相同的聊天消息)

我正在检查tableView:willDisplayCell:forRowAtIndexPath:中的行索引,所以当索引为0时我会获取更多的聊天消息。我完成了从DB获取更多消息的逻辑,但我没有完成抛光UI。

这是代码。

func tableView(tableView: UITableView, willDisplayCell cell: UITableViewCell, forRowAtIndexPath indexPath: NSIndexPath) {
    if indexPath.row == 0 && !isTableViewLoading {
        if photo.chatMessages.count != chatMessages.count {
            var loadingChatItems: Array<ChatMessage>

            let start = photo.chatMessages.count - chatMessages.count - Metric.ChatMessageFetchAmount
            if start > 0 {
                loadingChatItems = Database.loadChatMessages(photoId, startIndex: start, amount: Metric.ChatMessageFetchAmount)
            } else {
                loadingChatItems = Database.loadChatMessages(photoId, startIndex: 0, amount: Metric.ChatMessageFetchAmount + start)
            }

            chatMessages = loadingChatItems + chatMessages

            isTableViewLoading = true

            var indexPaths = Array<NSIndexPath>()
            for row in 0..<loadingChatItems.count {
                let indexPath = NSIndexPath(forRow: row, inSection: 0)
                indexPaths.append(indexPath)
            }

            tableView.scrollEnabled = false
            tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: UITableViewRowAnimation.None)
        }
    } else {
        isTableViewLoading = false
        tableView.scrollEnabled = true
    }
}

有什么建议吗?

3 个答案:

答案 0 :(得分:3)

Swift 3

这篇文章有点陈旧,但这里有一个解决方案:

1)在scrollViewDidScroll,

中滚动到顶部时检测到

2)加载新消息

3)保存contentSize,重新加载tableView

4)将tableView的contentOffset.y设置为(newContentSizeHeight - oldContentSizeHeight),这正好是当前点

这里是代码:

func scrollViewDidScroll(_ scrollView: UIScrollView) {
    if scrollView == tableView { 
        if tableView.contentOffset.y < 50 {
            loadMessages()
            let oldContentSizeHeight = tableView.contentSize.height
            tableView.reloadData()
            let newContentSizeHeight = tableView.contentSize.height
            tableView.contentOffset = CGPoint(x:tableView.contentOffset.x,y:newContentSizeHeight - oldContentSizeHeight)
        }
    }
}

答案 1 :(得分:0)

viewDidLoad

self.refreshControl?.addTarget(self, action: "refresh:", forControlEvents: UIControlEvents.ValueChanged)

然后添加功能:

func refresh(refreshControl: UIRefreshControl) {

    //your code here

    refreshControl.endRefreshing()

}

这将允许用户向上滚动以刷新UITableView。

答案 2 :(得分:0)

我已经实现了另一种解决方案,它使用委托中的滚动侦听器以及异步服务的响应。

因此,它会在没有动画的情况下滚动到开始加载更多消息的位置,因为消息已附加到我的数组中(这几乎不会影响过渡)。

我之所以决定这样做,是因为第一个解决方案有一个问题,那就是当您自动设置行高时,新的内容高度将不准确。

这是我的代码。

- (void) scrollViewDidScroll:(UIScrollView*)scrollView  {
    if (!topReached && scrollView == self.table) {
        if (!isLoadingTop && self.table.contentOffset.y < 40) {
            isLoadingTop = YES;
            [self loadChat];
        }
    }
}

// method used by the response of the async service
- (void)fillMessages: (NSArray*) messageArray {
    if ([messageArray count] == 0) {
        topReached = YES;
    } else {

        if ([messageArray count] < limit) {
            topReached = YES;
        }
        for (int i=0; i<messageArray.count; i++) {
            NSDictionary* chat = [messageArray objectAtIndex:i];
            [messages insertObject:[[MessageModel alloc] initWithDictionary:chat] atIndex:i];
        }

        [table reloadData];
        if (!isLoadingTop)
            [self scrollToBottom];
        else {
            isLoadingTop = NO;
            [self.table
                scrollToRowAtIndexPath:[NSIndexPath indexPathForRow:[messageArray count] inSection:0]
                atScrollPosition:UITableViewScrollPositionTop animated:false];
        }

        offset += limit;
    }
}

作为辅助信息,我想在视图控制器中阻止对异步服务消耗的访问,因此在同一视图中只能调用一次服务。