UITableViewController olmadan UIRefreshControl


308

Hemen merak edilmediği için merak ediyorum, ancak yeni iOS 6 UIRefreshControlsınıfından bir UITableViewControlleralt sınıf kullanmadan sinsi bir yol var mı?

Sık sık bir kullanmak UIViewControllerbir ile UITableViewsubview ve uygun UITableViewDataSourceve UITableViewDelegateyerine bir kullanmaktan daha UITableViewControllerdüpedüz.


6
@DaveDeLong: Hayır, Dave, ne yapmalı? Bu sayfada daha sonra çözümünün desteklenmediğini söylüyorsunuz, doğru çözüm nedir?
mat

3
@matt kullanmalı UITableViewControllerve bir UIRefreshControlile UITableViewdoğrudan kullanmak için API isteyen bir hata dosyalamalıdır .
Dave DeLong

31
UITableViewController çok fazla belirsiz ve niş hatalar ve önemsiz olmayan görünüm hiyerarşileri ile ilgili sorunlar yaşadı (ve devam ediyor) ... Bu, bir TableView alt görünümüyle standart bir VC kullanmaya geçtiğinizde tümüyle sihirli bir şekilde yok oluyor. "Kullanım UITVC" IMHO herhangi bir çözüm için kötü bir başlangıçtır.
Adam

@Adam 'UITableViewController' alt görünüm denetleyicisi olarak kullanıldığında bu hatalar oluşuyor mu (böylece tableViewControllers hiyerarşisinde dolaşmadan görünüm özelleştirmesine erişim sağlıyor)? Bu şekilde kullanırken hiç sorunla karşılaşmadım.
memmons

Yanıtlar:


388

Bir önsezide ve DrummerB'in ilhamına dayanarak, basitçe bir UIRefreshControlörneği alt görünüm olarak eklemeye çalıştım UITableView. Ve sihirli bir şekilde çalışıyor!

UIRefreshControl *refreshControl = [[UIRefreshControl alloc] init];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.myTableView addSubview:refreshControl];

Bu UIRefreshControltablo görünümünüzün üstüne ekler ve bir UITableViewController:) kullanmak zorunda kalmadan beklendiği gibi çalışır :)


DÜZENLEME: Bu hala çalışıyor, ancak birkaçının belirttiği gibi, UIRefreshControl bu şekilde eklenirken hafif bir "kekeme" vardır. Bunun çözümü bir UITableViewController örneğini oluşturmak ve sonra UIRefreshControl ve UITableView'ınızı buna ayarlamaktır, yani:

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;

48
Bilginize, bu desteklenmeyen bir davranıştır ve gelecekte değişebilir. Apple'ın verdiği tek garanti, sağlanan api'ye (bu durumda -[UITableViewController setRefreshControl:]) göre kullanmanın çalışmaya devam edeceğidir.
Dave DeLong

18
Bu uygulama ile, tetiklemeden hemen önce handleRefresh:, kaydırma görünümünün değerinde bir an için beklenmedik bir değişiklik olduğu görülüyor contentInsets. Başka biri bunu deneyimliyor ya da bir düzeltme var mı? (evet, bunun ilk etapta desteklenmediğini biliyorum!)
Tim

6
Bunun için gerçekten bir Kapsayıcı Görünümü kullanmalısınız. Görünüm denetleyicisinin sınıfını özel alt sınıfınıza ayarlayın ve UITableViewController"doğru şekilde yapın".
Eugene

3
İOS7'de (iOS6 için bilinmeyen) düzenlenen sürüm, uygulamayı kapatıp yeniden açmanız durumu dışında iyi çalışır. Animasyon, 2. yenilemenize kadar oynatılamaz. Uygulamayı yeniden açtıktan sonra ilk kez yenileniyor, onu ne kadar aşağı çektiğinize bağlı olarak artan daire yerine sadece tam bir daire. Bir düzeltme var mı?
david2391

