web-dev-qa-db-ja.com

単一の.xibファイルを使用したポートレートおよびランドスケープ用の代替iOSレイアウト

Xcodeのインターフェイスビルダーと1つの.xibファイルを使用して、横向きと縦向きの間で回転するときに代替レイアウトを作成するにはどうすればよいですか?

異なるレイアウトの図を参照 enter image description here

N.b。緑のビュー/エリアには、横向きに流れる3つのアイテムが含まれ、縦向きでは、これらの3つのアイテムが緑のビュー/エリア内で垂直に流れます。

40
Dave Haigh

これを行う方法は、.xibファイルに3つのビューを持つことです。 1つ目は、サブビューのないViewcontrollerの通常のビューです。

次に、必要に応じてポートレートとランドスケープのビューを作成します。 3つすべてがルートレベルのビューである必要があります(スクリーンショットをご覧ください)

enter image description here

Viewcontrollerで、ポートレート用とランドスケープビュー用の2つのIBOutletを作成し、それらをインターフェイスビルダーの対応するビューに接続します。

IBOutlet UIView *_portraitView;
IBOutlet UIView *_landscapeView;
UIView *_currentView;

3番目のビュー、_currentViewは、これらのビューのどれが現在表示されているかを追跡するために必要です。次に、次のような新しい関数を作成します。

-(void)setUpViewForOrientation:(UIInterfaceOrientation)orientation
{
    [_currentView removeFromSuperview];
    if(UIInterfaceOrientationIsLandscape(orientation))
    {
        [self.view addSubview:_landscapeView];
        _currentView = _landscapeView;
    }
    else
    {
        [self.view addSubview:_portraitView];
        _currentView = _portraitView;
    }
}

最初に初期化のために、2つの異なる場所からこの関数を呼び出す必要があります。

-(void)viewDidLoad
{
    [super viewDidLoad];
    UIInterfaceOrientation interfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
    [self setUpViewForOrientation:interfaceOrientation];
}

そして、方向変更の2番目:

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [self setUpViewForOrientation:toInterfaceOrientation];
}

それがあなたを助けることを願っています!

44
MeXx

Apple design。に対してです。両方の方向をサポートする1​​つのViewControllerが必要です。

しかし、本当にやりたい場合は、回転イベントでxibをリロードし、異なるnibファイルをロードする必要があります。

-(void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration
{
    [[NSBundle mainBundle] loadNibNamed:[self nibNameForInterfaceOrientation:toInterfaceOrientation] owner:self options:nil];
    [self viewDidLoad];
}

- (NSString*) nibNameForInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    NSString *postfix = (UIInterfaceOrientationIsLandscape(interfaceOrientation)) ? @"portrait" : @"landscape";
    return [NSString stringWithFormat:@"%@-%@", NSStringFromClass([self class]), postfix];
}

そして、「landscape」と「portrait」でポストフィックスされた2つのnibファイルを作成します。

14

@MeXxのソリューションは気に入っていますが、2つの異なるビュー階層をメモリに保持するオーバーヘッドがあります。また、サブビューの状態(色など)が変化する場合は、階層を切り替えるときにマッピングする必要があります。

別の解決策は、自動レイアウトを使用して、各方向の各サブビューの制約を交換することです。これは、両方の方向のサブビュー間で1:1のマッピングがある場合に最適に機能します。

当然、IBを使用して、各方向のレイアウトを視覚的に定義する必要があります。私の計画では、@ MeXxが規定することを実行する必要がありますが、ペン先が読み込まれたら(awakeFromNib)制約の両方のセットを格納し、レイアウトに正しいセットを再適用する(viewWillLayoutSubviews)。制約をスクレイピングして保存したら、セカンダリビュー階層を破棄できます。 (制約はビュー固有であるため、実際のサブビューに適用する新しい制約を作成する可能性があります)。

申し訳ありませんが、コードがありません。この段階では単なる計画です。

最後の注意-ストーリーボードでは、ビューコントローラーのメインビューの外側にあるビューを記述するのは苦痛なので、ストーリーボードよりもxibの方が簡単です(それ以外の場合は編集するPITAであるため望ましい)。ブラッ!

8
TomSwift

ええ、あなたは確実に....

以前は、デバイスが回転したときに手動でフレームを指定していました

デバイスが回転するたびに、- (void)viewWillLayoutSubviewsが呼び出されます

例-UIViewで_UIButton *button_を取る

_- (void)viewWillLayoutSubviews
   {
       if (UIDeviceOrientationIsLandscape([self.view interfaceOrientation]))
       {
         //x,y as you want
         [ button setFrame:CGRectMake:(x,y,button.width,button.height)];

       }
       else
       {
         //In potrait
          //x,y as you want
         [ button setFrame:CGRectMake:(x,y,button.width,button.height)];


       }

   }
_

このようにして、好きなように配置できます。ありがとう

これらの画像をご覧ください

両方の画面で必要なxCode XIB UIViewの最初の画像

enter image description here

今、私もこのビューを風景で見たいので、-(void)viewWillLayoutSubviewsを編集しに行きました

enter image description here

これで、結果は次のようになります。シミュレータのpotrait画面の最初の画像

