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