【问题标题】:UIRefreshControl incorrect title offset during first run and sometimes title missingUIRefreshControl 首次运行时标题偏移不正确,有时标题丢失
【发布时间】:2013-10-07 21:55:15
【问题描述】:

第一次启动 UIRefreshControl 时文本偏移错误...稍后有时刷新文本根本不显示,只有刺可见

我认为 iOS6 没有这个问题...可能与 iOS7 有关

在作为子项添加到 VC 的 UITableViewController 中,它驻留在模态呈现的 UINavigationController 中

- (void)viewDidLoad {

    [super viewDidLoad];

    [self setRefreshControlText:@"Getting registration data"];
    [self.refreshControl beginRefreshing];
}

- (void)setRefreshControlText:(NSString *)text {

    UIFont * font = [UIFont fontWithName:@"Helvetica-Light" size:10.0];
    NSDictionary *attributes = @{NSFontAttributeName:font, NSForegroundColorAttributeName : [UIColor blackColor]};
    self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:text attributes:attributes];

}

【问题讨论】:

  • 是发生在模拟器上还是真机上?我在这个问题上花了几个小时,当我在真实设备上尝试相同的代码时,它运行得很顺利。
  • 您找到解决方案了吗?我也遇到了同样的问题。
  • 没有任何工作 100% :( 对我来说
  • @FelixGuerrero 看到答案,终于找到解决办法了
  • Apple 会解决这个问题吗?

标签: cocoa-touch uitableview ios7 uirefreshcontrol


【解决方案1】:

当您在下拉 tableView 时更改属性标题时,UIRefreshControl 在 IOS9.3 上似乎仍然被破坏。似乎可行的是继承 UIRefreshControl 并在(属性)标题更改后强制更新其布局。 核心修复是触发对 tableView contentOffset 的更改(在布局微调器和文本子视图的 _update 方法中导致一些隐藏的魔法)并另外强制帧高度为其预期值,以确保背景颜色填充下拉区域。

@implementation MEIRefreshControl
{
    __weak UITableView* _tableView;
}

- (instancetype)initWithTableView:(UITableView*)tableView
{
    self = [super initWithFrame:CGRectZero];
    if (self)
    {
        _tableView = tableView;
    }

    return self;
}

@synthesize title = _title;

- (void)setTitle:(NSString *)title
{
    if (!PWEqualObjects(_title, title))
    {
        _title = title;
        self.attributedTitle = [[NSAttributedString alloc] initWithString:_title ? _title : @""];

        [self forceUpdateLayout];
    }
}

- (void)forceUpdateLayout
{
    CGPoint contentOffset = _tableView.contentOffset;
    _tableView.contentOffset = CGPointZero;
    _tableView.contentOffset = contentOffset;
    CGRect frame = self.frame;
    frame.size.height = -contentOffset.y;
    self.frame = frame;
}

@end

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,我确实通过在初始化刷新控件后直接设置带有空格字符串的属性文本来刷新控件来解决它

    _refreshControl = [[UIRefreshControl alloc]init];
    [_refreshControl setAttributedTitle:[[NSAttributedString alloc]initWithString:@" "]];
    

    之后,将新的属性文本设置为刷新控件就没有任何问题了。

    [[self refreshControl] setAttributedTitle:[[NSAttributedString alloc]initWithString:[NSString stringWithFormat:@"Последнее обновление: %@", [dateFormat stringFromDate:[_post dateUpdated]]]]];
    

    更新

    我注意到当我使用 attrsDictionary 时问题又出现了:

    这段代码运行良好

    NSAttributedString* attributedString = [[NSAttributedString alloc]initWithString:string];
    [[self refreshControl] setAttributedTitle: attributedString];
    

    这使得 refreshControl 的标题在视图加载后直接出现

    NSAttributedString* attributedString = [[NSAttributedString alloc]initWithString:string attributes:attrsDictionary];
    [[self refreshControl] setAttributedTitle: attributedString];
    

    我还没找到解决办法。

    更新

    终于找到解决办法了,refreshcontrol init set attributes string 后也带有attributes:attrsDictionary

    NSDictionary *attrsDictionary = [NSDictionary dictionaryWithObjects:
                                     [NSArray arrayWithObjects:[UIColor appDarkGray], [UIFont fontWithName:@"OpenSans-CondensedLight" size:14.0f], nil] forKeys:
                                     [NSArray arrayWithObjects:NSForegroundColorAttributeName, NSFontAttributeName, nil]];
    [_refreshControl setAttributedTitle:[[NSAttributedString alloc]initWithString:@" " attributes:attrsDictionary]];
    

    所以之后设置新的刷新控件的标题就没有问题了。

    【讨论】:

      【解决方案3】:

      我的解决方案是在viewDidAppear中设置一个文本,无需调用

      beginRefreshingendRefreshing 在 mainQueue 上

      -(void)viewDidAppear:(BOOL)animated
      {
          [super viewDidAppear:animated];
      
          NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
          [formatter setDateFormat:@"d MMM, HH:mm"];
          NSString *lastUpdated = [NSString stringWithFormat:NSLocalizedString(@"refresh_last_updated", nil),[formatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:[[[DatabaseController sharedInstance] getCurrentSettings].lastTimeStamp doubleValue]]]];
          UIFont *font = [UIFont fontWithName:FONT_LATO_LIGHT size:12.0f];
          NSAttributedString *attrString = [[NSAttributedString alloc] initWithString:lastUpdated attributes:@{NSFontAttributeName:font}];
      
          _refreshControl.attributedTitle = attrString;
      }
      

      【讨论】:

        【解决方案4】:

        我遇到了同样的问题,对我来说,在设置属性标题后它与 layoutIfNeeded 一起工作:

        - (void)setRefreshControlText:(NSString *)text
        {
            UIColor *fg = [UIColor colorWithWhite:0.4 alpha:1.0];
            NSDictionary *attrsDictionary = @{NSForegroundColorAttributeName: fg};
            self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:text attributes:attrsDictionary];
            [self.refreshControl layoutIfNeeded];
        }
        

        Cédric 建议使用[self.refreshControl setNeedsLayout],但这不会强制立即更新视图,因此您必须使用layoutIfNeeded

        【讨论】:

          【解决方案5】:

          这是似乎可以解决所有问题的代码。许多其他涉及开始或结束刷新的其他部分会干扰控件的其他部分。

          //This chunk of code is needed to fix an iOS 7 bug with UIRefreshControls
          static BOOL refreshLoadedOnce = NO;
          if (!refreshLoadedOnce) {
            __weak typeof(self) weakself = self;
            [UIView animateWithDuration:0.25 delay:0 options:UIViewAnimationOptionBeginFromCurrentState animations:^(void){
              self.tableView.contentOffset = CGPointMake(0, -weakself.refreshControl.frame.size.height);
            } completion:^(BOOL finished) {
              weakself.refreshControl.attributedTitle = self.refreshControl.attributedTitle;
              [weakself.refreshControl setNeedsUpdateConstraints];
              [weakself.refreshControl setNeedsLayout];
              refreshLoadedOnce = YES;
            }];
          }
          //End of bug fix
          

          【讨论】:

          • 我在第一次调用控件的 beginRefreshing 方法之前把这段代码放在了前面。它只会被调用一次,因此如果多次调用它不会影响性能。但我想它也可以在多个位置执行(可能在 ViewWillAppear 或 ViewDidAppear 中,甚至可能在 ViewDidLoad 中);
          【解决方案6】:

          我终于找到了这方面的圣杯,看起来在所有情况下都有效

          注意:UIRefreshControl 被添加到 UITableViewController(注意,永远不要将 UIRefreshControl 作为子视图添加到普通 UIVIewController 的 UITableView)(最好将 UITableViewController 添加为 UIViewController 内的子 VC如果你必须)

          注意:这也解决了问题,即 UIRefreshControl 在第一次刷新时不可见 (link)

          加你.h

          @interface MyViewController ()
          
          @property (nonatomic, assign) BOOL refreshControlFixApplied;
          
          - (void)beginRefreshing;
          - (void)beginRefreshingWithText:(NSString *)text;
          - (void)endRefreshing;
          - (void)endRefreshingWithText:(NSString *)text;
          
          @end
          

          加你.m

          ////////////////////////////////////////////////////////////////////////
          #pragma mark - UIRefreshControl Fix (peter@min60.com) https://stackoverflow.com/questions/19121276/uirefreshcontrol-incorrect-title-offset-during-first-run-and-sometimes-title-mis/
          ////////////////////////////////////////////////////////////////////////
          
          - (void)beginRefreshingWithText:(NSString *)text {
          
              [self setRefreshControlText:text];
              [self beginRefreshing];
          
          }
          
          - (void)endRefreshingWithText:(NSString *)text {
          
              [self setRefreshControlText:text];
              [self.refreshControl endRefreshing];
          
          }
          
          - (void)beginRefreshing {
          
              if (self.refreshControl == nil) {
                  return;
              }
          
              if (!self.refreshControlFixApplied) {
          
                  dispatch_async(dispatch_get_main_queue(), ^{
          
                      if ([self.refreshControl.attributedTitle length] == 0) {
                          [self setRefreshControlText:@" "];
                      }
                      [self.refreshControl beginRefreshing];
          
                      dispatch_async(dispatch_get_main_queue(), ^{
          
                          [self.refreshControl endRefreshing];
          
                          dispatch_async(dispatch_get_main_queue(), ^{
          
                              // set the title before calling beginRefreshing
                              if ([self.refreshControl.attributedTitle length] == 0) {
                                  [self setRefreshControlText:@" "];
                              }
                              if (self.tableView.contentOffset.y == 0) {
                                  self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
                              }
                              [self.refreshControl beginRefreshing];
          
                              self.refreshControlFixApplied = YES;
          
                          });
          
                      });
          
                  });
          
              } else {
          
                  if (self.tableView.contentOffset.y == 0) {
                      self.tableView.contentOffset = CGPointMake(0, -self.refreshControl.frame.size.height);
                  }
                  [self.refreshControl beginRefreshing];
          
              }
          
          }
          
          - (void)endRefreshing {
          
              if (self.refreshControl == nil) {
                  return;
              }
          
              if (!self.refreshControlFixApplied) {
                  dispatch_async(dispatch_get_main_queue(), ^{
                      [self endRefreshing];
                  });
              } else {
                  if (self.tableView.contentOffset.y < 0) {
                      self.tableView.contentOffset = CGPointMake(0, 0);
                  }
                  [self.refreshControl endRefreshing];
          
              }
          
          }
          
          - (void)setRefreshControlText:(NSString *)text {
          
              UIFont * font = [UIFont fontWithName:@"Helvetica-Light" size:10.0];
              NSDictionary *attributes = @{NSFontAttributeName : font, NSForegroundColorAttributeName : [UIColor colorWithHex:0x00B92E]};
              self.refreshControl.attributedTitle = [[NSAttributedString alloc] initWithString:text attributes:attributes];
          
          }
          

          只使用方法

          - (void)beginRefreshing;
          - (void)beginRefreshingWithText:(NSString *)text;
          - (void)endRefreshing;
          - (void)endRefreshingWithText:(NSString *)text;
          

          【讨论】:

          • 对我来说,对于这样一个小问题,这是编写大量代码的方式(我相信 Apple 很快就会修复)。
          • 嗯,还没有修复
          【解决方案7】:

          viewWillAppear 下调用endRefreshing 为我做了这件事:

          -(void)viewWillAppear:(BOOL)animated
          {
              [super viewWillAppear:animated];
          
              [self.refreshControl endRefreshing];
          }
          

          在 iOS7 下,在 UINavigationController 中自定义 UITableViewController

          【讨论】:

            【解决方案8】:

            这绝对是 iOS 7 的错误,但我还没有弄清楚究竟是什么原因造成的。它似乎与视图层次结构有关 - 将我的 UITableViewController 作为子视图添加到包装视图控制器似乎一开始就为我修复了它,尽管该错误自 iOS 7 GM 以来又回来了。

            似乎在创建刷新视图后将以下代码添加到您的 UITableViewController 可以永久修复定位问题:

            dispatch_async(dispatch_get_main_queue(), ^{
                [self.refreshControl beginRefreshing];
                [self.refreshControl endRefreshing];
            });
            

            【讨论】:

            • 这确实有帮助,但在我的情况下,attributedTitle 在刷新过程的开始和结束时仍然与 tableCells 重叠。当我切换到 Xcode 5 时,这种情况就开始发生了。
            • 是的,这个问题在后来的 iOS 版本中又回来了,即使有解决方法。我注意到 Mail.app 在应用的微调器中没有标签,这让我相信这是一个内部已知问题,他们还没有完全解决。
            • 嗯,没错,Mail.app 只向您显示微调器,我尝试了您的方法但它不起作用,标题与表格视图重叠。
            • 终于找到了解决办法,看帖子
            • 嗯,[self.refreshControl setNeedsLayout];似乎更适合这种问题。开始/结束刷新是一种技巧。
            猜你喜欢
            • 2012-12-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-10-04
            • 1970-01-01
            • 1970-01-01
            • 2013-06-22
            相关资源
            最近更新 更多