UIRfreshControl неправильное смещение заголовка во время первого запуска, а иногда заголовок отсутствует

Текст смещается неправильно при первом запуске UIRfreshControl... позже иногда текст обновления вообще не отображается, и виден только колючий

Я не думаю, что у меня была эта проблема с iOS6... может быть связана с iOS7

Находится в UITableViewController, добавленном как дочерний элемент к VC, который находится в модальном представленном 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];

}

введите здесь описание изображения

введите здесь описание изображения


person Peter Lapisu    schedule 01.10.2013    source источник
comment
Это происходит на симуляторе или на реальном устройстве? Я потратил часы на эту проблему, и когда я попробовал тот же код на реальном устройстве, все прошло гладко.   -  person autremoi    schedule 15.10.2013
comment
Вы нашли решение?, я столкнулся с той же проблемой.   -  person Felix    schedule 10.01.2014
comment
ничего не помогло на 100% :( у меня   -  person Peter Lapisu    schedule 10.01.2014
comment
@FelixGuerrero посмотри ответ, наконец нашел решение   -  person Peter Lapisu    schedule 22.01.2014
comment
Apple когда-нибудь это исправит?   -  person lostintranslation    schedule 07.05.2015


Ответы (8)


Это определенно ошибка iOS 7, но я точно не понял, что ее вызвало. Похоже, это как-то связано с иерархией представлений — добавление моего UITableViewController в качестве дочернего представления к контроллеру представления-оболочки поначалу, казалось, исправило это для меня, хотя ошибка вернулась с iOS 7 GM.

Похоже, что добавление следующего кода в ваш UITableViewController после создания представления обновления навсегда устраняет проблему позиционирования:

dispatch_async(dispatch_get_main_queue(), ^{
    [self.refreshControl beginRefreshing];
    [self.refreshControl endRefreshing];
});
person Ben Jackson    schedule 01.10.2013
comment
Это действительно помогает, но в моем случае attributeTitle все еще перекрывается с tableCells в начале и в конце процесса обновления. Это начало происходить, когда я перешел на Xcode 5. - person autremoi; 15.10.2013
comment
Да, эта проблема вернулась, чтобы укусить меня в более поздней сборке iOS, даже с обходным путем. Я заметил, что у Mail.app нет меток в счетчике приложения, что наводит меня на мысль, что это известная внутренняя проблема, которую они еще не совсем исправили. - person Ben Jackson; 28.10.2013
comment
Хмммм, это правда, Mail.app показывает вам только счетчик, я попробовал ваш подход, но он не работает, заголовок перекрывает представление таблицы. - person Felix; 10.01.2014
comment
наконец-то нашел исправление, см. пост - person Peter Lapisu; 22.01.2014
comment
Интересно, что у меня возникла аналогичная проблема с SSPullToRefresh, и я переключился на UIRefreshControl в надежде решить эту проблему, но здесь, похоже, еще больший беспорядок. - person Marius Soutier; 17.02.2014
comment
Хм, [self.refreshControl setNeedsLayout]; кажется более подходящим для такого рода проблем. начало/конец обновления — это хак. - person onekiloparsec; 28.03.2014
comment
Это хак, но setNeedsLayout не работает. Все еще проблема в 8.3 Xcode 6. Тьфу, почему Apple не исправит это? - person lostintranslation; 07.05.2015
comment
До сих пор есть на iOS9. - person Matthieu Riegler; 08.02.2016
comment
У меня все еще глючит на iOS 9. (попробовав этот и все остальные трюки, которые я нашел) - person b.zdybowicz; 22.07.2016

вызов endRefreshing под viewWillAppear сделал это за меня:

-(void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    [self.refreshControl endRefreshing];
}

Под iOS7 с пользовательским UITableViewController внутри UINavigationController

person Edgar    schedule 04.01.2014

У меня была та же проблема, и у меня она работала с layoutIfNeeded после установки атрибутаTitle:

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

Седрик предложил использовать [self.refreshControl setNeedsLayout], но это не требует немедленного обновления представления, поэтому вы должны использовать layoutIfNeeded.

person Andreas Bogavčić    schedule 04.06.2014

Наконец-то я нашел святой Грааль, который похоже, работает во всех случаях

примечание: UIRefreshControl добавляется к UITableViewController (обратите внимание, никогда не добавляйте UIRefreshControl просто как подпредставление к обычному UIVIewController UITableView) (лучше всего добавить UITableViewController в качестве дочернего VC внутри UIViewController, если необходимо)

примечание: это также устраняет проблему, когда UIRefreshControl не отображается при первом обновлении (ссылка)

Добавить вам .h

@interface MyViewController ()

@property (nonatomic, assign) BOOL refreshControlFixApplied;

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

@end

Добавлю тебе .м

////////////////////////////////////////////////////////////////////////
#pragma mark - UIRefreshControl Fix ([email protected]) 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;
person Peter Lapisu    schedule 22.01.2014
comment
Для меня это слишком много кода для такой небольшой проблемы (я уверен, что Apple скоро исправит ее). - person meaning-matters; 26.02.2014
comment
ну до сих пор не исправили - person Jasper; 23.04.2015

UIRfreshControl, кажется, все еще не работает в IOS9.3, когда вы меняете атрибутTitle, когда tableView вытаскивается. Что, кажется, работает, так это создание подкласса 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
person berbie    schedule 09.05.2016

Это код, который, кажется, решает все проблемы. Многие другие, связанные с началом или окончанием обновления, мешали другим частям элемента управления.

//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
person Brett    schedule 12.05.2014
comment
Я помещаю этот код прямо перед первым вызовом метода beginRefreshing элемента управления. Он будет вызываться только один раз, поэтому он не повлияет на производительность, если будет вызываться несколько раз. Но я предполагаю, что это может быть выполнено и в нескольких местах (возможно, в ViewWillAppear или ViewDidAppear, возможно, даже в ViewDidLoad); - person Brett; 13.05.2014

У меня была та же проблема, я решил ее, установив атрибутированный текст с пробелом для управления обновлением непосредственно после управления обновлением инициализации.

_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];

Я еще не нашел решения.

ОБНОВЛЕНИЕ

Наконец-то найдено решение, после того, как updatecontrol init установил атрибутную строку также с атрибутами: 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]];

поэтому после этого нет проблем с установкой нового заголовка элемента управления обновлением.

person Maxime Ashurov    schedule 13.10.2015

Решение для меня состояло в том, чтобы установить текст в viewDidAppear, не нужно звонить

beginRefreshing или endRefreshing в 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;
}
person Jasper    schedule 23.04.2015