2012-07-17 190 views
34

我有一個iPad應用程序。在橫向方向上,UIViewController的視圖實際寬度= 1024px和height = 768-20(statusBar) - 44(navigationBar)= 704px獲取UIViewController視圖的正確範圍

所以我想得到這[1024 x 704]大小,我使用self.view.bounds它。它返回[748 x 1024],這是錯誤的!但是當我旋轉屏幕兩次(當前 - >縱向 - >當前)時,視圖的邊界是正確的 - [1024 x 704]

有人初始化是這樣的:

- (void)loadView { 
    self.view = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]]; 
    self.view.backgroundColor = [UIColor lightGrayColor]; 
} 

和範圍都得到這樣的:

- (void)viewDidLoad { 
    [super viewDidLoad]; 
    NSLog(@"bounds = %@", NSStringFromCGRect(self.view.bounds)); 
} 
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation { 
    NSLog(@"bounds = %@", NSStringFromCGRect(self.view.bounds)); 
} 

所以,問題是..我怎樣才能得到正確的觀點在一開始綁定?

回答

29

根據其他一些答案,您看到的問題是因爲viewDidLoad在之前被稱爲輪換髮生。因爲iPad始終以縱向模式初始化,所以如果您獲得viewDidLoad中的尺寸值,它們將始終爲縱向尺寸 - 這與您配置的任何方向無關。

要獲得之後的尺寸發生定向/旋轉,請在viewDidAppear中獲取尺寸值。


我特別不理解爲什麼iOS不處理這更好的 - 特別是考慮到你定義在項目設置的方位,並且,在Xcode界面生成器。但是,我確信有一個很好的理由;-)。

+1

如果你正在創建大視圖,可能會延遲視圖外觀,你可以通過使用'viewWillAppear'減少延遲 – 2014-08-09 08:07:26

+0

我試過viewWillAppear,它不能按要求工作,看來邊界計算是在視圖出現之後完成的 – Billy 2016-05-07 18:17:22

+1

