web-dev-qa-db-ja.com

XIBからプログラムでカスタムUIViewのサイズを変更する

次の問題があります。カスタムUIViewクラスとそのレイアウトをXIBファイルに作成しました。 XIBでのカスタムビューのサイズが150 x 50であるとしましょう。sizeClasses(wAny hAny)とAutoLayoutを有効にしました。シミュレートされたメトリックでは、Size = FreeformStatus Bar = None、 すべて other = Inferred

カスタムUIViewクラスのコードは次のようになります。

#import "CustomView.h"

@implementation CustomView

#pragma mark - Object lifecycle

- (id)initWithFrame:(CGRect)frame {
    self = [super initWithFrame:frame];

    if (self) {
        [self setup];
    }

    return self;
}

- (id)initWithCoder:(NSCoder *)aDecoder {
    self = [super initWithCoder:aDecoder];

    if (self) {
        [self setup];
    }

    return self;
}

#pragma mark - Private & helper methods

- (void)setup {
    if (self.subviews.count == 0) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self.bounds = self.view.bounds;
        [self addSubview:self.view];
    }
}

@end

このカスタムUIViewControllerを追加するUIViewで、CustomViewを追加するダミーUIView(インターフェイスビルダーで設定したサイズ)を作成しました。 私のCustomViewが私のコンテナビューの境界に一致するようにしたい

私はそれをこのようにしようとしています:

_vCustomView = [[CustomView alloc] init];
_vCustomView.translatesAutoresizingMaskIntoConstraints = NO;
[_vContainer addSubview:_vCustomView];

[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeLeft relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeLeft multiplier:1.0 constant:0.0]];
[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeRight relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeRight multiplier:1.0 constant:0.0]];
[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeTop relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeTop multiplier:1.0 constant:0.0]];
[_vContainer addConstraint:[NSLayoutConstraint constraintWithItem:_vCustomView attribute:NSLayoutAttributeBottom relatedBy:NSLayoutRelationEqual toItem:_vContainer attribute:NSLayoutAttributeBottom multiplier:1.0 constant:0.0]];

しかし、運はありません。コンテナービューが300 x 100で、カスタムUIViewを追加すると、私のカスタムビューは150 x 5になります。

コンテナビューなしで作業を試みました-カスタムUIViewオブジェクトをUIViewControllerのself.viewに直接追加し、幅と高さを次のように設定します。

  • autoLayout制約
  • カスタムを初期化するときにinitWithFrameを使用するUIView

しかし再び-運はありません。カスタムビューは常に150 x 50です。

誰かが私にどのようにして私に説明できるかプログラムでUIViewで作成したカスタムXIBを追加し、autoLayout制約を使用してサイズ変更

よろしくお願いします。

編集#1:CustomViewでAndreaのコードを実行しようとすると発生するエラー

Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) 
(
    "<NSLayoutConstraint:0x17489b760 V:[UIView:0x17418d820(91)]>",
    "<NSLayoutConstraint:0x170c9bf80 V:|-(0)-[CustomView:0x1741da7c0]   (Names: '|':CustomView:0x1741da8b0 )>",
    "<NSLayoutConstraint:0x170c9bfd0 V:[CustomView:0x1741da7c0]-(0)-|   (Names: '|':CustomView:0x1741da8b0 )>",
    "<NSLayoutConstraint:0x170c9be90 V:|-(0)-[CustomView:0x1741da8b0]   (Names: '|':UIView:0x17418d820 )>",
    "<NSLayoutConstraint:0x170c9bee0 CustomView:0x1741da8b0.bottom == UIView:0x17418d820.bottom>",
    "<NSAutoresizingMaskLayoutConstraint:0x170c9dba0 h=--& v=--& CustomView:0x1741da7c0.midY == + 25.0>"
)

Will attempt to recover by breaking constraint 
<NSLayoutConstraint:0x170c9bfd0 V:[CustomView:0x1741da7c0]-(0)-|   (Names: '|':CustomView:0x1741da8b0 )>

編集#2:うまくいく!

@Andreaが追加した後:

view.translatesAutoresizingMaskIntoConstraints = NO;

彼の中で:

- (void) stretchToSuperView:(UIView*) view;

