UITableViewController가없는 UIRefreshControl


308

즉시 궁금하지는 않지만 호기심이 많지만 하위 UIRefreshControl클래스를 사용하지 않고 새로운 iOS 6 클래스 를 활용하는 은밀한 방법이 UITableViewController있습니까?

나는 종종를 사용 UIViewControllerUITableView서브 뷰와 준수 UITableViewDataSource하고 UITableViewDelegate오히려를 사용하는 것보다 UITableViewController철처.


6
@DaveDeLong : 아니요, Dave, 어떻게해야합니까? 이 페이지 뒷부분에서 자신의 솔루션이 지원되지 않는다고 말하면 올바른 솔루션은 무엇입니까?
matt

3
@ 매트 그는를 사용해야 UITableViewController하고를 사용하는 API를 요청하는 버그를 제출 UIRefreshControlUITableView직접.
Dave DeLong

31
UITableViewController는 너무 많은 모호하고 틈새 버그와 사소한 뷰 계층 구조의 문제를 가지고 있습니다. TableView 하위 뷰와 함께 표준 VC를 사용하도록 전환하면 마술처럼 사라집니다. "UITVC 사용"은 모든 솔루션 IMHO의 시작이 좋지 않습니다.
Adam

@Adam 'UITableViewController'를 자식 뷰 컨트롤러로 사용할 때 이러한 버그가 발생합니까? 이런 식으로 사용할 때 문제가 발생하지 않았습니다.
memmons

답변:


388

직감하고 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;

48
참고로, 이는 지원되지 않는 동작이며 향후 변경 될 수 있습니다. Apple이 제공하는 유일한 보증은 제공된 api (이 경우 -[UITableViewController setRefreshControl:]) 에 따라 사용하는 것이 계속 작동한다는 것입니다.
Dave DeLong

18
이 구현으로 트리거하기 직전 handleRefresh:에 스크롤 뷰의 값이 예기치 않게 변경되는 것처럼 보입니다 contentInsets. 다른 사람이 이것을 경험하거나 해결해야합니까? (그래, 나는 이것이 처음에는 지원되지 않는다는 것을 안다!)
Tim

6
이것을 위해 단순히 컨테이너 뷰를 사용해야합니다. 뷰 컨트롤러의 클래스를 커스텀 서브 클래스로 설정 UITableViewController하면 "올바로 작동"하게됩니다.
유진

3
iOS7 (iOS6에 알려지지 않음)에서 앱을 닫았다가 다시 열 때를 ​​제외하고 편집 된 버전이 제대로 작동합니다. 두 번째로 새로 고침 할 때까지 애니메이션이 재생되지 않습니다. 앱을 다시 연 후 처음으로 새로 고침하는 방법은 앱을 얼마나 아래로 당기는가에 따라 증분 원 대신 전체 원입니다. 수정이 있습니까?
david2391

30
UITableViewController를 여전히 우회하면서 위에서 언급 한대로 "버 거림"을 피하려면 다음과 같이 테이블보기 아래에 새로 고침 제어를 추가하십시오 [_tableView insertSubview:_refreshControl atIndex:0];. iOS 7과 8에서 테스트
;;

95

허용 대답에 의해 발생하는 더듬을 제거하기 위해, 당신은 당신을 할당 할 수 있습니다 UITableViewA를 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않고 테이블 뷰에서 데이터를 새로 고친 후 멋진 애니메이션을 유지하는 방법입니다.

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

7
새로운 UITableView를 만들 필요조차 없습니다. initWithStyle : existingTableView.style이라고 말한 다음 newTableViewController.tableView = existingTableView를 수행하고 refreshControl을 할당하십시오. 이것을 세 줄로 끓입니다.
Trenskow 2013

[_tablewViewController didMoveToParentViewController:self];서브 뷰를 추가 한 후 전화하는 것을 잊지 마십시오 .
qix

4
self.tableView = _tableViewController.tableView;해야_tableViewController.tableView = self.tableView
알리

@Linus는 왜 필요한가? 내 커스텀 viewController의 viewDidLoad 메소드에서 _tableViewController.view를 subView로 추가했는데 트릭을 수행하는 것처럼 보였습니다. _tableViewController.tableView를 설정할 필요조차 없습니다
taber

UITableViewController를 사용할 수 없으며 테이블보기가있는 UIViewController를 사용하는 이유입니다. stackoverflow.com/questions/18900428/…
lostintranslation 14 년

21

시도하는 것은 사용중인 ViewController 내부의 컨테이너보기를 사용하는 것입니다. 전용 테이블 뷰로 깨끗한 UITableViewController 서브 클래스를 정의하고 ViewController에 배치 할 수 있습니다.


2
정확하게, 가장 깨끗한 방법은 UITableViewController 유형의 자식보기 컨트롤러를 추가하는 것 같습니다.
Zdenek

그런 다음을 사용하여 UITableViewController를 가져올 수 있습니다 self.childViewControllers.firstObject.
cbh2000

^ prepareForSegue스토리 보드에서 인스턴스화 할 때 segue 이벤트로 즉시 트리거되므로 컨테이너보기에서 UITableViewController 객체에 대한 참조를 얻는 데 사용할 수도 있습니다 .
crarho

18

UIRefreshControl은 UIView 하위 클래스이므로 자체적으로 사용할 수 있습니다. 어떻게 렌더링되는지 잘 모르겠습니다. 렌더링은 단순히 프레임에 의존 할 수 있지만 UIScrollView 또는 UITableViewController에 의존 할 수도 있습니다.

어느 쪽이든, 그것은 우아한 솔루션보다 해킹이 될 것입니다. 사용 가능한 타사 복제본 중 하나를 보거나 직접 작성하는 것이 좋습니다.