我強烈建議**不要**使用'viewDidAppear '你的視圖在屏幕上,用戶可以看到這一點,你做的改變會引起突然和可見的毛刺,它也不會幫助你響應旋轉期間視圖大小的變化(等等)。 'viewWillLayoutSubviews'](http://stackoverflow.com/a/42275589/2547229)(披露:鏈接到我的答案)這是iOS處理這個的方式。 – Benjohn 2017-02-16 13:52:57

2

這是我在過去的項目中找到:self.view的框架將viewDidLoad中後,根據需要調節如果屏幕上有導航欄等

因此,也許你想使用的viewDidLoad後的值(可能在viewWillAppear或viewDidAppear中)或者通過減去小節的高度來手動調整它。

+0

我已經在'viewDidLoad'方法中使用它,並且在它之後。直到我旋轉屏幕,邊界仍然存在錯誤。手動減法是不好的解決方案,因爲應用程序是針對所有設備和方向的。 – demon9733 2012-07-17 13:10:21

+3

你會在viewDidLoad之後使用它嗎?在我的情況下,viewDidAppear將返回正確的大小。 – Selkie 2012-07-17 13:22:17

13

我一直使用:

CGSize sizeOfScreen = [[UIScreen mainScreen] bounds].size; 

得到屏幕的大小,以及:

CGSize sizeOfView = self.view.bounds.size; 

得到view的大小。我剛纔測試了viewDidLoad中和它返回:

2012-07-17 10:25:46.562 Project[3904:15203] bounds = {768, 1004} 

因爲CGSize被定義爲{寬度,高度}這是正確的。

+1

是的,它只在旋轉後才起作用:( – demon9733 2012-07-17 13:28:38

+0

這很奇怪,你在viewDidLoad中獲得大小的事實應該不重要,因爲視圖「已經加載」 – Luke 2012-07-17 13:33:22

2

我遇到了這個問題,發現獲取viewDidAppear的邊界符合我的需求。

12

如何做到這一點正確

UIViewController子類應該覆蓋的方法viewWillLayoutSubviewssee also here

調用此方法時,viewController的view具有正確的大小,您可以在佈局傳遞子視圖之前對子視圖進行必要的調整。

文檔

當視圖的邊界改變,視圖調整它的子視圖的位置。您的視圖控制器可以覆蓋此方法以在視圖佈局其子視圖之前進行更改。此方法的默認實現不做任何事情。

正如你從強調的部分看,這種方法每次視圖控制器的視圖改變大小稱爲,以及當視圖第一次出現。這使您可以正確地響應旋轉和其他邊界改變事件

幾個錯誤方法可以做到通過這裏 其他答案建議不工作這

幾種方法以及 是徹底打破。不幸的是,這包括選定的答案。你真的不應該使用這些方法。他們在這裏,原因是你不應該使用它們。請不要。

  • viewDidLoadviewWillAppear - 在這些調用view還沒有最終的大小。 你得到的大小將永遠是純粹的機會正確的,以誤導你。請求,我求求你,不要使用這些方法。
  • viewDidAppear - 這太晚了。 您的觀點已經在屏幕上顯示給用戶。在這裏進行更改會導致可見的變化/突然的故障,並且看起來像可怕的業餘時間垃圾。再一次請 - 爲了你,爲了我的緣故,大家的爲什麼不這樣做!你比這更好,你的用戶也是如此。
  • UIScreen.mainScreen.bounds.size - 這是極端低級別。你正在實現一個UIViewController,其視圖的大小取決於它嵌套在其中的控制器(導航,選項卡,分頁,任何自定義控制器等),設備旋轉的方式以及屏幕如何拆分多任務處理。所以,雖然你可能能夠彌補所有這些,並計算你的觀點的最終大小,你會最終得到複雜和脆弱的代碼。 UIViewController爲你做了這一切,如果你只是覆蓋viewWillLayoutSubviews

除了沒有提供正確的信息,這些方法不會幫助你,支持自動旋轉或者使視圖控制器的視圖改變大小如多任務手勢的其他事件。這是你真正想要處理的事情。

所以請:成爲冠軍。以正確的方式去做。使用viewWillLayoutSubviews。你的實施將被要求每一個尺寸的變化,你的用戶,未來的自我,團隊成員和我會爲你慶祝。好樣的!

進一步提示

viewWillLayoutSubviews被調用時,層次結構中的唯一觀點將被調整到它的最終尺寸爲viewController.view。爲此放棄是以方法的名義。它告訴你view…(您的視圖控制器的view…WillLayout…(真的快了,但它沒有發生尚未…Subviews(根視圖下,一切都在它的層次其他人)。

所以子視圖佈局還沒有發生! 孩子根還有一個有效的最後大小。從子視圖查詢的任何大小的信息將是最好的完全錯誤。

更可能的是,和無限更差,它將是誤導性更正

發生是您期望和需要的,因爲此尺寸和方向的默認設置,或者由於您的故事板設置。但這只是偶然的,並不是你可以依靠不同的設備尺寸或方向。

如果您需要告訴特定子視圖何時更改大小,並且知道其確切最終大小,則通常應該覆蓋該特定子類的layoutSubviews方法。

+0

感謝您的回答!爲了澄清,你是說如果我們想知道類UIView的子視圖的大小,唯一正確的方法是重寫它的'layoutSubviews'方法(這將需要創建一個自定義類)? – Crashalot 2017-12-08 00:08:22

+0

@Crashalot覆蓋對於展示子項的子類是有意義的。但是,如果您經常要編寫此行爲而不是覆蓋現有視圖類,則可能會產生問題。我採取的一種方法是創建一個特定的'UIView'子類,'BoundsSenderView',_only_具有將'layoutSubviews'轉發給某些注入的'boundsListener'處理程序的行爲。它不會顯示任何內容或響應觸摸等。然後,您可以使用自動佈局將其固定在您想要的大小的視圖上,並且在更改大小時您將獲得回調。 – Benjohn 2017-12-08 10:28:59

+0

可能還有其他方法可以在佈局後獲得子視圖的大小,但我並不知道它們。您需要連接完成的完整版式傳遞。 – Benjohn 2017-12-08 10:31:56