web-dev-qa-db-fra.com

UIRefreshControl offset de titre incorrect lors de la première exécution et parfois titre manquant

Le texte est décalé de manière erronée lors du premier lancement de UIRefreshControl ... plus tard, parfois, le texte d'actualisation n'apparaît pas du tout et seule l'épine est visible

Je ne pense pas que j'ai eu ce problème avec iOS6 ... pourrait être lié à iOS7

Est dans un UITableViewController ajouté en tant qu'enfant à un VC, qui réside dans un UINavigationController présenté sous forme modale

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

}

enter image description here

enter image description here

29
Peter Lapisu

Il s’agit bien d’un bogue iOS 7, mais je n’ai pas trouvé exactement ce qui l’a causé. Cela semble avoir quelque chose à voir avec la hiérarchie des vues - l'ajout de mon UITableViewController en tant que vue enfant à un contrôleur de vue wrapper a semblé résoudre le problème pour moi au début, bien que le bogue soit de retour depuis iOS 7 GM.

Il semble que l'ajout du code suivant à votre UITableViewController après la création de la vue d'actualisation résout le problème de positionnement de manière définitive:

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

appeler endRefreshing sous viewWillAppear l'a fait pour moi:

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

    [self.refreshControl endRefreshing];
}

Sous iOS7 avec une UITableViewController personnalisée dans une UINavigationController 

4
Edgar

J'ai eu le même problème et pour moi, cela fonctionnait avec layoutIfNeeded après la définition du attributTitle:

- (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 a suggéré d'utiliser [self.refreshControl setNeedsLayout], mais cela ne force pas une mise à jour immédiate de la vue, vous devez donc utiliser layoutIfNeeded.

3

UIRefreshControl semble toujours être endommagé sur IOS9.3 lorsque vous modifiez le attributTitle lorsque la tableView est déroulée. Ce qui semble fonctionner est de sous-classer UIRefreshControl et de forcer la mise à jour de sa présentation une fois que le titre (attribué) a été modifié. les sous-vues de spinner et de texte) et de forcer la hauteur du cadre à la valeur attendue en veillant à ce que la couleur d'arrière-plan remplisse la zone déroulée.

@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
berbie

J'ai finalement trouvé le Saint Graal à ce sujet, qui semble fonctionner dans tous les cas

note: UIRefreshControl est ajouté à UITableViewController (remarque, n'ajoutez jamais UIRefreshControl juste comme sous-vue à un UITableView de UIVIewController normal) (il est préférable d'ajouter UITableViewController en tant qu'enfant VC dans UIViewController si

note: que cela corrige aussi le problème, que l'UIRefreshControl n'est pas visible au premier rafraîchissement ( link )

Ajouter à vous .h

@interface MyViewController ()

@property (nonatomic, assign) BOOL refreshControlFixApplied;

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

@end

Ajouter à vous .m

////////////////////////////////////////////////////////////////////////
#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];

}

Utilisez uniquement des méthodes

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

C'est le code qui semble résoudre tous les problèmes. Beaucoup d'autres qui impliquaient le début ou la fin du rafraîchissement interféraient avec d'autres parties du contrôle.

//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
1
Brett

J'ai eu le même problème, je l'ai résolu en définissant un texte attribué avec une chaîne d'espace pour actualiser le contrôle directement après le contrôle d'actualisation init

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

Après cela, la définition d'un nouveau texte attribué pour actualiser le contrôle s'est déroulée sans aucun problème.

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

METTRE &AGRAVE; JOUR

J'ai remarqué que le problème revenait lorsque j'utilisais attrsDictionary:

ce code fonctionne bien

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

et cela fait apparaître le titre de refreshControl directement après l'affichage chargé

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

Je n'ai pas encore trouvé de solution.

METTRE &AGRAVE; JOUR

La solution finalement trouvée, après refreshcontrol init, définit également la chaîne attribuée avec des attributs: 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]];

donc après cela, il n'y a plus de problème pour définir le titre du nouveau refreshcontrol.

1
Maxime Ashurov

La solution pour moi était de définir un texte dans viewDidAppear, inutile d'appeler 

beginRefreshing ou endRefreshing dans la file d'attente principale

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