すぐには可能ではないようですが、UIRefreshControl
サブクラスを使用せずに新しいiOS 6のUITableViewController
クラスを活用するための卑劣な方法はありますか。
UIViewController
をそのまま使用するのではなく、UITableView
をUITableViewDataSource
サブビューとともに使用し、UITableViewDelegate
およびUITableViewController
に準拠させることがよくあります。
急いで、そしてDrummerBのインスピレーションに基づいて、私は単にUIRefreshControl
のサブビューとしてUITableView
インスタンスを追加することを試みました。そしてそれは魔法のようにちょうどうまくいきます!
UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.myTableView addSubview:refreshControl];
これにより、テーブルビューの上にUIRefreshControl
が追加され、UITableViewController
を使用しなくても期待どおりに機能します。
編集:これはまだうまくいくが、少数が指摘したように、この方法で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;
編集:
テーブルビューでデータを更新した後に、UIRefreshControl
を付けずにUITableViewController
を付け加え、Niceアニメーションを保持する方法。
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の中でcontainer viewを使うことです。専用のtableviewを使用してきれいなUITableViewControllerサブクラスを定義し、それをViewControllerに配置することができます。
UIRefreshControlはUIViewのサブクラスなので、単独で使用できます。それがどのように自分自身をレンダリングするとしても私はよくわからない。レンダリングは単にフレームに依存しますが、UIScrollViewまたはUITableViewControllerにも依存する可能性があります。
いずれにせよ、それは優雅な解決策よりももっとハックになるでしょう。私はあなたが利用可能なサードパーティクローンの1つを調べるか、あなた自身のものを書くことを勧めます。
NSObjectの-endRefresh
またはGCDの-performSelector:withObject:afterDelay:
を使用して、tableViewがその内容をリロードした後、refreshControl dispatch_after
メソッドの呼び出しを数分の1秒遅らせるようにしてください。
このために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
}
}
iOS 10のUIRefreshControlについて知りたい場合は、 ここを参照してください。
サブビューとして最新表示コントロールを追加すると、セクションヘッダーの上に空のスペースが作成されます。
代わりに、私はUITableViewControllerを私のUIViewControllerに埋め込み、それからtableView
プロパティを埋め込みのものを指すように変更しました。最小限のコード変更。 :-)
ステップ:
@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.refreshControlは、iOS 9.xまではUITableViewControllerでのみ使用可能で、iOS 10.x以降はUITableViewで提供されています。
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)
これはもう一つ別の解決策です。
ビュー階層の問題があるため、これを使用する必要がありました。ビュー階層内のさまざまな場所にビューを渡す必要がある機能を作成していました。これは通常のビューだけではなく、コントローラ/ビューの階層が矛盾しているためクラッシュしていました。
基本的に独自のUITableViewControllerのサブクラスを作成し、loadViewをオーバーライドしてself.viewに別のビューを割り当て、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;
これには別の使用方法があります。
このようにサブクラス化するとself.viewとself.tableViewが分離されるため、このUITableViewControllerを通常のコントローラとして使用し、他のサブビューをself.viewに追加することが可能になります。ビューコントローラは、UITableViewControllerの子を持つのではなく、直接UITableViewControllerのサブクラスです。
注意すべき点がいくつかあります。
Superを呼び出さずにtableViewプロパティをオーバーライドしているので、注意が必要な点がいくつかあり、必要に応じて処理する必要があります。たとえば、上の例でテーブルビューを設定しても、テーブルビューがself.viewに追加されたり、フレームを設定したりすることはできません。また、この実装では、クラスがインスタンス化されたときにデフォルトのtableViewが指定されていません。これも追加を検討することができます。これはケースバイケースであるため、ここでは説明しません。このソリューションは、実際にはKellerのソリューションに適しています。