30
Hala UITableViewController pas geçerek yukarıda da belirtildiği gibi "Slutter" önlemek için, sadece bu yüzden gibi tablo görünümünde altına Yenileme denetimini ekleyin: [_tableView insertSubview:_refreshControl atIndex:0];. Hem iOS 7 hem de 8 ile test edildi;)
ptitvinou

95

Kabul edilen cevabın neden olduğu kekemeliği ortadan kaldırmak için UITableView, a 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;

DÜZENLE:

Kesintisiz bir UIRefreshControlhayır eklemenin UITableViewControllerve tablo görünümünde verileri yeniledikten sonra güzel animasyonu korumanın bir yolu .

UIRefreshControl *refreshControl = [UIRefreshControl new];
[refreshControl addTarget:self action:@selector(handleRefresh:) forControlEvents:UIControlEventValueChanged];
[self.theTableView addSubview:refreshControl];
[self.theTableView sendSubviewToBack:refreshControl];

Daha sonra yenilenen verileri işlerken ...

- (void)handleRefresh:(UIRefreshControl *)refreshControl {
    [self.theTableView reloadData];
    [self.theTableView layoutIfNeeded];
    [refreshControl endRefreshing];
}

7
Yeni bir UITableView bile oluşturmanız gerekmez. Sadece initWithStyle: existingTableView.style deyin ve sonra newTableViewController.tableView = existingTableView yapın ve refreshControl atayın. Bunu üç satıra kadar kaynatır.
13'te Trenskow

[_tablewViewController didMoveToParentViewController:self];Alt görünümü ekledikten sonra aramayı unutmayın .
qix

4
self.tableView = _tableViewController.tableView;olmalı_tableViewController.tableView = self.tableView
Ali

@Linus neden gerekli? _TableViewController.view benim özel viewController'ın viewDidLoad yönteminde bir subView olarak ekledi ve bu hile yapmak gibiydi. _TableViewController.tableView
taber

Bir UITableViewController kullanıcı olamaz ve içinde bir tablo görünümü w / bir UIViewController kullanıyorum nedeni. stackoverflow.com/questions/18900428/…
lostintranslation

21

Ne denemek istiyorsunuz kullandığınız ViewController içinde konteyner görünümü kullanmaktır. özel tableview ile temiz UITableViewController alt sınıfını tanımlayabilir ve bunu ViewController'a yerleştirebilirsiniz.


2
Kesinlikle, en temiz yol UITableViewController türünün alt görünüm denetleyicisi eklemek gibi görünüyor.
Zdenek

Daha sonra kullanarak UITableViewController alabilirsiniz self.childViewControllers.firstObject.
cbh2000

^ Ayrıca prepareForSegue, kapsayıcı görünümünde UITableViewController nesnesine bir başvuru almak için kullanmayı düşünebilirsiniz , çünkü bu hemen film şeridinden örnekleme üzerinde segue olayı olarak tetiklenir.
crarho

18

UIRefreshControl bir UIView alt sınıfıdır, bu yüzden kendi başına kullanabilirsiniz. Kendini nasıl yarattığından emin değilim. Oluşturma yalnızca kareye bağlı olabilir, ancak aynı zamanda bir UIScrollView veya UITableViewController'a da dayanabilir.

Her iki durumda da, zarif bir çözümden ziyade bir hack olacak. Mevcut 3. taraf klonlarından birine bakmanızı veya kendinizinkini yazmanızı öneririm.

ODRefreshControl

resim açıklamasını buraya girin

SlimeRefresh

resim açıklamasını buraya girin


1
Yanıtınız için teşekkürler, ama tam olarak aradığım şey değil. Ancak gönderinizin ilk cümlesi bana neyin çözüm olduğunu söylemeye ilham verdi!
Keller

