Xem thay đổi khung giữa viewWillAppear: và viewDidAppear:


85

Tôi đã phát hiện ra một hành vi kỳ lạ trong ứng dụng của mình, trong đó một kết nối IBOutletcó khung của chế độ xem được kết nối giữa các cuộc gọi trong bộ điều khiển chế độ xem của tôi đến viewWillAppear:viewDidAppear:. Đây là mã có liên quan trong UIViewControllerlớp con của tôi :

-(void)viewWillAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

-(void)viewDidAppear:(BOOL)animated {
    NSLog(@"%@", self.scrollView);
}

và kết quả đầu ra nhật ký:

MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 0; 0 0); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>
MyApp[61880:c07] <UIScrollView: 0x1057eff0; frame = (0 44; 320 416); clipsToBounds = YES; autoresize = TM+BM; gestureRecognizers = <NSArray: 0x10580100>; layer = <CALayer: 0x1057f210>; contentOffset: {0, 0}>

Điều này cho thấy rõ ràng rằng khung hình đang thay đổi giữa hai cuộc gọi. Tôi muốn thiết lập với chế độ xem trong viewDidLoadphương thức, nhưng nếu nội dung không có sẵn để tôi thay đổi cho đến khi nó xuất hiện trên màn hình, thì điều đó có vẻ khá vô ích. Điều gì có thể xảy ra?


2
Bạn đang sử dụng autolayout? bạn đang thêm chế độ xem này trong Trình tạo giao diện hay theo chương trình?
Andrea

Tự động thanh toán được bật và chế độ xem này được tạo trong IB từ bảng phân cảnh.
Jumhyn

1
Tôi chưa bao giờ sử dụng bảng phân cảnh, nhưng rất có thể nó là chính xác. Sử dụng khung Autolayout của các dạng xem của bạn được đặt khi công cụ autolayout bắt đầu tính toán. Hãy thử hỏi điều tương tự ngay sau super of - (void) viewDidLayoutSubviews mpethod của bộ điều khiển chế độ xem của bạn.
Andrea

Điều đó kích hoạt thành công sự kiện của tôi vào đúng thời điểm, nhưng phương thức đó cũng được gọi bất cứ khi nào tôi thực hiện bất kỳ hoạt ảnh nào trên chế độ xem.
Jumhyn

1
viewDidLayoutSubviewslà cách chính xác để đi. Tôi chỉ cần đặt tất cả nội dung của mình vào một chế độ xem phụ để phương thức không được gọi lại bất cứ khi nào tôi thay đổi khung của chế độ xem chính.
Jumhyn

Câu trả lời:


111

Autolayoutđã thực hiện một thay đổi lớn về cách chúng tôi thiết kế và phát triển GUI cho các quan điểm của chúng tôi. Một trong những điểm khác biệt chính là autolayoutkhông thay đổi kích thước chế độ xem của chúng tôi ngay lập tức, mà chỉ khi được kích hoạt, có nghĩa là tại một thời điểm cụ thể, nhưng chúng tôi có thể buộc nó tính toán lại các ràng buộc của chúng tôi ngay lập tức hoặc đánh dấu chúng là "cần" bố cục. Nó hoạt động như thế nào -setNeedDisplay.
Thách thức lớn đối với tôi là phải hiểu và chấp nhận rằng, chúng ta không cần phải sử dụng mặt nạ tự động hóa nữa, và khung hình đã trở thành một tài sản vô dụng trong việc đặt chế độ xem của chúng ta. Chúng ta không cần phải suy nghĩ về vị trí xem nữa mà nên nghĩ xem chúng ta muốn xem chúng như thế nào trong một không gian liên quan đến nhau.
Khi chúng ta muốn kết hợp mặt nạ tự động khôi phục cũ và tự động thanh toán là khi vấn đề phát sinh. Chúng ta nên sớm nghĩ đến việc triển khai autolayout và cố gắng tránh kết hợp cách tiếp cận cũ trong một hệ thống phân cấp chế độ xem dựa trên autolayout.
Tốt hơn nếu có chế độ xem vùng chứa chỉ sử dụng mặt nạ tự động khôi phục, chẳng hạn như chế độ xem chính của bộ điều khiển chế độ xem, nhưng sẽ tốt hơn nếu chúng ta không cố gắng trộn lẫn.
Tôi chưa bao giờ sử dụng bảng phân cảnh, nhưng rất có thể nó là chính xác. Sử dụng Autolayout, khung các chế độ xem của bạn được đặt khi công cụ autolayout bắt đầu tính toán. Hãy thử hỏi điều tương tự ngay sau siêu - (void)viewDidLayoutSubviewsphương thức của bộ điều khiển chế độ xem của bạn.
Phương pháp này được gọi khi công cụ autolayout kết thúc để tính toán khung hình của các chế độ xem của bạn.


