2012-02-28 25 views
11

tôi đang cố gắng để thực thi mã sau trong phương pháp viewDidLoad của dự án xem điều khiển duy nhất của tôi:không thể cập nhật view.layer.frame trong viewDidLoad?

self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 

Nhưng nó không cung cấp cho các inset mong muốn. Tuy nhiên thay đổi giao diện người dùng khác tôi thực hiện trong cùng một phương pháp làm việc ví dụ

self.view.layer.backgroundColor = [UIColor orangeColor].CGColor; 

Trên dòng mã không làm việc và nền là thay đổi màu da cam nhưng khung thì không.

Công cụ inset chỉ hoạt động nếu tôi đặt dòng mã trong chế độ xemDidAppear. Tôi muốn hiểu lý do chính cho hành vi này nếu ai đó có thể giải thích. Cảm ơn bạn trước.

Trả lời

11

Phương thức viewDidLoad còn quá sớm để đặt khung của khung nhìn vì một thứ khác đang thay đổi khung sau này.

Ví dụ: nếu đây là bộ điều khiển chế độ xem gốc của bạn, thì đối tượng UIWindow sẽ đặt khung của khung nhìn khi nó tự thêm chế độ xem làm chế độ xem phụ. Phương pháp viewDidLoad chạy ngay sau khi loadView trả về, trước khi bất kỳ đối tượng bên ngoài nào (như UIWindow) có thể xem xét trên màn hình.

Bạn có thể kiểm tra điều này bằng cách sử dụng một giao diện tùy chỉnh (nếu bạn chưa phải) và trọng setFrame: trong lớp giao diện tùy chỉnh:

- (void)setFrame:(CGRect)frame { 
    [super setFrame:frame]; 
} 

Đặt một breakpoint trong phương pháp đó và bạn sẽ thấy rằng khung của khung nhìn được đặt một thời gian sau khi trả về viewDidLoad.

+0

Lưu ý, bạn cũng có thể quan sát sự thay đổi giá trị bằng cách sử dụng [Giá trị chính Quan sát] (http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html), mặc dù nó sẽ không cho kết quả chính xác giống như subclassing (khác khi sử dụng breakpoint) –

+0

@lindonfox Bạn không thể quan sát một cách đáng tin cậy 'khung hình' của khung nhìn với KVO. Bạn cũng phải quan sát 'center',' bounds' và 'transform' của nó. –

+0

Làm thế nào về 'viewWillAppear'? Dường như với tôi làm điều đó trong 'viewDidAppear' là quá muộn và sẽ dẫn đến hiện tượng trục trặc thị giác. – devios1

5

Câu trả lời của Rob Mayoff là chính xác và tuyệt vời, nhưng đặt nó theo một cách hơi khác: viewDidLoad chỉ có nghĩa là chế độ xem đã được tải, tức là bộ điều khiển chế độ xem đã có chế độ xem. Nó không có nghĩa là khung nhìn đã được đặt trong giao diện. Đó thực sự là một trong những điều mà viewDidAppear: có nghĩa là - và đó là lý do tại sao nó hoạt động khi bạn chạy mã của mình ở đó.

Bí quyết trong tình huống này, nơi bạn muốn khởi tạo một cái gì đó về chế độ xem, là làm điều đó đủ muộn nhưng chỉ thực hiện một lần. viewDidAppear: có thể dễ dàng được gọi lại sau, nhưng bạn không muốn khởi tạo lại chế độ xem (trừ khi nó chưa được tải). Trong iOS 5, isMovingToParentViewController cho phép bạn phân biệt các trường hợp cụ thể mà bạn đang tìm kiếm. Trước đó, nó có thể là cần thiết để thiết lập một lá cờ BOOL để bạn thực hiện khởi tạo cuối cùng chỉ một lần.

Bẫy liên quan là điều sẽ xảy ra khi ứng dụng khởi chạy theo hướng ngang. Ở đây cũng vậy, viewDidLoad quá sớm vì giao diện vẫn chưa được xoay thành cảnh quan.

