UIRefreshControl без UITableViewController
Просто любопытно, поскольку это не сразу кажется возможным, но есть ли скрытый способ использовать новый класс iOS 6 UIRefreshControl
без использования подкласса UITableViewController
?
Я часто использую UIViewController
с подтекстом UITableView
и отвечаю UITableViewDataSource
и UITableViewDelegate
, а не используя UITableViewController
.
Ответы
Ответ 1
На догадке и на основе вдохновения DrummerB я попробовал просто добавить экземпляр UIRefreshControl
в качестве подзаголовка для моего UITableView
. И это волшебство просто работает!
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.myTableView addSubview:refreshControl];
Это добавляет UIRefreshControl
над табличным представлением и работает как ожидалось, не используя UITableViewController
:)
EDIT: Это выше все еще работает, но, как отметили некоторые, существует небольшое "заикание" при добавлении UIRefreshControl таким образом. Решением этого является создание экземпляра UITableViewController, а затем настройка UIRefreshControl и UITableView на это: i.e.:
UITableViewController *tableViewController = [[UITableViewController alloc] init];
tableViewController.tableView = self.myTableView;
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:@selector(getConnections) forControlEvents:UIControlEventValueChanged];
tableViewController.refreshControl = self.refreshControl;
Ответ 2
Чтобы устранить заикание, вызванное принятым ответом, вы можете назначить UITableView
UITableViewController
.
_tableViewController = [[UITableViewController alloc]initWithStyle:UITableViewStylePlain];
[self addChildViewController:_tableViewController];
_tableViewController.refreshControl = [UIRefreshControl new];
[_tableViewController.refreshControl addTarget:self action:@selector(loadStream) forControlEvents:UIControlEventValueChanged];
_theTableView = _tableViewController.tableView;
EDIT:
Способ добавления UIRefreshControl
без UITableViewController
без заикания и сохранения хорошей анимации после обновления данных в представлении таблицы.
UIRefreshControl *refreshControl = [UIRefreshControl new];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.theTableView addSubview:refreshControl];
[self.theTableView sendSubviewToBack:refreshControl];
Позже при обработке обновленных данных...
- (void)handleRefresh:(UIRefreshControl *)refreshControl {
[self.theTableView reloadData];
[self.theTableView layoutIfNeeded];
[refreshControl endRefreshing];
}
Ответ 3
То, что вы попробуете, это использовать контейнерный вид внутри ViewController, который вы используете. вы можете определить чистый подкласс UITableViewController с выделенным представлением таблицы и поместить его в ViewController.
Ответ 4
Ну UIRefreshControl - это подкласс UIView, поэтому вы можете использовать его самостоятельно. Я не уверен, что, как он себя проявляет. Отказ может просто зависеть от фрейма, но он также может полагаться на UIScrollView или UITableViewController.
В любом случае, это будет скорее хак, чем элегантное решение. Я рекомендую вам заглянуть в один из доступных сторонних клонов или написать свой собственный.
ODRefreshControl
![enter image description here]()
SlimeRefresh
![enter image description here]()
Ответ 5
Попробуйте отложить вызов метода refreshControl -endRefresh
на долю секунды после того, как tableView перезагрузит его содержимое, используя NSObject -performSelector:withObject:afterDelay:
или GCD dispatch_after
.
Я создал категорию для UIRefreshControl для этого:
@implementation UIRefreshControl (Delay)
- (void)endRefreshingAfterDelay:(NSTimeInterval)delay {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self endRefreshing];
});
}
@end
Я тестировал его, и это также работает над Collection Views. Я заметил, что небольшая задержка
Достаточно 0,01 секунды:
// My data refresh process here while the refresh control 'isRefreshing'
[self.tableView reloadData];
[self.refreshControl endRefreshingAfterDelay:.01];
Ответ 6
IOS 10 Swift 3.0
это просто
import UIKit
class ViewControllerA: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var myTableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
myTableView.delegate = self
myTableView.dataSource = self
if #available(iOS 10.0, *) {
let refreshControl = UIRefreshControl()
let title = NSLocalizedString("PullToRefresh", comment: "Pull to refresh")
refreshControl.attributedTitle = NSAttributedString(string: title)
refreshControl.addTarget(self,
action: #selector(refreshOptions(sender:)),
for: .valueChanged)
myTableView.refreshControl = refreshControl
}
}
@objc private func refreshOptions(sender: UIRefreshControl) {
// Perform actions to refresh the content
// ...
// and then dismiss the control
sender.endRefreshing()
}
// MARK: - Table view data source
func numberOfSections(in tableView: UITableView) -> Int {
return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 12
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "reuseIdentifier", for: indexPath)
cell.textLabel?.text = "Cell \(String(indexPath.row))"
return cell
}
}
![введите описание изображения здесь]()
Если вы хотите узнать о iOS 10 UIRefreshControl, прочитайте здесь.
Ответ 7
Добавление элемента управления обновлением в виде подвью создает пустое пространство над заголовками разделов.
Вместо этого я встроил UITableViewController в свой UIViewController, а затем изменил свойство tableView
, чтобы указать на встроенный и альт! Минимальные изменения кода.: -)
Шаги:
- Создайте новый UITableViewController в Storyboard и вставьте его в свой оригинальный UIViewController
- Замените
@IBOutlet weak var tableView: UITableView!
на один из недавно встроенного UITableViewController, как показано ниже.
class MyViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
weak var tableView: UITableView!
override func viewDidLoad() {
super.viewDidLoad()
let tableViewController = self.childViewControllers.first as! UITableViewController
tableView = tableViewController.tableView
tableView.dataSource = self
tableView.delegate = self
// Now we can (properly) add the refresh control
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: "handleRefresh:", forControlEvents: .ValueChanged)
tableViewController.refreshControl = refreshControl
}
...
}
Ответ 8
Для Swift 2.2.
Сначала создайте UIRefreshControl().
var refreshControl : UIRefreshControl!
В вашем методе viewDidLoad() добавьте:
refreshControl = UIRefreshControl()
refreshControl.attributedTitle = NSAttributedString(string: "Refreshing..")
refreshControl.addTarget(self, action: #selector(YourUIViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
self.tableView.addSubview(refreshControl)
И сделайте функцию обновления
func refresh(refreshControl: UIRefreshControl) {
// do something ...
// reload tableView
self.tableView.reloadData()
// End refreshing
refreshControl.endRefreshing()
}
Ответ 9
Здесь другое решение, которое немного отличается.
Мне пришлось использовать его из-за некоторых проблем иерархии представлений, которые у меня были: я создавал некоторые функции, которые требовали передачи представлений в разные места в иерархии представлений, которые были нарушены при использовании таблицы UITableViewController table/b, tableView - это UITableViewController root view (self.view), а не просто обычный просмотр, он создал несогласованные иерархии контроллеров/представлений и вызвал сбой.
В основном создайте свой собственный подкласс UITableViewController и переопределите loadView, чтобы назначить self.view другому представлению и переопределить свойство tableView, чтобы вернуть отдельное представление таблицы.
например:
@interface MyTableVC : UITableViewController
@end
@interface MyTableVC ()
@property (nonatomic, strong) UITableView *separateTableView;
@end
@implementation MyTableVC
- (void)loadView {
self.view = [[UIView alloc] initWithFrame:CGRectZero];
}
- (UITableView *)tableView {
return self.separateTableView;
}
- (void)setTableView:(UITableView *)tableView {
self.separateTableView = tableView;
}
@end
В сочетании с решением Keller это будет более надежным в том смысле, что tableView теперь является обычным представлением, а не корневым представлением VC, и будет более устойчивым к изменению иерархии представлений. Пример использования этого метода:
MyTableVC *tableViewController = [[MyTableVC alloc] init];
tableViewController.tableView = self.myTableView;
self.refreshControl = [[UIRefreshControl alloc] init];
[self.refreshControl addTarget:self action:@selector(getConnections) forControlEvents:UIControlEventValueChanged];
tableViewController.refreshControl = self.refreshControl;
Для этого есть еще одно возможное использование:
Так как подкласс таким образом отделяет self.view от self.tableView, теперь можно использовать этот UITableViewController как обычный регулярный контроллер и добавлять другие subviews в self.view без странностей добавления subviews в UITableView, поэтому можно что делает их контроллеры представлений непосредственно подклассом UITableViewController, а не дочерними элементами UITableViewController.
Некоторые вещи, на которые следует обратить внимание:
Так как мы переопределяем свойство tableView без вызова super, могут быть некоторые вещи, на которые нужно обратить внимание и которые должны обрабатывать там, где это необходимо. Например, установка tableview в моем примере выше не добавит tableview в self.view и не установит фрейм, который вы, возможно, захотите сделать. Кроме того, в этой реализации по умолчанию не указан tableView по умолчанию, когда экземпляр класса создается, что также можно добавить. Я не включаю его здесь, потому что это в каждом случае, и это решение действительно хорошо подходит для решения Keller.
Ответ 10
Попробуйте это,
Выше решения отлично, но tableView.refreshControl доступен только для UITableViewController, до iOS 9.x и входит в UITableView с iOS 10.x и далее.
Написано в Swift 3 -
let refreshControl = UIRefreshControl()
refreshControl.addTarget(self, action: #selector(FeedViewController.loadNewData), for: UIControlEvents.valueChanged)
// Fix for the RefreshControl Not appearing in background
tableView?.addSubview(refreshControl)
tableView.sendSubview(toBack: refreshControl)
Ответ 11
Первое предложение Keller вызывает странную ошибку в iOS 7, где вставка таблицы увеличивается после того, как контроллер просмотра снова появляется. Переходя к второму ответу, используя uitableviewcontroller, я исправил все для меня.
Ответ 12
Оказывается, вы можете использовать следующее при использовании UIViewController с подвью UITableView и соответствовать UITableViewDataSource и UITableViewDelegate:
self.refreshControl = [[UIRefreshControl alloc]init];
[self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];