5
- (void) viewDidLayoutSubviews là câu trả lời cho tôi! Cảm ơn rất nhiều!
FrizzTheSnail,

Câu trả lời này thực sự không chính xác. Tất nhiên là có, rõ ràng là trong (5?) Năm rồi bạn phải sử dụng autolayout. Nhưng có bất kỳ trường hợp nào ( sử dụng autolayout ) mà bạn cần, chẳng hạn như thêm nội dung nào đó trên màn hình, "ngay trước khi nó xuất hiện với người dùng". (Nếu bạn làm điều đó trong viewDidAppear, bạn sẽ nhận được nhấp nháy. Nếu bạn làm điều đó trong viewWillAppear - các vị trí sẽ sai.) Câu trả lời thực sự là sử dụng viewDidLayoutSubviews.
Fattie

add something on a screen, "just before it appears to the user". The actual answer is indeed to use viewDidLayoutSubviews.... bạn sẽ hiển thị quan điểm đó nhiều lần
Andrea

156

Từ tài liệu:

viewWillAppear:

Thông báo cho bộ điều khiển chế độ xem rằng chế độ xem của nó sắp được thêm vào hệ thống phân cấp chế độ xem.

viewDidAppear:

Thông báo cho bộ điều khiển chế độ xem rằng chế độ xem của nó đã được thêm vào hệ thống phân cấp chế độ xem.

Do đó, khung của các lần xem phụ chưa được đặt trong viewWillAppear:

Phương pháp thích hợp để sửa đổi giao diện người dùng của bạn trước khi chế độ xem được hiển thị trên màn hình là:

viewDidLayoutSubviews

Thông báo cho bộ điều khiển chế độ xem rằng chế độ xem của nó vừa tạo ra các chế độ xem phụ.


2
Ugh, thật là khó chịu. Ngay cả từ ngữ của tài liệu cũng làm cho nó có vẻ như là viewWillApepar: và viewDidAppear: sẽ xảy ra trực tiếp sau nhau.
Jumhyn

2 tháng chờ đợi câu trả lời này ... cảm ơn tôi đã tìm thấy nó !! CẢM ƠN RÂT NHIỀU!
Rafael Ruiz Muñoz

6
Cần lưu ý rằng nó viewDidLayoutSubviewssẽ được gọi nhiều lần và không phải lúc nào cũng với cùng một khung, (tôi nghĩ đôi khi nó được gọi với CGRectZero trong lần gọi đầu tiên). Nó được gọi cho mỗi lần xem phụ được thêm vào và các thay đổi khác trong chế độ xem.
bauerMusic

Tôi đã quan tâm đến điều này cả ngày (viewDidLayoutSubviews được gọi nhiều lần, kể cả khi loại bỏ chế độ xem), và chỉ nói ef với nó, và đặt logic trong câu lệnh if và thực hiện một bool được đặt thành true sau mã đã chạy một lần. Tôi nghĩ phải có một cách sạch sẽ hơn, nhưng đã có quá nhiều thời gian dành cho nó.
solenoid

chúng ta phải đi sâu vào vấn đề này! viewDidLayoutSubviews là khủng khiếp, seNeedDisplay không hoạt động
Yaro

9

gọi

self.scrollView.layoutIfNeeded ()

trong viewWillAppearphương pháp của bạn . Sau đó, bạn có thể truy cập khung của nó và nó sẽ có cùng giá trị khi bạn inviewDidAppear


1
Không, điều này không chính xác. Ví dụ: bạn có một thanh điều hướng trên màn hình (từ bộ điều khiển điều hướng của bạn). Ngay cả sau layoutIfNeeded (), chiều cao của thanh điều hướng không được bao gồm, vì vậy kích thước khung của bạn sẽ thay đổi.
xaphod

Đây một cách tốt để buộc tính toán lại kích thước của khung hình cuộn để nó nhất quán trong toàn bộ phân cấp lệnh gọi bố cục chế độ xem nếu khung cuộn Chế độ xem được gắn với các ràng buộc trong chế độ xem siêu cao của nó.
smakus

4

Trong trường hợp của tôi, di chuyển tất cả các phương thức liên quan đến khung sang

override func viewWillLayoutSubviews()

hoạt động hoàn hảo (tôi đang cố gắng sửa đổi các ràng buộc từ bảng phân cảnh).

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.