7
ODRefreshControl harika - ipucu için teşekkürler! Çok basit ve işi yapar. Ve elbette Apple'lardan çok daha esnek. Neden herkes UITableViewController, IMO bütün API en kötü sınıf kullanacağını asla anladım. (Yanında) hiçbir şey yapmaz, ancak görüşlerinizi esnek hale getirir.
n13

Aslında orada ne kullandığınız projenize bağlıdır .. benim durumumda bir uitableview kullanarak projenin karmaşıklığı artıyordu ve şimdi uitableviewcontroller hangi tür kodumu iki segmente bölünmüş i mutlu ben olabilir 2 küçük dosya var büyük bir dosya yerine hata ayıklamak için kullanılabilir ..
kush

@ n13 Merhaba, UITableViewController kullanmak için iyi bir neden statik hücrelerle tasarım yapabiliyor. Bir UIViewController'da bulunan bir tableView içinde maalesef kullanılamıyor.
Jean Le Moignan

İOS araçları ve kütüphaneleri hızla değişiyor, bu nedenle 3 yıllık bir yorumum artık geçerli değil. SnapKit ile koddaki tüm kullanıcı arayüzlerini oluşturmaya geçtim ve dürüst olmak gerekirse arayüz oluşturucusunda 10 bin kez tıklamaktan çok daha verimli. Ayrıca bir UITableViewController'ı bir UIViewController olarak değiştirmek kolaydır ve sadece bir saniye sürer, oysa IB'de büyük bir acıdır.
n13

7

TableView -endRefreshiçeriğini NSObject -performSelector:withObject:afterDelay:veya GCD kullanarak yeniden yükledikten sonra refreshControl yöntemine yapılan çağrıyı bir saniye kadar geciktirmeyi deneyin dispatch_after.

Bunun için UIRefreshControl üzerinde bir kategori oluşturdum:

@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

Test ettim ve bu aynı zamanda Koleksiyon Görünümleri üzerinde de çalışıyor. 0.01 saniye kadar küçük bir gecikmenin yeterli olduğunu fark ettim:

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

4
Gecikmeler ve beklemeler gerçekten kötü bir stil.
orkoden

2
@orkoden katılıyorum. Bu, zaten desteklenmeyen bir kullanım için bir çözümdür UIRefreshControl.
boliva

Gecikmeli bir yöntemi çok daha kolay çağırabilirsiniz. [self performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.01]
orkoden

2
Son etki tamamen aynıdır ve 'hack'i daha az / daha zarif yapmaz. Bunun için -performSelector:withObject:afterDelay:GCD'nin kullanılıp kullanılmayacağı kişisel bir zevk meselesidir.
boliva

7

İOS 10 Swift 3.0

basit

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
    }

}

resim açıklamasını buraya girin

İOS yaklaşık 10 öğrenmek istiyorsanız UIRefreshControl okumak burada .


3

Yenileme denetimini alt görünüm olarak eklemek bölüm başlıklarının üstünde boş bir alan oluşturur.

Bunun yerine, bir UITableViewController benim UIViewController gömülü, sonra benim tableViewözellik gömülü bir işaret ve viola işaret edecek şekilde değiştirdi ! Minimum kod değişikliği. :-)

Adımlar:

  1. Storyboard'da yeni bir UITableViewController oluşturun ve orijinal UIViewController'ınıza gömün
  2. @IBOutlet weak var tableView: UITableView!Aşağıda gösterildiği gibi, yeni katıştırılmış UITableViewController'dan biriyle değiştirin

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
    }

    ...
}

2

Swift 2.2 için.

Önce UIRefreshControl () 'i yapın.

var refreshControl : UIRefreshControl!

ViewDidLoad () yönteminize şunu ekleyin:

refreshControl = UIRefreshControl()
    refreshControl.attributedTitle = NSAttributedString(string: "Refreshing..")
    refreshControl.addTarget(self, action: #selector(YourUIViewController.refresh(_:)), forControlEvents: UIControlEvents.ValueChanged)
    self.tableView.addSubview(refreshControl)

Ve yenileme işlevini yapın

func refresh(refreshControl: UIRefreshControl) {

    // do something ...

    // reload tableView
    self.tableView.reloadData()

    // End refreshing
    refreshControl.endRefreshing()
}

0

İşte biraz farklı olan başka bir çözüm.

Ben vardı bazı görünüm hiyerarşi sorunları nedeniyle kullanmak zorunda kaldı: Ben görünüm hiyerarşisinde farklı yerlere etrafında görünüm gerektiren bir işlevsellik oluşturuyordu, bir UITableViewController tablo görünümü b / c kullanırken tableView UITableViewController kök görünümü ( self.view) ve yalnızca normal bir görünüm değil, tutarsız denetleyici / görünüm hiyerarşileri oluşturdu ve bir çökmeye neden oldu.

Temel olarak kendi UITableViewController alt sınıfınızı oluşturun ve self.view'i farklı bir görünüm atamak için loadView'i geçersiz kılın ve ayrı bir tablo görünümü döndürmek için tableView özelliğini geçersiz kılın.

Örneğin:

@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'in çözümü ile birleştirildiğinde, bu, tableView'in artık bir VC'nin kök görünümü değil, normal bir görünüm olduğu ve görünüm hiyerarşilerinin değiştirilmesine karşı daha sağlam olacağı anlamında daha sağlam olacaktır. Bu şekilde kullanma örneği:

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;

Bunun başka bir olası kullanımı daha vardır:

Bu şekilde alt sınıflama self.view dosyasını self.tableView öğesinden ayırdığından, artık bu UITableViewController'ı normal bir denetleyici olarak kullanmak ve UITableView'a alt görünüm ekleme tuhaflıkları olmadan self.view'e başka alt görünümler eklemek mümkündür. Görünüm denetleyicileri, UITableViewController alt öğelerine sahip olmak yerine doğrudan bir UITableViewController alt sınıfına sahiptir.

Dikkat edilmesi gereken bazı şeyler:

Süper çağırmadan tableView özelliğini geçersiz kıldığımız için, dikkat edilmesi gereken bazı şeyler olabilir ve gerektiğinde işlemesi gerekir. Örneğin, yukarıdaki örneğimde tablo görünümünü ayarlamak, self.view öğesine tablo görünümünü eklemez ve yapmak isteyebileceğiniz çerçeveyi ayarlamaz. Ayrıca, bu uygulamada, sınıf somutlaştırıldığında size verilen varsayılan tableView yoktur, bu da eklemeyi düşünebileceğiniz bir şeydir. Buraya dahil etmiyorum çünkü bu duruma göre ve bu çözüm aslında Keller'in çözümüne çok iyi uyuyor.


1
"UITableViewController alt sınıfı kullanılmadan" sorusu belirtildi ve bu yanıt bir UITableViewController alt sınıfı içindir.
Brian

0

Bunu dene,

Yukarıdaki çözümler iyi ancak tableView.refreshControl, iOS 9.x'e kadar yalnızca UITableViewController için kullanılabilir ve iOS 10.x'ten itibaren UITableView'da gelir.

Yazan 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)

Şimdiye kadarki en iyi çözüm
Karthik KM

-1

Keller'in ilk önerisi, iOS 7'de görünüm denetleyicisinin yeniden görünmesinden sonra tablonun iç kısmının arttığı garip bir hataya neden oluyor. İkinci cevaba geçmek, uitableviewcontroller kullanarak işleri düzeltti.


-6

UITableView alt görünümüne sahip bir UIViewController kullandığınızda ve UITableViewDataSource ve UITableViewDelegate ile uyumlu olduğunda aşağıdakileri kullanabileceğiniz ortaya çıkıyor:

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

9
Katılmıyorum. self.refreshControla için bir özelliktir, a UITableViewControllerdeğil UIViewController.
Rickster

ÇALIŞMIYOR, uiviewcontroller için referhControl tanımlanmadı
OMGPOP
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.