2009-04-08 25 views
212

Tôi có chế độ xem tùy chỉnh không nhận được thông báo layoutSubview trong khi hoạt ảnh.Bố cục được bố trí khi nào?

Tôi có chế độ xem lấp đầy màn hình. Nó có một subview tùy chỉnh ở dưới cùng của màn hình mà thay đổi kích thước một cách chính xác trong Interface Builder nếu tôi thay đổi chiều cao của thanh nav. layoutSubviews được gọi khi chế độ xem được tạo nhưng không bao giờ trở lại. Các cuộc phỏng vấn của tôi được trình bày chính xác. Nếu tôi tắt thanh trạng thái trong cuộc gọi, thì chế độ xem của tất cả layoutSubviews không được gọi, ngay cả khi chế độ xem chính hoạt ảnh thay đổi kích thước.

Trong hoàn cảnh nào là layoutSubviews thực sự được gọi?

Tôi có autoresizesSubviews đặt thành NO cho chế độ xem tùy chỉnh của tôi. Và trong Interface Builder tôi có các thanh chống trên và dưới cùng và mũi tên dọc được đặt.

Trả lời

6

tôi theo dõi các giải pháp xuống khăng khăng Interface Builder rằng suối không thể thay đổi trên một quan điểm cho rằng có những yếu tố màn hình mô phỏng bật (thanh trạng thái, vv). Vì các lò xo bị tắt cho chế độ xem chính, chế độ xem đó không thể thay đổi kích thước và do đó được cuộn xuống toàn bộ khi thanh trong cuộc gọi xuất hiện.

Tắt các tính năng mô phỏng, sau đó thay đổi kích thước chế độ xem và đặt lò xo chính xác khiến hoạt ảnh xuất hiện và phương thức của tôi sẽ được gọi.

Một vấn đề bổ sung trong gỡ lỗi này là giả lập bỏ các ứng dụng khi tình trạng trong cuộc gọi là toggled qua menu. Thoát ứng dụng = không có trình gỡ lỗi.

+0

Bạn có nói rằng layoutSubviews được gọi khi xem được thay đổi kích cỡ? Tôi luôn cho rằng nó không phải là ... –

+0

. Khi một lần xem được thay đổi kích thước, nó cần phải làm điều gì đó với các bản xem trước của nó. Nếu bạn không cung cấp nó thì nó sẽ tự động chuyển chúng bằng lò xo, thanh chống, vv .. –

4

bạn đã xem bố cụcNếu được yêu cầu?

Đoạn mã tài liệu bên dưới. Hoạt ảnh có hoạt động nếu bạn gọi phương thức này một cách rõ ràng trong hoạt ảnh không?

layoutNếu được yêu cầu Đưa ra các bản xem phụ nếu cần.

- (void)layoutIfNeeded 

Thảo luận Sử dụng phương pháp này để buộc bố cục của các bản xem trước trước khi vẽ.

Tính khả dụng Có trong iPhone OS 2.0 trở lên.

0

Một phần của câu đố là cửa sổ phải được thực hiện chủ yếu:

[window makeKeyAndVisible]; 

của người nào khác subviews không tự động thay đổi kích cỡ.

2

Khi di chuyển một ứng dụng OpenGL từ SDK 3-4, layoutSubviews không được gọi nữa. Sau rất nhiều thử và sai Cuối cùng tôi đã mở MainWindow.xib, chọn đối tượng cửa sổ, trong thanh tra chọn Window Attributes tab (ngoài cùng bên trái) và kiểm tra "Visible lúc khởi động". Dường như trong SDK 3 nó vẫn sử dụng để gây ra một cuộc gọi layoutSubviews, nhưng không phải trong 4.

6 giờ thất vọng đưa đến một kết thúc.

+0

Bạn đã tạo khóa cửa sổ chưa? Nếu không, điều này có thể gây ra tất cả những điều thú vị không xảy ra. –

415

