AutoLayoutレイアウト使用上の注意点

7859 ワード

UIについて
1.3つのコントロールa,b,cがあれば、左から右へのレイアウトはa,b,cの順である.aとcはずっと存在し、bは一定の条件によって隠すことがあり、表示することがある.では、Masonryレイアウトで、bの制約をどのように設定しますか?
e.g.name,level,shoppingの順
//    
@property (nonatomic, strong) MASConstraint *shoppingLabelLeftToNameConstraint;
@property (nonatomic, strong) MASConstraint *shoppingLabelLeftToLevelConstraint;
//    
        [self.shoppingCarImageV mas_makeConstraints:^(MASConstraintMaker *make) {
            self.shoppingLabelLeftToLevelConstraint = make.left.mas_equalTo(self.levelView.mas_right).mas_offset(6);
            self.shoppingLabelLeftToNameConstraint = make.left.mas_equalTo(self.nameLabel.mas_right).mas_offset(6)          make.centerY.mas_equalTo(self.nameLabel.mas_centerY);
        }];
//      
if (     ){
        [self.shoppingLabelLeftToLevelConstraint activate];
        [self.shoppingLabelLeftToNameConstraint deactivate];
} else{
        [self.shoppingLabelLeftToNameConstraint activate];
        [self.shoppingLabelLeftToLevelConstraint deactivate];
}

これにより、コンストレイントが混乱してコントロールの表示が正常でないことを回避できます.
2.自動レイアウトにおける親コントロールのサブコントロールによるサイズの適応
UILabel,UIImageView,UIButtonなどのUIViewに継承されたコントロールは,いずれも:Intrinsic Content Sizeプロパティを利用することができる.UIViewの-(CGSize)intrinsicContentSize:メソッドを書き換えます.また、この値を変更する必要がある場合は、invalidateIntrinsicContentSizeメソッドを呼び出し、システムにこの値が変更されたことを通知します.したがって,UIViewから継承されたカスタムコンポーネントを記述する際に,Intrinsic Content Sizeも必要とする場合には,この方法で容易に実現できる.eg.
  //   view :(.m  )
- (void)setup{

        // 0.    
        self.backgroundColor = [UIColor grayColor];
    
        [self addSubview:self.label1];
        [self addSubview:self.button2];
        [self addSubview:self.label3];
    
    [self.label1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left).offset(10);
        make.top.equalTo(self);
    }];
    [self.button2 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.label1.mas_right).offset(10);
        make.top.equalTo(self);
    }];
    [self.label3 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.button2.mas_right).offset(10);
        make.top.equalTo(self);
    }];

}

- (UILabel *)label1
{
    if (!_label1) {
        self.label1 = [[UILabel alloc] init];
        self.label1.backgroundColor = [UIColor orangeColor];
        self.label1.text = @"label1";
    }
    return _label1;
}
- (UIButton *)button2
{
    if (!_button2) {
        self.button2 = [[UIButton alloc] init];
        self.button2.backgroundColor = [UIColor orangeColor];
        [self.button2 setTitle:@"button2" forState:(UIControlStateNormal)];
    }
    return _button2;
}
- (UILabel *)label3
{
    if (!_label3) {
        self.label3 = [[UILabel alloc] init];
        self.label3.backgroundColor = [UIColor orangeColor];
        self.label3.text = @"label3";
    }
    return _label3;
}
- (CGSize)intrinsicContentSize
{
    CGFloat height = MAX([self.label1 sizeThatFits:CGSizeZero].height, [self.button2 sizeThatFits:CGSizeZero].height);
//    CGFloat width = 2 * MARGIN + 6*NUMBER_PADDING;
    CGFloat width = 30;
    for (UIView *subView in self.subviews) {
        width += [subView sizeThatFits:CGSizeZero].width;
    }
    return CGSizeMake(width, height);
}

//viewController     :
  {
        TestView *view = [[TestView alloc] init];
//        view.backgroundColor = [UIColor grayColor];
        [self.view addSubview:view];
        [view mas_makeConstraints:^(MASConstraintMaker *make) {
            make.left.top.mas_equalTo(100);
            
        }];
        //      ,      “[view invalidateIntrinsicContentSize];”   , view       ,   view   label    (    ),view       ,  ,      :    invalidateIntrinsicContentSize  。
        [self performSelector:@selector(testInvalidateIntrinsic:) withObject:view afterDelay:4];
    
    }

    //      :
- (void)testInvalidateIntrinsic:(TestView *)view
{
    [view invalidateIntrinsicContentSize];
    view.label1.text = @"fdsajfdsjadfs";
    [view.button2 setTitle:@"dfdsfjs" forState:(UIControlStateNormal)];

}


