cocoa-touch uitableview ios7 uirefreshcontrol

cocoa touch - UIRefreshControl offset de título incorrecto durante la primera ejecución y, a veces, falta el título



cocoa-touch uitableview (8)

El texto se compensa erróneamente con el primer lanzamiento de UIRefreshControl ... más tarde, a veces, el texto de actualización no aparece y solo se ve el espinoso

No creo que haya tenido este problema con iOS6 ... podría estar relacionado con iOS7

Está en un UITableViewController agregado como un elemento secundario a un VC, que reside en un UINavigationController modal presentado

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


Al llamar a endRefreshing en viewWillAppear hice por mí:

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

En iOS7 con un UITableViewController personalizado dentro de un UINavigationController


Este es el código que parece solucionar todos los problemas. Muchos de los otros que involucraron el comienzo o la finalización de la actualización fueron interferir con otras partes del control.

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


Esto es definitivamente un error de iOS 7, pero no he descubierto exactamente qué lo causó. Parece que tiene algo que ver con la jerarquía de vistas: al agregar mi UITableViewController como una vista secundaria a un controlador de vista de contenedor parecía arreglarlo primero, aunque el error ha vuelto desde iOS 7 GM.

Parece que agregar el siguiente código a su UITableViewController después de crear la vista de actualización corrige el problema de posicionamiento para siempre:

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


Finalmente encontré el santo grial en esto, que parece funcionar en todos los casos

nota: UIRefreshControl se agrega a UITableViewController (nota, nunca agregue UIRefreshControl solo como subvista a UITableView de un UIVIewController normal) (mejor para agregar UITableViewController como un VC hijo dentro de un UIViewController si es necesario)

nota: que esto también soluciona el problema, que el UIRefreshControl no es visible al primer refresco ( link )

Añadir a ti .h

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

Añadir a usted .m

//////////////////////////////////////////////////////////////////////// #pragma mark - UIRefreshControl Fix ([email protected]) https://.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]; }

Use solo métodos

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


La solución para mí fue establecer un texto en viewDidAppear , sin necesidad de llamar

beginRefreshing o endRefreshing en la 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; }


Tuve el mismo problema y para mí funcionó con layoutIfNeeded después de configurar el attributeTitle:

- (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 sugirió usar [self.refreshControl setNeedsLayout] , pero esto no obliga a una actualización inmediata de la vista, por lo que debe usar layoutIfNeeded .


Tuve el mismo problema, lo resolví configurando el texto atribuido con una cadena de espacio para actualizar el control directamente después del control de actualización de inicio

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

Después de eso, establecer nuevo texto atribuido para actualizar el control fue sin ningún problema.

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

ACTUALIZAR

Noté que el problema vuelve cuando uso attrsDictionary:

este código funciona bien

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

y esto hace que el título de refreshControl aparezca directamente después de la vista cargada

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

No encontré la solución todavía.

ACTUALIZAR

Solución finalmente encontrada, después de que el inicio de refreshcontrol configure la cadena atribuida también con atributos: 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]];

así que después de eso no hay problema para establecer el nuevo título de refreshcontrol.


UIRefreshControl parece estar roto en IOS9.3 cuando cambias el attributeTitle mientras se baja el tableView. Lo que parece funcionar es subclase UIRefreshControl y forzar la actualización de su diseño una vez que se cambia el título (atribuido). La corrección básica es activar un cambio en tableView contentOffset (lo que provoca cierta magia oculta en el método _update que distribuye las subvistas spinner y text) y forzar la altura del marco a su valor esperado para garantizar que el color de fondo llene la región desplegada.

@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