如何创建一个简短地显示在UITableView(如UIRefreshControl)“上方”的状态消息?

我正在尝试用UIView补充一个UIRefreshControl ,其中包含一条消息( statusMessageView ),该消息在应用程序启动后出现在UITableViewController “上方”。 此视图将通知用户UITableViewController已刷新且不需要刷新。

以下是我要完成的细分:

该应用程序启动, UITableViewController显示正常然后向下滚动44px以显示statusMessageView (高度为44px)。

statusMessageView保持可见状态2秒

UITableViewController动画向上滚动到它的原始位置,有效地“ statusMessageViewstatusMessageView 。 (比如UIRefreshControl ,但用代码动画)

注意 :此statusMessageView将与UIRefreshControl一起使用,因此在显示之后需要“消失”,以便可以正常使用UIRefreshControl

我看过其他第三方“拉动刷新”控制器,但我认为由于我正在使用UIRefreshControl

看起来这里的其他答案正在为UINavigationBar下方的通知提供解决方案。 如果您仍在寻找位于UITableView的滚动视图中的解决方案,那么我会在表视图中添加自定义表头(而不是节头)。

以下是完成此任务所需的粗略步骤:

1.在加载时创建初始标题视图

我通常使用一个UIViewController子类,它拥有一个UITableView实例变量(而不是使用UITableViewController),但你应该能够通过任一设置来完成这个任务。 在tableview中设置代码(可能在viewDidLoad中),在其中设置backgroundColor,contentInset,separatorStyle等内容,创建一个将成为标题的UILabel。 然后将此UILabel设置为tableView的tableHeaderView。 当然,如果你想为这个“通知部分”制作一些更复杂的东西,请随意使用嵌套的UILabel +其他东西制作UIView。 所以类似于:

 UILabel *headerLabel = [[UILabel alloc] initWithFrame:CGRectMake(0.0f, 0.0f, self.tableView.bounds.size.width, 44.0f)]; headerLabel.backgroundColor = [UIColor clearColor]; // Just in case you have some fancy background/color in your table view headerLabel.textAlignment = UITextAlignmentCenter; headerLabel.font = .... headerLabel.textColor = .... headerLabel.text = @"You are an awesome user!"; self.tableView.tableHeaderView = headerLabel; 

2.将您的tableview设置为“正常”加载(即不显示标题)

同样,在viewDidLoad中,您需要正确设置tableview的contentOffset和alwaysBounceVertical以在加载时隐藏此标题视图。 设置为标题高度的contentOffset将启动tableview的标题正下方的y坐标。 alwaysBounceVertical设置为YES将允许您的tableview正常运行,即使您的tableview的contentsize小于您的屏幕大小。 所以类似于:

 self.tableView.contentOffset = (CGPoint){0.0f, 44.0f}; self.tableView.alwaysBounceVertical = YES; 

3.向下添加滑块并滑开