注意:Intrinsic Contenet Size–Intrinsic Content Size:固有サイズ.その名の通りAutoLayoutでは、UIViewのプロパティとして(文法上の属性ではありません)という意味で、自分の大きさを知っています.もしあなたが私にサイズを指定してくれなかったら、私はこのサイズに従います.例えば、AutoLayoutを使うとき、UILabelはサイズを指定する必要はありません.位置を指定するだけでいいのです.文字の内容やフォントなどの情報を確定すれば、自分で計算できるからです大きさを出す.
コードでは、上記のシステムコントロールは、UIViewの-(CGSize)intrinsicContentSize:メソッドを書き換えています.また、この値を変更する必要がある場合は、invalidateIntrinsicContentSizeメソッドを呼び出し、システムにこの値が変更されたことを通知します.
したがって,UIViewから継承されたカスタムコンポーネントを記述する際に,Intrinsic Content Sizeも必要とする場合には,この方法で容易に実現できる.
Intrinsic競合–1つのUIViewにIntrinsic Content Sizeがある場合、サイズを指定せずに位置のみを指定できます.これらの2つのコンストレイントがトリガーされる可能性があります.しかし問題はまた来ており,上記のようなUIVEewでは位置のみを指定して大きさを指定しない場合があり,問題がある場合がある.UILabelを例に挙げましょう(Intrinsic Content Sizeをサポートするすべてのコンポーネントにこの問題があります).2つのUILabel,UILabel 1(文字内容:UILabel 1)とUILabel 2(文字内容:UILabel 2)、その内容は以下のようにレイアウトを説明します:-2つのUILabelは上の欄から50点です.-UILabel 1と左の欄の距離は10、UILabel 2の左の距離UILabel 1は10点です.いずれもIntrinsic属性を持っているのでsizeを指定する必要はありません.位置も明らかになったはずです.今問題が来て、UILabel 2に制約を加えて、右側の距離は右の欄です10時です.明らかに、制約に従ってレイアウトすると、2つのUIlabelがIntrinsic Content Sizeを使用し、少なくとも1つのUIlabelの幅がIntrinsic Content Sizeより大きいことを満たすことはできません.この場合,2つのコンポーネント間の「Intrinsic競合」と呼ぶ.「Intrinsic競合」を解決する方法は2つあります.a.両方のUIlabelはIntrinsic Content Sizeを使用しません.2つのUIlabelに新しい制約を追加して、それらのサイズを明示的に指定します.たとえば、2つのUIlabelに幅や高さコンストレイント、等幅などの高さコンストレイントを追加します.b.一方のUIlabelにIntrinsic Content Sizeを使用させることができ、他方のlabelは自動的に残りのスペースを占有する.このときContent HuggingとContent Compression Resistanceが必要です!
content Hugging/content Compression Resistance–まず、この2つの概念はUIViewのプロパティです.2つのコンポーネントが「Intrinsic競合」:1.Content Huggingコンストレイント(大きくなりたくないコンストレイント)は、コンポーネントのこのアトリビュートの優先度が他のコンポーネントよりも高い場合、このコンポーネントはそのままで、もう1つはストレッチが必要なときにストレッチできます.アトリビュートは横方向と縦方向の2つの方向に分かれています.2.Content Compression Resistanceコンストレイント(制約を小さくしたくない)表示:コンポーネントのこの属性優先度が他のコンポーネントよりも高い場合、このコンポーネントはそのままで、もう1つは圧縮が必要なときに圧縮できます.属性は横方向と縦方向の2つの方向に分かれています.意味は明らかです.上記のUIlabelの例では、あるUILabelがIntrinsic Content Sizeの場合、もう1つは伸ばす必要があります.2つのUILabelのContent Hugging制約の優先度を調整する必要があります.参照先:http://blog.csdn.net/hard_man/article/details/50888377
3. sizeThatFits; preferredMaxLayoutWidth; sizeToFit
e.g.例えばlabel:
    [self.label1 mas_makeConstraints:^(MASConstraintMaker *make) {
        make.left.equalTo(self.mas_left).offset(10);
        make.top.equalTo(self);
        make.width.mas_equalTo([self.label1 sizeThatFits:CGSizeMake(50, UIViewNoIntrinsicMetric)].width);
//        NSLog(@"%@", @([self.label1 sizeThatFits:CGSizeZero].width + 10));
    }];
    //CGSizeMake(10, UIViewNoIntrinsicMetric)
    self.label1.preferredMaxLayoutWidth = 80;

sizeThatFits:
この方法では,labelコンテンツの実際の幅と高さを取得することができ,パラメータ伝達:CGSizeZero,戻り値は取得したコンテンツの実際の幅と高さである.パラメータがCGSizeZeroを伝達しない場合、例えばCGSizeMake(50,UIViewNoIntrinsicMetric)が伝達され、50はコンテンツの幅を制限し、labelのnumberOfLines=0を設定すると、labelの入力text幅が50より大きい場合、labelは改行し、さらに高さを増やしてtextを満たす.
preferedMaxLayoutWidthこの方法:
数値を設定と、この幅を制限幅とする高さを自動的に計算するために使用され、例えばself.label1.preferredMaxLayoutWidth = 80; すると、labelのtext文字列は80を幅とし、対応する高さh 1を算出すると、labelコントロール表示の高さがh 1となる.この場合、labelのsizeThatFits:CGSizeMake(50,UIViewNoIntrinsicMetric)が50に設定されると、実際のコンテンツの高さはtext文字列が50を幅として算出されたh 2であり、h 2はコンテンツの実際の高さであり、この場合:h 2はh 1より大きく、コンテンツの実際の高さがコントロールの高さより大きいと、コンテンツが不完全に表示されます.逆に、h 2がh 1より小さい場合、コントロールには多くの空きがあります.まとめ:この例では、コントロールの幅:sizeThatFits:CGSizeMake(50,UIViewNoIntrinsicMetric)、sizeの幅パラメータ50をコントロールが実際に表示する幅とする.コントロールの高さ:self.label1.preferredMaxLayoutWidth = 80;のpreferedMaxLayoutWidth値80で算出された高さは、コントロールが実際に表示する高さです.この例では、labelの大きさは幅:50、高さ:text内容が80を幅として計算された高さであり、背景はオレンジ色である.
一般的に、上記の2つの方法は、シーンに応じて1つだけ使用され、1つだけ使用される場合、コントロールの幅と高さは、この方法のルールに従って計算されます.
sizeToFit:
は、コントロールがframeで位置とサイズを設定した後、このメソッドを呼び出し、コントロールはコンテンツの幅などに応じて自動的にコンテンツのサイズに適応します.コントロールは内容によって変わります.