enter image description here

これは横向きです

enter image description here

3
kshitij godara

Ios8およびXCode 6の今後の新機能を反映するために、新しい回答を追加したいと思います。

最新の新しいソフトウェアでは、Apple導入 サイズクラス 。これにより、使用している画面のサイズと向きに基づいてストーリーボードがインテリジェントに適応できるようになります。上記のドキュメントまたはWWDC 2014セッション IKitでアダプティブアプリを構築する で、言い換えます。

サイズクラスが enabled、 であることを確認してください。

ストーリーボードファイルが正方形になっていることがわかります。ここで基本的なインターフェイスを設定できます。インターフェイスは、有効なすべてのデバイスと向きに合わせてインテリジェントにサイズ変更されます。

画面の下部に、yAny xAnyというボタンが表示されます。これをクリックすると、たとえば横向きと縦向きなど、1つのサイズクラスのみを変更できます。

上記のドキュメントを読むことをお勧めしますが、ストーリーボードを1つしか使用しないため、これがお役に立てば幸いです。

2
rocket101

ストーリーボードを使用したソリューション[ios7]。メインView Controller内には、Tab Bar Controllerを含めることができるコンテナビューがあります。 Tab Bar Controllerの内部には、2つのタブがあります。 1つのタブは縦向きのコントローラー用で、もう1つのタブは横向きモードのコントローラー用です。

メインView Controllerは、次の機能を実装しています。

#define INTERFACE_ORIENTATION() ([[UIApplication sharedApplication]statusBarOrientation])

@interface MainViewController ()
@property(nonatomic,weak) UITabBarController *embeddedTabBarController;
@end

@implementation MainViewController
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    if ([segue.identifier isEqualToString:@"embedContainer"])
    {
        self.embeddedTabBarController = segue.destinationViewController;
        [self.embeddedTabBarController.tabBar setHidden:YES];
    }
}

- (void) adaptToOrientation:(UIInterfaceOrientation)interfaceOrientation
{
    if (UIInterfaceOrientationIsLandscape(interfaceOrientation))
    {
        [self.embeddedTabBarController setSelectedIndex:1];
    }
    else
    {
        [self.embeddedTabBarController setSelectedIndex:0];
    }
}
- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
    [self adaptToOrientation:interfaceOrientation];    
}

- (void) viewWillAppear:(BOOL)animated
{
    [self adaptToOrientation:INTERFACE_ORIENTATION()];
}

ストーリーボードのセグエリンクは、「embedContainer」という名前にする必要があります。

コンテナビューのサイズを変更して、親ビュー(どちらの場合も風景とポートレート)を満たすようにします。

ランタイムでは、同じコントローラーの2つのインスタンスが同時に存在することに注意してください。

Storyboard


更新: 代替のView Manager用のAppleドキュメント

2
Prcela

ライブラリGPOrientationを使用できます。 リンク

1
Savitha

プログラムによるサイズ変更

私はまったく同じ状況にあるアプリを持っています。私のNIBでは、ポートレートレイアウトができました。他のレイアウトはプログラムで実行されます。プログラムでいくつかのサイズを指定することはそれほど難しくないため、2つのNIBを維持する必要はありません。

フレームを設定してビューの変更をプログラムで実行すると、アニメーションが生成されることに注意してください(またはアニメーションを使用して簡単に作成できます)。これにより、ユーザーはどのコンポーネントがどの位置に移動したかについて貴重なフィードバックを得ることができます。 2番目のビューを読み込むだけの場合、この利点は失われます。UIの観点からは、代替ビューを読み込むことは良い解決策ではないと考えています。

2つのViewControllersを使用する

2つのViewControllerを使用する場合は、Appleの開発者向けドキュメントでその方法を説明しています。つまり、質問に対する答えは RespondingtoDeviceOrientationChanges にあります。

プログラムで実行する場合は、didRotateFromInterfaceOrientationメソッドに再配置コードを追加できます。

ViewControllerにメソッドを追加しました。

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
    [self adjustLayoutToOrientation];
}

次に、レイアウトの調整を実装しました。以下に例を示します(コードはアプリに固有ですが、スーパービューのサイズを読み取り、そこからサブビューのフレームを計算できます。

- (void)adjustLayoutToOrientation
{
    UIInterfaceOrientation toInterfaceOrientation = self.interfaceOrientation;
    bool isIPhone = !([[UIDevice currentDevice] respondsToSelector:@selector(userInterfaceIdiom)] && [[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad);

    [self adjustViewHeight];
    [self adjustSubviewsToFrame: [mailTemplateBody.superview.superview frame]];

    CGRect pickerViewWrapperFrame = pickerViewWrapper.frame;
    if(isIPhone) {
        pickerViewWrapperFrame.Origin.x = 0;
        pickerViewWrapperFrame.size.height = keyboardHeight;
        pickerViewWrapperFrame.Origin.y = [self view].frame.size.height-pickerViewWrapperFrame.size.height;
        pickerViewWrapperFrame.size.width = [self view].frame.size.width;
    }
    else {
        pickerViewWrapperFrame = pickerView.frame;
    }

// MORE ADJUSTMENTS HERE

}
1
Christian Fries