Tôi đã có một câu hỏi tương tự, nhưng đã không hài lòng với câu trả lời (hoặc bất kỳ tôi có thể tìm trên mạng), vì vậy tôi đã thử nó trong thực tế và đây là những gì tôi nhận:

  • init làm không gây layoutSubviews để được gọi là (duh)
  • addSubview: gây layoutSubviews được kêu gọi xem được bổ sung, quan điểm nó là thêm vào (xem mục tiêu), và tất cả các subviews của mục tiêu
  • xem setFrame thông minh gọi layoutSubviews trên quan điểm có khung của nó chỉ đặt nếu tham số kích thước của khung là khác nhau
  • di chuyển một UIScrollView gây layoutSubviews được kêu gọi các scrollview và SuperView của nó
  • xoay thiết bị chỉ gọi layoutSubview trên chế độ xem gốc (số trả lời xemBộ điều khiển chính xem)
  • Thay đổi kích thước một cái nhìn sẽ gọi layoutSubviews trên SuperView của nó

kết quả của tôi - http://blog.logichigh.com/2011/03/16/when-does-layoutsubviews-get-called/

+1

Câu trả lời hay. Tôi đã luôn luôn tự hỏi về 'layoutSubviews'. Có 'initWithFrame:' ​​gây ra 'layoutSubviews' được gọi? – Robert

+2

@Robert - Tôi đã sử dụng initWithFrame ... nên không. – BadPirate

+0

Tôi đã chạy vào trường hợp setFrame thay đổi kích thước nhưng không gây ra layoutSubviews được gọi. Tôi không biết tại sao. Xem câu hỏi này: http://stackoverflow.com/questions/7921610/why-might-layoutsubviews-not-automatically-be-called-on-a-view-when-its-frame-is –

9

Một số điểm trong BadPirate's answer chỉ là một phần sự thật:

  1. Đối addSubView điểm

    addSubview khiến bố cụcSubviews được gọi vào thứ chế độ xem e được thêm vào, chế độ xem được thêm vào (chế độ xem mục tiêu) và tất cả các bản xem trước của mục tiêu.

    Tùy thuộc vào mặt nạ tự động xem (xem mục tiêu). Nếu nó tự động hóa mặt nạ BẬT, layoutSubview sẽ được gọi trên mỗi addSubview. Nếu nó không có mặt nạ tự động hóa thì layoutSubview sẽ chỉ được gọi khi kích thước khung của khung nhìn (target View) thay đổi.

    Ví dụ: nếu bạn đã tạo UIView theo lập trình (mặc định không có mặt nạ tự động hóa), LayoutSubview sẽ chỉ được gọi khi khung UIView thay đổi không trên mỗi addSubview.

    Thông qua kỹ thuật này, hiệu suất của ứng dụng cũng tăng lên.

  2. Đối với các điểm luân chuyển thiết bị

    luân phiên một thiết bị chỉ gọi layoutSubview trên xem mẹ (đáp ứng quan điểm chính viewController của)

    Điều này có thể là đúng chỉ khi VC của bạn là ở VC phân cấp (root tại window.rootViewController), đây là trường hợp phổ biến nhất. Trong iOS 5, nếu bạn tạo một VC, nhưng nó không được thêm vào bất kỳ VC khác, thì VC này sẽ không nhận được bất kỳ chú ý khi thiết bị xoay.Do đó quan điểm của nó sẽ không được chú ý bằng cách gọi layoutSubviews.

53

Xây dựng dựa trên câu trả lời trước bởi @BadPirate, tôi đã thử nghiệm thêm một chút và đưa ra một số giải thích/chỉnh sửa. Tôi thấy rằng layoutSubviews: sẽ được gọi là trên một cái nhìn khi và chỉ khi:

  • của nó sở hữu vọt (không khung) thay đổi.
  • Giới hạn của một trong các bản xem trước trực tiếp của nó đã thay đổi.
  • Một chế độ xem phụ được thêm vào chế độ xem hoặc bị xóa khỏi chế độ xem.

