3

我正在尝试UIRefreshControl用包含一条UIView消息(此视图将通知用户已刷新,不需要刷新。statusMessageViewUITableViewControllerUITableViewController

以下是我要完成的工作的细分:

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

statusMessageView保持可见 2 秒

动画滚动到它的UITableViewController原始位置,有效地“statusMessageView收起”。(类似UIRefreshControl,但用代码动画)

注意:这个statusMessageView会和a配合使用UIRefreshControl,所以显示后需要“走开”UIRefreshControl才能正常使用

我看过其他第 3 方“拉动刷新”控制器,但我认为这是矫枉过正,因为我正在使用UIRefreshControl

4

4 回答 4

2

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

于 2013-05-28T05:38:52.297 回答
2

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

以下是完成此操作所需的粗略步骤:

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

我通常使用拥有 UITableView 实例变量的 UIViewController 子类(而不是使用 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})延迟一秒,第二个动画将 tableview 向上滑动(即设置contentOffset 到 {0.0f, 44.0f}) 延迟两秒。或者您可以使用 GCD 并将两个动画安排为异步 + 延迟块。无论哪种方式都很好(并且可能有两种或三种其他好的方法可以实现这一点),但只是为了传达这个想法......你可以像这样链接动画:

__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 时,为了支持隐藏标题,我将实现UIScrollViewDelegate中的一个- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate或添加类似的内容:- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView

if (self.tableView.tableHeaderView != nil)
{
    self.tableView.tableHeaderView = nil;
}

// or

if (self.tableView.tableHeaderView.hidden == NO)
{
    self.tableView.tableHeaderView.hidden = YES;
}

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

这会让你更接近你正在寻找的东西吗?

于 2013-05-30T10:27:05.523 回答
0

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

- (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;
}

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

我使用 UIImageView 在那里显示应用程序徽标(它更简单:请参见此处)。

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

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

于 2013-06-01T00:06:29.467 回答
0

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

https://github.com/tciuro/NoticeView

于 2013-05-27T13:28:45.767 回答