UIRefreshControl без UITableViewController

просто любопытно, так как это не сразу кажется возможным, но есть ли хитрый способ использовать новый iOS 6 UIRefreshControl класс без использования UITableViewController подкласс?

Я часто использую UIViewController С UITableView subview и соответствовать UITableViewDataSource и UITableViewDelegate вместо UITableViewController вчистую.

12 ответов


по наитию, а на основе вдохновения DrummerB, я попробовал просто добавить UIRefreshControl экземпляр в качестве подвида для my 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 на это, т. е.:

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;

чтобы устранить заикание, вызванное принятым ответом, вы можете назначить свой 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 без заикания и сохранить хорошую анимацию после обновления данных на tableview.

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

то, что вы попытаетесь использовать вид контейнера внутри ViewController, который вы используете. вы можете определить чистый подкласс UITableViewController с выделенным tableview и поместить его в ViewController.


Ну UIRefreshControl является подклассом UIView, поэтому вы можете использовать его самостоятельно. Я не уверен, хотя, как это делает себя. Рендеринг может просто зависеть от кадра, но он также может полагаться на UIScrollView или UITableViewController.

в любом случае, это будет скорее Хак, чем элегантное решение. Я рекомендую вам изучить один из доступных клонов 3rd party или написать свой собственный.

ODRefreshControl

enter image description here

SlimeRefresh

enter image description here


попробуйте отложить вызов refreshControl -endRefresh способ на доли секунды после TableView для загружает его содержимое, либо с помощью или 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

я протестировал его, и это также работает на представлениях коллекции. Я заметил, что задержка такая маленькая, как 0.01 секунд достаточно:

// My data refresh process here while the refresh control 'isRefreshing'
[self.tableView reloadData];
[self.refreshControl endRefreshingAfterDelay:.01];

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
    }

}

enter image description here

если вы хотите узнать о iOS 10 UIRefreshControl читать здесь.


добавление элемента управления refresh в качестве подвида создает пустое пространство над заголовками разделов.

вместо этого я встроил UITableViewController в мой UIViewController, а затем изменил мой tableView свойство, чтобы указать на встроенный, и альт! Минимальные изменения кода. :-)

действия:

  1. создайте новый UITableViewController в раскадровке и вставьте его в свой оригинальный UIViewController
  2. заменить @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
    }

    ...
}

Для 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()
}

вот еще одно решение, которое немного отличается.

Я должен был использовать его из-за некоторых проблем иерархии представлений, которые у меня были: я создавал некоторую функциональность, которая требовала передачи представлений в разные места иерархии представлений, которые нарушались при использовании tableview UITableViewController b/c tableView является корневым представлением UITableViewController (self.view), а не только обычный вид, он создал несогласованные иерархии контроллера / представления и вызвал крушение.

в основном создайте свой собственный подкласс UITableViewController и переопределите loadView для назначения self.просмотрите другое представление и переопределите свойство tableView, чтобы вернуть отдельный 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

в сочетании с решением Келлера это будет более надежным в том смысле, что 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;

для этого есть еще одно возможное использование:

Так как подклассы таким образом отделяет себя.вид из себя.tableView, теперь можно использовать этот UITableViewController как более обычный контроллер и добавить другие подвиды к себе.просмотр без странностей добавления подвидов в UITableView, поэтому можно рассмотреть вопрос о том, чтобы сделать их контроллеры представления непосредственно подклассом UITableViewController вместо UITableViewController дети.

некоторые вещи, чтобы наблюдать за:

поскольку мы переопределяем свойство tableView без вызова super, могут быть некоторые вещи, которые нужно остерегаться и должны обрабатывать, когда это необходимо. Например, установка tableview в моем примере выше не добавит tableview к себе.просмотр и не установить кадр, который вы можете сделать. Кроме того, в этой реализации нет tableView по умолчанию, данного вам при создании экземпляра класса, который также является чем-то вы может рассмотреть возможность добавления. Я не включаю его здесь, потому что это случай за случаем, и это решение действительно хорошо подходит к решению Келлера.


попробуйте это,

вышеуказанные решения прекрасны, но 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)

первое предложение Келлера вызывает странную ошибку в iOS 7, где вставка таблицы увеличивается после появления контроллера вида. Переход ко второму ответу, используя uitableviewcontroller, исправил все для меня.


оказывается, вы можете использовать следующее При использовании UIViewController с UITableView subview и соответствовать UITableViewDataSource и UITableViewDelegate:

self.refreshControl = [[UIRefreshControl alloc]init];
[self.refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];