Một số chi tiết liên quan:

  • Các giới hạn được coi là thay đổi chỉ khi giá trị mới là khác nhau, trong đó có một nguồn gốc khác nhau. Lưu ý cụ thể đó là lý do tại sao layoutSubviews: được gọi là bất cứ khi nào một cuộn UIScrollView cuộn, vì nó thực hiện cuộn bằng cách thay đổi gốc của giới hạn của nó.
  • Thay đổi khung sẽ chỉ thay đổi giới hạn nếu kích thước đã thay đổi, đó là điều duy nhất được truyền đến thuộc tính giới hạn.
  • Thay đổi giới hạn của chế độ xem chưa có trong hệ thống phân cấp chế độ xem sẽ dẫn đến một cuộc gọi đến layoutSubviews:khi chế độ xem cuối cùng được thêm vào phân cấp chế độ xem.
  • Và chỉ để hoàn thành: những trình kích hoạt này không trực tiếp bố cục cuộc gọiSubviews, nhưng thay vào đó hãy gọi setNeedsLayout, đặt/tăng cờ. Mỗi lần lặp của vòng lặp chạy, cho tất cả các chế độ xem trong cấu trúc phân cấp xem, cờ này được chọn. Đối với mỗi chế độ xem nơi cờ được tìm thấy được nâng lên, layoutSubviews: được gọi trên đó và cờ được đặt lại. Lượt xem cao hơn lên hệ thống phân cấp sẽ được kiểm tra/gọi trước tiên.
+4

không thể đưa ra câu trả lời này đủ. nó phải là câu trả lời hàng đầu. ba quy tắc được đưa ra là tất cả những gì bạn cần. Tôi chưa bao giờ gặp bất kỳ hành vi layoutSubview nào mà các quy tắc này không mô tả một cách hoàn hảo. –

6

gọi [self.view setNeedsLayout]; trong viewController làm cho nó để gọi viewDidLayoutSubviews

6

https://developer.apple.com/library/prerelease/tvos/documentation/WindowsViews/Conceptual/ViewPG_iPhoneOS/CreatingViews/CreatingViews.html#//apple_ref/doc/uid/TP40009503-CH5-SW1

thay đổi Layout có thể xảy ra bất cứ khi nào bất kỳ sự kiện sau đây xảy ra trong một cái nhìn:

a. Kích thước hình chữ nhật có viền thay đổi.
b. Một thay đổi định hướng giao diện xảy ra, thường gây ra thay đổi trong hình chữ nhật viền của chế độ xem gốc.
c. Tập hợp các lớp con Hoạt ảnh cốt lõi được liên kết với các thay đổi của chế độ xem và yêu cầu bố cục.
d. Ứng dụng của bạn buộc bố cục xảy ra bằng cách gọi phương thức setNeedsLayout hoặc layoutIfNeeded của chế độ xem.
e. Ứng dụng của bạn buộc bố cục bằng cách gọi phương thức setNeedsLayout của đối tượng lớp cơ bản của chế độ xem.

+0

Ngoài ra, điều quan trọng cần chỉ ra là không có sự kiện nào trong số đó được gọi khi khung nhìn chưa được thêm vào khung nhìn. Bạn bao gồm điều này với từ "có thể", nhưng cụ thể nó được gọi trong chu kỳ có sẵn tiếp theo của chủ đề chính của ứng dụng khi nó đã được đánh dấu là cần bố trí bởi một trong những sự kiện đó. – user1122069

0

Một trường hợp khá mơ hồ, nhưng rất quan trọng khi layoutSubviews không bao giờ được gọi là:

class View: UIView { 

    override class var layerClass: AnyClass { return Layer.self } 

    class Layer: CALayer { 
     override func layoutSublayers() { 
      // if we don't call super.layoutSublayers() 
     } 
    } 

    override func layoutSubviews() { // this never gets called by the OS! 
     print(#function) 
    } 
}