メソッド、すべてが期待どおりに機能します。

@Andreaに感謝します。

14
uerceg

Xibをコンテンツビューに追加するときに自動レイアウトを使用しないことが主な問題だと思います。
initメソッドにサブビューを追加した後、そのメソッドを呼び出して、xibのビューを渡します。

- (void) stretchToSuperView:(UIView*) view {
    view.translatesAutoresizingMaskIntoConstraints = NO;
    NSDictionary *bindings = NSDictionaryOfVariableBindings(view);
    NSString *formatTemplate = @"%@:|[view]|";
    for (NSString * axis in @[@"H",@"V"]) {
        NSString * format = [NSString stringWithFormat:formatTemplate,axis];
        NSArray * constraints = [NSLayoutConstraint constraintsWithVisualFormat:format options:0 metrics:nil views:bindings];
        [view.superview addConstraints:constraints];
    }

}

[編集]
セットアップコードは次のようになります。

- (void)setup {
    if (self.subviews.count == 0) {
        [[NSBundle mainBundle] loadNibNamed:@"CustomView" owner:self options:nil];
        self.bounds = self.view.bounds;
        [self addSubview:self.view];
        [self stretchToSuperView:self.view];
    }
}

ストレッチビュー内に追加したことに注意してくださいview.translatesAutoresizingMaskIntoConstraints = NO;
[編集2]
リクエストに応じて、回答を詳しく説明します。 autolayoutを使用して、制約を設定せずにビューを追加すると、autolayoutは自動サイズ変更マスクを制約に自動的に変換し、それらのデフォルトプロパティはUIViewAutoresizingNoneです。つまり、自動サイズ変更しません。
あなたのXIBビューは、制約なしに、そして自動サイズ変更の可能性なしにその親に追加されたため、元のサイズを維持しています。ビューに合わせてビューのサイズを変更したいので、2つの選択肢があります。

  • Xibビューの自動サイズ変更マスクを柔軟な幅と高さに変更しますが、それらは親サイズと一致する必要があるか、完全なカバーがありません
  • 2つのビューを制約するいくつかの制約を追加して、親の変更に応じて変更します。そして、XIBビューとその親ビューの間で、トレーリング/リーディングとトップ/ボタンの間のスペースが0であると言います。それらの境界に接着剤を付けているようなものです。これを行うには、自動変換のサイズ変更マスクを制約にNOに設定する必要があります。そうしないと、ログに投稿したときに競合が発生する可能性があります。

後で行うことは、ビュー(XIBビューをホストする)にスーパービューに制約を追加することですが、XIBとその親の間に制約がなかったため、自動レイアウトではXIBビューのサイズを変更する方法がわかりません。
ビュー階層の各ビューには、独自の制約が必要です。
これが理解を深めるのに役立つことを願っています。

19
Andrea

スーパービューに拡大するSwift 4.0関数:

コードスニペット:

static public func stretchToSuperView(view:UIView)
    {
        view.translatesAutoresizingMaskIntoConstraints = false
        var d = Dictionary<String,UIView>()
        d["view"] = view
        for axis in ["H","V"] {
            let format = "\(axis):|[view]|"
            let constraints = NSLayoutConstraint.constraints(withVisualFormat: format, options: NSLayoutFormatOptions(rawValue: 0), metrics: [:], views: d)
            view.superview?.addConstraints(constraints)
        }
    }

注:サブビューとして引数を指定して関数を呼び出すだけです。

これは、Swift 4.0の.xib resingの問題を解決するのに役立ちます。

あなたのコードには次のようなものが必要です:

まず、変更したい幅制約へのIBOutletを、viewControllerまたはCustomViewのどちらかで指定します(制約値を計算するためのロジックがどこにあるのか、実際にはわかりません)。

@property (nonatomic, weak) IBOutlet NSLayoutConstraint *widthConstraint;

次に、定数値を更新するメソッドで、次のようなものが得られます。

-(void)updateWidth {
    [self.widthConstraint setConstant:newConstant];
    [self.view layoutIfNeeded]; // self.view must be an ancestor of the view

    //If you need the changes animated, call layoutIfNeeded in an animation block
}

これがうまくいくことを願っています。幸運を!

1
Catalina T.