Tuy nhiên, vấn đề này không được phát sinh chút nào. Không nên để doanh nghiệp của bạn chèn chế độ xem của trình điều khiển chế độ xem. Quan điểm là bộ điều khiển chế độ xem gốc, trong trường hợp đó kích thước của nó được lấy tự động một cách chính xác, hoặc là con của bộ điều khiển chế độ xem gốc, trong trường hợp đó là công việc của trình điều khiển chế độ xem của cha mẹ để kích thước chế độ xem (dưới dạng UINavigationController, ví dụ, đã có), hoặc khung nhìn sẽ được trình bày một cách bình thường, trong trường hợp đó kích thước của nó sẽ được thiết lập tự động để khớp với khung nhìn nó thay thế. Vì vậy, tôi sẽ đề nghị rằng bạn rất câu hỏi cho thấy bạn đang làm điều gì đó sai trái.

2

Tạo dự án của bạn bằng phiên bản Xcode cũ hơn (ví dụ: tôi đang sử dụng Xcode 4.3.3 cho việc này). Sau đó, bạn có thể sử dụng phương thức setFrame: với viewDidLoad trong bất kỳ phiên bản nào của Xcode.

0

Tôi cũng gặp phải vấn đề này trên hướng dẫn của Ray Wenderlich 'Giới thiệu về CALayers'. http://www.raywenderlich.com/2502/introduction-to-calayers-tutorial

Có vẻ như việc thu hẹp toàn bộ chế độ xem bộ điều khiển chế độ xem không phải là điều tốt nhất để làm. Thay vì tạo ra một cái nhìn phụ và gọi CGRectInset trên ví dụ rằng trong bộ điều khiển xem của bạn viewDidLoad

UIView *viewToManipulate = [[UIView alloc] initWithFrame:CGRectMake(0.0,0.0, self.view.bounds.size.width, self.view.bounds.size.height)]; 

[self.view addSubview:viewToManipulate]; 

viewToManipulate.backgroundColor = [UIColor redColor]; 
viewToManipulate.layer.cornerRadius = 20.0; 
viewToManipulate.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 
+0

Bạn có thể mở rộng lý do tại sao thu hẹp chế độ xem của toàn bộ bộ điều khiển chế độ xem không tốt? –

+0

Tôi đã có cùng một vấn đề với hướng dẫn của Ray Wenderlich 'Giới thiệu về CALayers'. Bản sửa lỗi (khi sử dụng XCode 4.6) là chuyển mã thành chức năng "viewDidAppear". Không phải viewWillAppear hoặc viewDidLoad, nhưng viewDidAppear. Và sau đó nó sẽ hoạt động! Tôi tự hỏi nếu XCode 4.6 mới khủng khiếp "Sử dụng autolayout" hoặc chức năng Autosizing đang ngăn chặn các mã ban đầu từ làm việc ..? –

17

Tôi nghĩ vấn đề bạn đang chạy vào với dòng này:

self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 

có thể được giải thích như sau:

  • trong chế độ xemDidLoad, thuộc tính được đặt nhưng khung của chế độ xem chưa được xác định.
  • theo chế độ xem thời gianWillAppear được kích hoạt, chúng sẽ được đặt. Điều đó giải thích tại sao dòng mã đó hoạt động ở đó.
  • Nhưng kể từ iOS 5, có một phương thức khác được gọi sau khi viewDidLoad và trước viewWillAppear trong đó khung xem được đặt: viewDidLayoutSubviews.

Bạn có thể tìm thấy giải thích đầy đủ về điều này trong khóa học Stanford CS193P của mùa này về lập trình iOS (rất hay bằng cách này).

Vì vậy, nếu bạn muốn nó hoạt động chỉ một lần, sử dụng:

- (void)viewDidLayoutSubviews 
{ 
    self.view.layer.frame = CGRectInset(self.view.layer.frame, 20, 20); 
} 

PS: Tôi gửi câu trả lời này trên diễn đàn của Ray quá. Kính trọng, Fred

Các vấn đề liên quan