好的,现在有几种方法可以做到这一点。 在viewDidAppear上,您可以创建一个链式UIView动画,其中第一个动画向下滑动tableview(即。将contentOffset设置为{0.0f,0.0f})延迟一秒,第二个动画将桌面视图滑回(即设置) contentOffset为{0.0f,44.0f})延迟两秒。 或者您可以使用GCD并将两个动画安排为async +延迟块。 无论哪种方式都很好(并且可能还有两三种其他好方法可以实现这一点),但只是为了实现这个想法…你可以像这样链接动画:

 __weak MyCustomViewController *me = self; [UIView animateWithDuration:0.4f delay:1.0f options:UIViewAnimationOptionAllowUserInteraction animations:^ { me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; } completion:^(BOOL finished) { if (me.tableView) { [UIView animateWithDuration:0.4f delay:2.0f options:UIViewAnimationOptionAllowUserInteraction animations:^ { me.tableView.contentOffset = (CGPoint){0.0f, 44.0f}; } completion:^(BOOL finished) { if (me.tableView) { me.tableView.tableHeaderView = nil; // If you want to completely get rid of this notification header me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; // I'm unsure if this will cause the tableview to jump... if it does, you can animate the headerview away instead of animating the tableview up to hide the header, then setting header to nil and reseting the contentOffset // or me.tableView.tableHeaderView.hidden = YES; // If you want to just hide the header } }]; } }]; 

我编写了示例代码而没有测试任何代码……呵呵,所以它可能无法正常工作。 如果您需要更多帮助,我很乐意帮助您充实! 祝你好运。

更新:允许用户滚动以取消动画

我不太确定你希望桌面上的用户交互对动画做什么。 如果您只是想在用户开始滚动时取消动画,那么我会使用GCD(参见下面的代码)。 但我可以通过其他方式看到动画可以通过用户触摸进行操作,因此它取决于您要查找的内容。 在任何情况下,假设任何用户触摸应该禁用下一个预定的动画,然后可以使用两个函数来实现:

 - (void)scheduleShowHeaderAnimation { __weak MyCustomViewController *me = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0f * NSEC_PER_SEC), dispatch_get_main_queue(), ^ // Start animating after 1 sec delay { if (me.tableView) // Make sure the tableview is still around { if (! me.tableView.tracking && // Don't show animation if user has begun to touch contentview ! me.tableView.dragging && // Don't show animation if user has begun to drag contentview ! me.tableView.decelerating) // Don't show animation if dragging happened and scrollview is starting to decelerate { [UIView animateWithDuration:0.4f delay:0.0f options:UIViewAnimationOptionAllowAnimatedContent // This will make sure user can interact with tableview while animation is going on animations:^ { me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; } completion:^(BOOL finished) { [me scheduleHideHeaderAnimation]; }]; } } }); } - (void)scheduleHideHeaderAnimation { __weak MyCustomViewController *me = self; dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2.0f * NSEC_PER_SEC), dispatch_get_main_queue(), ^ // Start animating after 2 secs delay { if (me.tableView) // Make sure the tableview is still around { if (! me.tableView.tracking && // Don't show animation if user has begun to touch contentview ! me.tableView.dragging && // Don't show animation if user has begun to drag contentview ! me.tableView.decelerating) // Don't show animation if dragging happened and scrollview is starting to decelerate { [UIView animateWithDuration:0.4f delay:0.0f options:UIViewAnimationOptionAllowAnimatedContent // This will make sure user can interact with tableview while animation is going on animations:^ { me.tableView.contentOffset = (CGPoint){0.0f, 44.0f}; } completion:^(BOOL finished) { if (me.tableView) { me.tableView.tableHeaderView = nil; // If you want to completely get rid of this notification header me.tableView.contentOffset = (CGPoint){0.0f, 0.0f}; // I'm unsure if this will cause the tableview to jump... if it does, you can animate the headerview away instead of animating the tableview up to hide the header, then setting header to nil and reseting the contentOffset // or me.tableView.tableHeaderView.hidden = YES; // If you want to just hide the header } }]; } } }); } 

我会在viewDidAppear中调用scheduleShowHeaderAnimation。

然后为了支持在用户已经向下滚动tableview时隐藏标题,我将实现- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView of UIScrollViewDelegate并添加如下内容:

 if (self.tableView.tableHeaderView != nil) { self.tableView.tableHeaderView = nil; } // or if (self.tableView.tableHeaderView.hidden == NO) { self.tableView.tableHeaderView.hidden = YES; } 

如果您想要支持更复杂的交互,或者您希望动画以不同方式响应用户触摸,则可能需要覆盖其他UIScrollViewDelegate方法,并且当用户开始与scrollview(父类)交互时的表视图),然后更改动画的行为。

这会让你更接近你想要的吗?

除了@Khawar的答案,还有另一种选择:
https://github.com/toursprung/TSMessages

您可以使用以下库来实现此目的。 您可以根据需要设置自动隐藏持续时间。 您还可以自定义其外观。

https://github.com/tciuro/NoticeView

它可以通过一种非常简单的方式完成:您只需在刷新控件中创建并插入子视图:

 - (void)viewDidLoad { [super viewDidLoad]; ... UIView *smView = [self statusMessageView]; [self.refreshControl insertSubview: smView atIndex: 0]; // to show and hide the view inserted in refresh control // With this transparent loader color even the middle area is not covered // so you can have all the space to show your message self.refreshControl.tintColor = [UIColor colorWithWhite:1.0 alpha:0.0]; [self.refreshControl beginRefreshing]; [self afterDelay: 2.0 performBlock: ^(){ [self.refreshControl endRefreshing]; // this delay is needed to prevent loader animation becoming visible // while the refresh control is being hidden [self afterDelay: 0.25 performBlock: ^(){ self.refreshControl.tintColor = nil; }); }); ... } -(void)afterDelay: (float)seconds performBlock: (void (^)())block { dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(seconds * NSEC_PER_SEC)); dispatch_after(popTime, dispatch_get_main_queue(), block); } -(UIView)statusMessageView { ... return view; } 

您需要的视图大小为320x43px(如果它更高,其底部将隐藏刷新控件可见),中间区域(大约35px)将被加载器动画覆盖(但最初显示消息时不会)。

我使用UIImageView在那里显示应用程序徽标(它甚至更简单:见这里 )。

在开始拉动之前,我可能更愿意(作为用户)不要看到此消息。 当我开始拉动时,我将看到在刷新开始之前不需要更新(当你下拉大约两倍于该子视图的高度时它开始,因此用户将有时间看看那里有什么以及是否需要刷新)。 如果表格中有未读项目(推文,post等),您可以在该视图中显示未读项目的数量。

但这是个人偏好的问题,它的完成方式似乎以一种非常简单的方式实现了你想要的。 我测试过,一切正常。