98

私は基本的に、xcode 6 で導入されたサイジング クラスを使用して、iPad の向き (ポートレートまたはランドスケープ) に応じてサブビューを異なる位置に配置したいと考えています。ただし、IB 上の iPad の個々の横向きまたは縦向きモードをカバーするものはないようです。誰でも助けることができますか?

4

7 に答える 7

176

Apple は両方の iPad の向きを同じように扱うことを意図しているように見えますが、多くの人が気付いているように、iPad の縦向きと iPad の横向きで UI レイアウトを変えたいという非常に正当な設計上の理由があります。

残念ながら、現在の OS はこの区別をサポートしていないようです...つまり、コードで自動レイアウト制約を操作するか、同様の回避策を使用して、理想的にはアダプティブ UI を使用して無料で取得できるようにする必要があります。 .

エレガントなソリューションではありません。

Apple がすでに IB と UIKit に組み込んでいる魔法を利用して、特定の方向に対して選択したサイズ クラスを使用する方法はありませんか?

この問題をより一般的に考えると、「サイズ クラス」は、実行時に必要に応じて呼び出すことができるように、IB に格納されている複数のレイアウトに対処する単純な方法であることに気付きました。

実際、「サイズ クラス」は、実際には列挙値のペアにすぎません。UIInterface.h から:

typedef NS_ENUM(NSInteger, UIUserInterfaceSizeClass) {
    UIUserInterfaceSizeClassUnspecified = 0,
    UIUserInterfaceSizeClassCompact     = 1,
    UIUserInterfaceSizeClassRegular     = 2,
} NS_ENUM_AVAILABLE_IOS(8_0);

したがって、Apple がこれらのさまざまなバリエーションにどのような名前を付けることにしたかに関係なく、基本的には、レイアウトを別のレイアウトと区別するために一種の一意の識別子として使用される整数のペアにすぎず、IB に保存されます。

ここで、IB で (未使用のサイズ クラスを使用して) 別のレイアウトを作成するとします。たとえば、iPad のポートレート用に ...実行時に必要に応じて、選択したサイズ クラス (UI レイアウト) をデバイスに使用させる方法はありますか? ?

問題に対していくつかの異なる (洗練されていない) アプローチを試みた後、プログラムでデフォルトのサイズ クラスをオーバーライドする方法があるのではないかと考えました。そして(UIViewController.hに)あります:

// Call to modify the trait collection for child view controllers.
- (void)setOverrideTraitCollection:(UITraitCollection *)collection forChildViewController:(UIViewController *)childViewController NS_AVAILABLE_IOS(8_0);
- (UITraitCollection *)overrideTraitCollectionForChildViewController:(UIViewController *)childViewController NS_AVAILABLE_IOS(8_0);

したがって、View Controller階層を「子」View Controllerとしてパッケージ化し、それを最上位の親View Controllerに追加できる場合...条件付きで子をオーバーライドして、デフォルトとは異なるサイズクラスであると考えることができますOSから。

「親」View Controllerでこれを行うサンプル実装を次に示します。

@interface RDTraitCollectionOverrideViewController : UIViewController {
    BOOL _willTransitionToPortrait;
    UITraitCollection *_traitCollection_CompactRegular;
    UITraitCollection *_traitCollection_AnyAny;
}
@end

@implementation RDTraitCollectionOverrideViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    [self setUpReferenceSizeClasses];
}

- (void)setUpReferenceSizeClasses {
    UITraitCollection *traitCollection_hCompact = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassCompact];
    UITraitCollection *traitCollection_vRegular = [UITraitCollection traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassRegular];
    _traitCollection_CompactRegular = [UITraitCollection traitCollectionWithTraitsFromCollections:@[traitCollection_hCompact, traitCollection_vRegular]];

    UITraitCollection *traitCollection_hAny = [UITraitCollection traitCollectionWithHorizontalSizeClass:UIUserInterfaceSizeClassUnspecified];
    UITraitCollection *traitCollection_vAny = [UITraitCollection traitCollectionWithVerticalSizeClass:UIUserInterfaceSizeClassUnspecified];
    _traitCollection_AnyAny = [UITraitCollection traitCollectionWithTraitsFromCollections:@[traitCollection_hAny, traitCollection_vAny]];
}

-(void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    _willTransitionToPortrait = self.view.frame.size.height > self.view.frame.size.width;
}

- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator]
    _willTransitionToPortrait = size.height > size.width;
}

-(UITraitCollection *)overrideTraitCollectionForChildViewController:(UIViewController *)childViewController {
    UITraitCollection *traitCollectionForOverride = _willTransitionToPortrait ? _traitCollection_CompactRegular : _traitCollection_AnyAny;
    return traitCollectionForOverride;
}
@end

動作するかどうかを確認するための簡単なデモとして、IB の子コントローラー レイアウトの 'Regular/Regular' および 'Compact/Regular' バージョンに特別にカスタム ラベルを追加しました。

ここに画像の説明を入力 ここに画像の説明を入力

iPad が両方の向きにある場合の実行中の様子は次のとおりです。 ここに画像の説明を入力 ここに画像の説明を入力

出来上がり!実行時のカスタム サイズのクラス構成。

Apple が OS の次のバージョンでこれを不要にすることを願っています。それまでの間、これは、自動レイアウトの制約をプログラムでいじったり、コードで他の操作を行ったりするよりも、洗練されたスケーラブルなアプローチになる可能性があります。

編集(2015 年 6 月 4 日): 上記のサンプル コードは、基本的に、この手法を実証するための概念実証であることを念頭に置いてください。独自の特定のアプリケーションの必要に応じて自由に変更してください。

編集(2015 年 7 月 24 日): 上記の説明が問題の解明に役立つと思われることは喜ばしいことです。私はそれをテストしていませんが、mohamede1945 によるコード [下記] は、実用的な目的に役立つ最適化のように見えます。お気軽に試してみて、ご意見をお聞かせください。(完全を期すために、上記のサンプル コードはそのままにしておきます。)

于 2015-02-01T21:34:32.240 に答える
0

ランドスケープ モードは、ポートレート モードとどの程度異なりますか? 大きく異なる場合は、別のビュー コントローラーを作成し、デバイスが横向きのときにそれを読み込むことをお勧めします。

例えば

    if (UIDeviceOrientationIsLandscape([UIDevice currentDevice].orientation)) 
    //load landscape view controller here
于 2014-10-29T15:04:59.837 に答える