ODRefreshControl

여기에 이미지 설명을 입력하십시오

슬라임

여기에 이미지 설명을 입력하십시오


1
답장을 보내 주셔서 감사합니다. 그러나 내가 찾던 것이 아닙니다. 그러나 귀하의 게시물의 첫 번째 문장은 해결책이었던 것을 시도하도록 영감을주었습니다!
켈러

7
ODRefreshControl은 대단합니다-팁 주셔서 감사합니다! 매우 간단하고 작업을 수행합니다. 물론 애플보다 훨씬 유연합니다. 나는 왜 아무도 APITableViewController, IMO를 전체 API에서 최악의 클래스로 사용하는지 이해하지 못했습니다. 아무것도하지 않지만 뷰를 유연하게 만듭니다.
n13

그것은 실제로 프로젝트에서 당신이 무엇을 사용하는지에 달려 있습니다.. 하나의 거대한 파일 대신 디버그하는 데 사용됩니다 ..
kush

@ n13 안녕하세요, UITableViewController를 사용해야하는 좋은 이유는 정적 셀로 디자인 할 수 있기 때문입니다. 불행히도 UIViewController에있는 tableView에서는 사용할 수 없습니다.
Jean Le Moignan

@JeanLeMoignan iOS 도구 및 라이브러리가 빠르게 변경되어 3 년 전 내 의견이 더 이상 유효하지 않습니다. SnapKit을 사용하여 코드로 모든 사용자 인터페이스를 만드는 것으로 전환했으며 정직하게 인터페이스 빌더에서 10 만 번 클릭하는 것보다 훨씬 효율적입니다. 또한 UITableViewController를 UIViewController로 변경하는 것은 쉽고 1 초 밖에 걸리지 않지만 IB에서는 큰 고통입니다.
n13

7

-endRefreshNSObject -performSelector:withObject:afterDelay:또는 GCD를 사용하여 tableView가 내용을 다시로드 한 후 새로 고침 컨트롤 메서드에 대한 호출을 1 초 정도 지연하십시오 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];

4
지연과 대기는 정말 나쁜 스타일입니다.
orkoden

2
@orkoden 동의합니다. 이것은 이미 지원되지 않는에 대한 해결 방법입니다 UIRefreshControl.
boliva

지연 시간이 훨씬 짧은 메소드를 훨씬 쉽게 호출 할 수 있습니다. [self performSelector:@selector(endRefreshing) withObject:nil afterDelay:0.01]
orkoden

2
최종 효과는 정확히 동일하며 '해킹'을 더 우아하게 만들지 않습니다. -performSelector:withObject:afterDelay:이것을 사용할 것인지 GCD 를 사용할 것인지는 개인적인 취향에 달려 있습니다.
boliva

7

iOS 10 스위프트 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에 대해 배우려면 여기를 참조하십시오 .


3

새로 고치기 제어를 서브 뷰로 추가하면 섹션 헤더 위에 빈 공간이 작성됩니다.

대신 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
    }

    ...
}

2

스위프트 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()
}

0

조금 다른 또 다른 해결책이 있습니다.

나는 몇 가지보기 계층 문제로 인해 그것을 사용해야했다. 나는 UITableViewController의 tableview b / c를 사용할 때 깨지는보기 계층 구조의 다른 장소로 뷰를 전달 해야하는 기능을 만들고 있었다. self.view)는 일반보기뿐만 아니라 일관성없는 컨트롤러 /보기 계층을 생성하여 충돌을 일으켰습니다.

기본적으로 고유 한 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

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를 일반 컨트롤러로 사용하고 UITableView에 서브 뷰를 추가 할 필요없이 self.view에 다른 서브 뷰를 추가 할 수 있습니다. UITableViewController 자식을 갖지 않고 직접 컨트롤러를 UITableViewController의 서브 클래스로 봅니다.

주의해야 할 사항 :

super를 호출하지 않고 tableView 속성을 재정의하므로 필요한 경우주의해야 할 사항이 있습니다. 예를 들어, 위의 예제에서 tableview를 설정하면 self.view에 tableview가 추가되지 않고 원하는 프레임이 설정되지 않습니다. 또한이 구현에는 클래스가 인스턴스화 될 때 제공되는 기본 tableView가 없으며 추가 할 수도 있습니다. 경우에 따라 여기에 포함되지 않으며이 솔루션은 실제로 Keller의 솔루션과 잘 맞습니다.


1
질문은 "UITableViewController 서브 클래스를 사용하지 않고"지정되었으며이 답변은 UITableViewController 서브 클래스에 대한 것입니다.
Brian

0

이 시도,

위의 솔루션은 훌륭하지만 iOS 9.x까지 iOSTableViewController에서만 tableView.refreshControl을 사용할 수 있으며 iOS 10.x부터 UITableView로 제공됩니다.

스위프트 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)

지금까지 최고의 솔루션
Karthik KM

-1

Keller의 첫 번째 제안은 iOS 7에서 뷰 컨트롤러가 다시 나타난 후 테이블의 삽입이 증가하는 이상한 버그를 유발합니다. uitableviewcontroller를 사용하여 두 번째 답변으로 변경하면 문제가 해결되었습니다.


-6

UITableView 하위보기와 함께 UIViewController를 사용하고 UITableViewDataSource 및 UITableViewDelegate를 준수 할 때 다음을 사용할 수 있습니다.

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

9
동의하지 않는다. self.refreshControlA의 속성입니다 UITableViewControllerA, 없습니다 UIViewController.
Rickster

작동하지 않음, referhControl이 uiviewcontroller에 대해 정의되어 있지 않음
OMGPOP
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.