Комментарии 19
Вообще говоря UIRefreshControl предназначен только для работы в связке с UITableViewController. То, что он работает и при простом добавлении в иерархию UITableView – счастливое стечение обстоятельств. Например в iOS6/7 в такой конфигурации (просто subview UITableVIew) возникали проблемы с анимациями. А у вас не возникают?
Note: Because the refresh control is specifically designed for use in a table view that's managed by a table view controller, using it in a different context can result in undefined behavior.
Пока не возникали, по крайней мере в двух несвязанных приложениях ничего такого не было (сравнил с UITableViewController, анимация работает идентично)
То есть вот такого «прыжка» в момент срабатывания обновления у вас не возникает?
www.youtube.com/watch?v=kEjJWfWKGSg
www.youtube.com/watch?v=kEjJWfWKGSg
обратите внимание на спиннер. Он тоже тормозит. Есть вероятность, что нечто сетевое или базаданное выполняется в UI треде, поэтому тормозит весь UI. Если это так — это проблема не UIRefreshControl.
Вообще можно github.com/samvermette/SVPullToRefresh. Он к UIScrollView цепляется.
Вообще можно github.com/samvermette/SVPullToRefresh. Он к UIScrollView цепляется.
Нет, дело именно в том, что UIRefreshControl неправильно инициализируется. Немного покопавшись в runtime легко убедиться, что UITableViewController при его инциализации дополнительно привязывает UIRefreshControl к UITableView – у таблицы вызывается приватный метод:
Впоследствии UITableView использует эту связь с UIRefreshControl – как раз для вычисления правильного contentInset при овер-скроллинге.
- (void)_setRefreshControl:(UIRefreshControl *)obj;
Впоследствии UITableView использует эту связь с UIRefreshControl – как раз для вычисления правильного contentInset при овер-скроллинге.
Точно, есть такой прыжок, действительно
Можно ведь делать UITableController, которому присваивать в качестве tableView вашу таблицу, а в качестве refreshControl собственно UIRefreshControl.
Часто нет возможности (или желания) наследовать свой контроллер от UITableViewController. Можно конечно создавать временный экземпляр UITableViewController – только для того, чтобы правильно инициализировать UIRefreshControl для своей таблицы. Или просто использовать приватные API, чтобы воспроизвести поведение UITableViewController при инициализации. О «радиусе кривизны» таких решений можно спорить – спасибо Apple за «классный» API.
Если поразмышлять, то при использовании UITableView не так много ситуаций когда UIViewController будет предпочтительнее UITableViewController (если все необходимые дополнительные элементы размещать на tableHeaderView и tableFooterView). Практически, если в каком-либо виде нужна UITableView, то изначально лучше использовать UITableViewController, и не придется думать о «радиусе кривизны»
Dreddik, насколько я понял, имел ввиду не наследование, а просто создание временного UITableViewController. Это фиксит проблему с «прыжком» из-за неправильной инициализации о которой Вы говорили ( omaksim )
К сожалению, конкретно в Swift не силен, но на Xamarin фикс выглядит так:
К сожалению, конкретно в Swift не силен, но на Xamarin фикс выглядит так:
[Register ("MyViewController")]
partial class MyViewController
{
[Outlet]
public UITableView myTableView { get; set; }
// ...
}
public partial class MyViewController : UIViewController
{
public UIRefreshControl myRefreshControl { get; set; }
public override void ViewDidLoad()
{
base.ViewDidLoad();
// ...
this.myRefreshControl = new UIRefreshControl();
this.myRefreshControl.AttributedTitle = new NSAttributedString("Обновляем...");
this.myRefreshControl.AddTarget(this, new ObjCRuntime.Selector("RefreshSource"), UIControlEvent.ValueChanged);
#region Fix the Jump problem
UITableViewController tableViewController = new UITableViewController();
tableViewController.TableView = this.myTableView;
tableViewController.RefreshControl = this.myRefreshControl;
#endregion
#region Fix the unwanted first showing
this.myRefreshControl.BeginRefreshing();
this.myRefreshControl.EndRefreshing();
#endregion
// ...
}
[Export("RefreshSource")]
private async void RefreshSource()
{
#region Edit source data
await Task.Run(() =>
{
Thread.Sleep(3000);
});
#endregion
this.myTableView.ReloadData();
this.myRefreshControl.EndRefreshing();
}
}
а еще счастливое стечение обстоятельств работает с UICollectionView
Было бы просто отлично, если бы каждый кто реализовывал infinite scrolling ещё и реализовал кнопочку по его отключению…
Если я все правильно понял, то у Вас вот здесь ошибка
Вы каждый раз создаете ячейку для таблицы, игнорируя механизм переиспользования ячеек UITableView. Из-за этого скролл talbeView может заметно подтормаживать, лучше поправить, а то наверняка новички, изучающие Swift, наткнутся на эту статью и потащут это к себе в проект.
let cell: UITableViewCell = UITableViewCell(style: UITableViewCellStyle.Subtitle, reuseIdentifier: "MyTestSwiftCell")
cell.text = "\(text) \(indexPath.row)"
cell.detailTextLabel.text = "Hi, \(indexPath.row)"
cell.detailTextLabel.textColor = UIColor.purpleColor()
return cell
Вы каждый раз создаете ячейку для таблицы, игнорируя механизм переиспользования ячеек UITableView. Из-за этого скролл talbeView может заметно подтормаживать, лучше поправить, а то наверняка новички, изучающие Swift, наткнутся на эту статью и потащут это к себе в проект.
Привожу корректный код:
Где CellReuseId некая строка идентификатор
var tableViewCell = tableView.dequeueReusableCellWithIdentifier(CellReuseId) as? UITableViewCell;
if (!tableViewCell){
tableViewCell = UITableViewCell(style: UITableViewCellStyle.Default, reuseIdentifier: CellReuseId);
tableViewCell.detailTextLabel.textColor = UIColor.purpleColor()
}
tableViewCell.text = "\(text) \(indexPath.row)"
tableViewCell.detailTextLabel.text = "Hi, \(indexPath.row)"
return tableViewCell;
Где CellReuseId некая строка идентификатор
let CellReuseId = "Row";
блин, не верно.
там где идет обращение к свойствам tableViewCell нужно добавить!
т.е.
tableViewCell!.text =
вот ничерта не читаем этот свифт…
там где идет обращение к свойствам tableViewCell нужно добавить!
т.е.
tableViewCell!.text =
вот ничерта не читаем этот свифт…
Попробовал разные варианты, но такой код так и не заработал, внутрь if не заходит. Посмотрел, что возвращает dequeueReusableCellWithIdentifier (возвращает nil), по идее должен работать такой код
Но dequeueReusableCellWithIdentifier никогда не возвращает nil, даже если делать custom ячейки. Чтобы заставить его работать, например, можно использовать такую проверку в случае с Subtitle (detailTextLabel.text по умолчанию содержит текст «Subtitle»)
или, если добавляется картинка, то
Еще тут возникает трудность с pull to refresh, надо учесть, что ячейки при таком условии не будут обновлены, потому что будут использоваться уже созданные
var cell = tableView.dequeueReusableCellWithIdentifier("MyTestSwiftCell") as UITableViewCell
if (cell == nil){
cell.detailTextLabel.textColor = UIColor.purpleColor()
cell.text = "\(text) \(indexPath.row)"
cell.detailTextLabel.text = "Hi, \(indexPath.row)"
}
return cell
Но dequeueReusableCellWithIdentifier никогда не возвращает nil, даже если делать custom ячейки. Чтобы заставить его работать, например, можно использовать такую проверку в случае с Subtitle (detailTextLabel.text по умолчанию содержит текст «Subtitle»)
if ( cell.detailTextLabel.text == "Subtitle" )
или, если добавляется картинка, то
if ( cell.imageView.image == nil )
Еще тут возникает трудность с pull to refresh, надо учесть, что ячейки при таком условии не будут обновлены, потому что будут использоваться уже созданные
ох, извините, я не указал. этот код работает для xib. в сторибоардах же, apple побеспокоилась и за нас (спасибо ей) и под капотом сделала часть кода, который мы раньше писали.
метод dequeueReusableCellWithIdentifier сам создает ячейку, если ее нет в кэше.
финальный вариант
и все там должно перезагружаться, если нет — то Вы что-то напутали. залейте в гит проект, посмотрим :)
метод dequeueReusableCellWithIdentifier сам создает ячейку, если ее нет в кэше.
финальный вариант
var tableViewCell = tableView.dequeueReusableCellWithIdentifier(CellReuseId) as? UITableViewCell;
tableViewCell!.detailTextLabel.textColor = UIColor.purpleColor()
tableViewCell!.text = "\(text) \(indexPath.row)"
tableViewCell!.detailTextLabel.text = "Hi, \(indexPath.row)"
return tableViewCell;
и все там должно перезагружаться, если нет — то Вы что-то напутали. залейте в гит проект, посмотрим :)
Да, в случае с сторибордами так и есть. Так же проверил этот код различными способами, и он, в итоге, ничем не отличается от более читаемого варианта
var tableViewCell = tableView.dequeueReusableCellWithIdentifier(CellReuseId) as UITableViewCell
tableViewCell.detailTextLabel.textColor = UIColor.purpleColor()
tableViewCell.text = "\(text) \(indexPath.row)"
tableViewCell.detailTextLabel.text = "Hi, \(indexPath.row)"
return tableViewCell
А есть какое-либо стандартное решение сделать pull to refresh внизу таблицы?
Зарегистрируйтесь на Хабре, чтобы оставить комментарий
Реализуем pull to refresh и infinite scrolling на Swift