自動レイアウトを使用しているときに、CALayerのアンカーポイントを調整するにはどうすればよいですか?


161

:この質問が行われて以来、状況は変化しています。最近の概要については、こちらをご覧ください。


自動レイアウトの前に、フレームを保存し、アンカーポイントを設定し、フレームを復元することで、ビューを移動せずにビューのレイヤーのアンカーポイントを変更できます。

自動レイアウトの世界では、もはやフレームを設定しませんが、制約は、ビューの位置を調整して目的の場所に戻すというタスクには及ばないようです。制約をハックしてビューの位置を変更できますが、回転やその他のサイズ変更イベントでは、これらは再び無効になります。

次の優れたアイデアは、「レイアウト属性の無効なペア(左と幅)」を作成するため機能しません。

layerView.layer.anchorPoint = CGPointMake(1.0, 0.5);
// Some other size-related constraints here which all work fine...
[self.view addConstraint:
    [NSLayoutConstraint constraintWithItem:layerView
                                 attribute:NSLayoutAttributeLeft
                                 relatedBy:NSLayoutRelationEqual 
                                    toItem:layerView 
                                 attribute:NSLayoutAttributeWidth 
                                multiplier:0.5 
                                  constant:20.0]];

ここでの私の意図はlayerView、アンカーポイントが調整されたビューの左端を、幅の半分+ 20(スーパービューの左端から差し込みたい距離)に設定することでした。

自動レイアウトでレイアウトされたビューで、ビューの位置を変更せずにアンカーポイントを変更することはできますか?ハードコードされた値を使用し、回転ごとに制約を編集する必要がありますか?私は望んでいない。

ビューに変換を適用したときに正しい視覚効果が得られるように、アンカーポイントを変更する必要があります。


ここにあるものだけを考えると、上記のコードが機能していても、あいまいなレイアウトになってしまうようです。どうやっlayerViewてその幅を知るのですか?それは何か他のものにその右側を突き刺していますか?
ジョンエストロピア、

それはでカバーされています//Size-related constraints that work fine-レイヤビューの幅と高さは、スーパーの由来です。
jrturton 2012年

回答:


361

[編集:警告:次のディスカッション全体がiOS 8によって時代遅れになるか、少なくとも大幅に緩和される可能性があります。これにより、ビューの変換が適用されたときにレイアウトをトリガーするミスを犯すことがなくなります。]

自動レイアウトとビュー変換

Autolayoutはビュー変換ではまったくうまく機能しません。私が識別できる限り、その理由は、変換(デフォルトの恒等変換以外)を持つビューのフレームをいじる必要がないためです-しかし、それはまさにautolayoutが行うことです。autolayoutが機能する方法はlayoutSubviews、ランタイムですべての制約をダッシュ​​し、それに応じてすべてのビューのフレームを設定することです。

つまり、制約は魔法ではありません。彼らはただのやることリストです。layoutSubviewsやることリストが行われる場所です。そして、それはフレームを設定することによってそれを行います。

これをバグとみなすのは仕方ない。この変換をビューに適用すると、次のようになります。

v.transform = CGAffineTransformMakeScale(0.5,0.5);

以前と同じ場所に、半分のサイズでビューの中心が表示されることを期待しています。しかし、その制約にもよりますが、私にはまったく見えないかもしれません。

[実際、2つ目の驚きがあります。ビューに変換を適用すると、レイアウトがすぐにトリガーされます。これは別のバグのようです。または、おそらくそれが最初のバグの中心です。私が期待するのは、レイアウト時間までフレームアニメーションを回避できるのと同じように、デバイスが回転するなど、少なくともレイアウト時間まで変換を回避できることです。しかし、実際には、レイアウト時間は即時であり、これは間違っているようです。]

解決策1:制約なし

現在の解決策の1つは、ビューに影響を与えるすべての制約を削除するために、半永久的な変換をビューに適用する(そして、一時的に何らかの方法で振るだけではない)場合です。残念ながら、これは通常、自動レイアウトがまだ行われているため、ビューが画面から消えてしまい、ビューを配置する場所を指示する制約がなくなりました。したがって、制約を削除することに加えて、ビューtranslatesAutoresizingMaskIntoConstraintsをYES に設定します。ビューは古い方法で機能し、実質的に自動レイアウトの影響を受けません。(それは、明らかに、自動レイアウトの影響を受けますが、暗黙の自動サイズ変更マスクの制約は、その行動は、それが自動レイアウトの前にしただけのようにさせます。)

解決策2:適切な制約のみを使用する

それが少し抜本的であると思われる場合、別の解決策は、目的の変換で正しく機能するように制約を設定することです。たとえば、ビューのサイズが内部の固定幅と高さだけで決まり、純粋に中心で配置されている場合、スケール変換は期待どおりに機能します。このコードでは、サブビュー(otherView)の既存の制約を削除し、それらを4つの制約に置き換えて、幅と高さを固定し、純粋に中心で固定しています。その後、私のスケール変換が機能します:

NSMutableArray* cons = [NSMutableArray array];
for (NSLayoutConstraint* con in self.view.constraints)
    if (con.firstItem == self.otherView || con.secondItem == self.otherView)
        [cons addObject:con];

[self.view removeConstraints:cons];
[self.otherView removeConstraints:self.otherView.constraints];
[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterX relatedBy:0 toItem:self.view attribute:NSLayoutAttributeLeft multiplier:1 constant:self.otherView.center.x]];
[self.view addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeCenterY relatedBy:0 toItem:self.view attribute:NSLayoutAttributeTop multiplier:1 constant:self.otherView.center.y]];
[self.otherView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeWidth relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.width]];
[self.otherView addConstraint:
 [NSLayoutConstraint constraintWithItem:self.otherView attribute:NSLayoutAttributeHeight relatedBy:0 toItem:nil attribute:0 multiplier:1 constant:self.otherView.bounds.size.height]];

要するに、ビューのフレームに影響を与える制約がない場合、自動レイアウトはビューのフレームに影響を与えません。これは、変換が関係しているときに必要なことです。

解決策3:サブビューを使用する

上記の両方のソリューションの問題は、ビューを配置するための制約の利点を失うことです。これを解決するソリューションがあります。ホストとしてのみ機能するジョブの非表示ビューから開始し、制約を使用して配置します。その中に、実際のビューをサブビューとして配置します。制約を使用して、サブビューをホストビュー内に配置しますが、これらの制約は、変換を適用したときに反発しない制約に制限します。

これがイラストです:

ここに画像の説明を入力してください

白いビューはホストビューです。あなたはそれが透明で、それゆえ目に見えないふりをすることになっています。赤いビューは、そのビューの中心をホストビューの中心に固定することによって配置されたサブビューです。これで、赤いビューをその中心の周りで問題なくスケールおよび回転できます。実際、図はそうしたことを示しています。

self.otherView.transform = CGAffineTransformScale(self.otherView.transform, 0.5, 0.5);
self.otherView.transform = CGAffineTransformRotate(self.otherView.transform, M_PI/8.0);

その間、ホストビューの制約により、デバイスを回転させてもホストビューは正しい場所に保持されます。

解決策4:代わりにレイヤー変換を使用する

ビュー変換の代わりに、レイアウトをトリガーせず、制約との即時の競合を引き起こさないレイヤー変換を使用します。

たとえば、次の単純な「ドキドキ」ビューのアニメーションは、自動レイアウトではうまく機能しない可能性があります。

[UIView animateWithDuration:0.3 delay:0
                    options:UIViewAnimationOptionAutoreverse
                 animations:^{
    v.transform = CGAffineTransformMakeScale(1.1, 1.1);
} completion:^(BOOL finished) {
    v.transform = CGAffineTransformIdentity;
}];

最終的にはビューのサイズに変更はありませんでしたが、設定するだけでtransformレイアウトが発生し、制約によってビューがジャンプすることがあります。(これはバグのように感じますか?)しかし、コアアニメーションで同じことを(CABasicAnimationを使用し、アニメーションをビューのレイヤーに適用して)行うと、レイアウトは行われず、正常に機能します。

CABasicAnimation* ba = [CABasicAnimation animationWithKeyPath:@"transform"];
ba.autoreverses = YES;
ba.duration = 0.3;
ba.toValue = [NSValue valueWithCATransform3D:CATransform3DMakeScale(1.1, 1.1, 1)];
[v.layer addAnimation:ba forKey:nil];

3
変換が問題の原因ではなく、新しいアンカーポイントを設定するだけです。制約を取り除き、自動サイズ変更マスクを試してみます。
jrturton 2013年

1
ここで何か理解できません。Solution4:ビューの変換プロパティがバッキングレイヤーの変換を参照しているため、トランスフォームがバッキングレイヤーに適用され、トランスフォームが自動レイアウトにも影響する
Luca Bartoletti 14

1
@Andy反対に、iOS 8では問題は完全になくなり、私の答えはすべて不要です
マット

1
@Sunkas私はあなたの問題で答えました。
ベンシンクレア

2
iOS 8では、レイヤー変換も自動レイアウトをトリガーします
CarmeloS 2015年

41

私は同様の問題を抱えていて、AppleのAutolayoutチームから戻ると聞きました。彼らはContainer Viewアプローチの使用を推奨しますが、mattはUIViewのサブクラスを作成して、layoutSubviewsを上書きし、そこにカスタムレイアウトコードを適用します-チャームのように機能します

ヘッダーファイルはそのように見えるため、選択したサブビューをInterface Builderから直接リンクできます。

#import <UIKit/UIKit.h>

@interface BugFixContainerView : UIView
@property(nonatomic,strong) IBOutlet UIImageView *knobImageView;
@end

そしてmファイルはそのような特別なコードを適用します:

#import "BugFixContainerView.h"

@implementation BugFixContainerView
- (void)layoutSubviews
{
    static CGPoint fixCenter = {0};
    [super layoutSubviews];
    if (CGPointEqualToPoint(fixCenter, CGPointZero)) {
        fixCenter = [self.knobImageView center];
    } else {
        self.knobImageView.center = fixCenter;
    }
}
@end

ご覧のとおり、最初に呼び出されたときにビューの中心点を取得し、それに応じてビューを配置するために、以降の呼び出しでその位置を再利用します。これは、その意味でAutolayoutコードを上書きし、[super layoutSubviews]の後に行われます。自動レイアウトコードが含まれています。

同様に、自動レイアウトを回避する必要はありませんが、デフォルトの動作が適切でなくなったときに独自の自動レイアウトを作成できます。もちろん、その例よりもはるかに複雑なものを適用できますが、私のアプリは縦向きモードしか使用できないため、これで十分でした。


5
これを投稿していただきありがとうございます。回答を書いてから、オーバーライドの重要性を理解するようになりましたlayoutSubviews。ただし、ここでAppleが単に(Autolayoutの実装で)実行する必要があると私が思っいること実行させているだけだと付け加えておきます。
2013

あなたは正しいですが、これは問題自体には実際には関係ないと思います。彼らは上記のコードを提供したので、私はそれで満足です!
sensslen

4
autolayoutチームが、autolayoutがビューシステムで長年の直感的な動作を壊す方法を回避するためだけにカスタムコンテナーサブクラスを作成することを推奨するのは悲しいことです。
藻類、2014年

8

私は簡単な方法を見つけます。そしてそれはiOS 8とiOS 9で動作します。

フレームベースのレイアウトを使用する場合は、anchorPointを調整します。

let oldFrame = layerView.frame
layerView.layer.anchorPoint = newAnchorPoint
layerView.frame = oldFrame

自動レイアウトでビューのアンカーを調整するときも、同じことを行いますが、制約があります。anchorPointが(0.5、0.5)から(1、0.5)に変わると、layerViewはビュー幅の半分の長さの距離で左に移動するため、これを補正する必要があります。

私は質問の制約を理解していません。したがって、以下の定数を使用して、superView centerXに相対的なcenterX制約を追加するとします。layerView.centerX= superView.centerX + constant

layerView.layer.anchorPoint = CGPoint(1, 0.5)
let centerXConstraint = .....
centerXConstraint.constant = centerXConstraint.constant + layerView.bounds.size.width/2

私の友達に最高のビールを これは非常に優れた回避策です。D
BłaFebej

3

自動レイアウトを使用している場合は、最終的に自動レイアウトが独自のレイアウトを計算するときに設定した位置の値を上書きするため、手動で設定した位置が長期的にどのように機能するかわかりません。

むしろ、anchorPointを設定することによって生成される変更を補正するために、レイアウト制約自体を変更する必要があります。次の関数は、変換されていないビューに対してそれを行います。

/**
  Set the anchorPoint of view without changing is perceived position.

 @param view view whose anchorPoint we will mutate
 @param anchorPoint new anchorPoint of the view in unit coords (e.g., {0.5,1.0})
 @param xConstraint an NSLayoutConstraint whose constant property adjust's view x.center
 @param yConstraint an NSLayoutConstraint whose constant property adjust's view y.center

  As multiple constraints can contribute to determining a view's center, the user of this
 function must specify which constraint they want modified in order to compensate for the
 modification in anchorPoint
 */
void SetViewAnchorPointMotionlesslyUpdatingConstraints(UIView * view,CGPoint anchorPoint,
                                                       NSLayoutConstraint * xConstraint,
                                                       NSLayoutConstraint * yConstraint)
{
  // assert: old and new anchorPoint are in view's unit coords
  CGPoint const oldAnchorPoint = view.layer.anchorPoint;
  CGPoint const newAnchorPoint = anchorPoint;

  // Calculate anchorPoints in view's absolute coords
  CGPoint const oldPoint = CGPointMake(view.bounds.size.width * oldAnchorPoint.x,
                                 view.bounds.size.height * oldAnchorPoint.y);
  CGPoint const newPoint = CGPointMake(view.bounds.size.width * newAnchorPoint.x,
                                 view.bounds.size.height * newAnchorPoint.y);

  // Calculate the delta between the anchorPoints
  CGPoint const delta = CGPointMake(newPoint.x-oldPoint.x, newPoint.y-oldPoint.y);

  // get the x & y constraints constants which were contributing to the current
  // view's position, and whose constant properties we will tweak to adjust its position
  CGFloat const oldXConstraintConstant = xConstraint.constant;
  CGFloat const oldYConstraintConstant = yConstraint.constant;

  // calculate new values for the x & y constraints, from the delta in anchorPoint
  // when autolayout recalculates the layout from the modified constraints,
  // it will set a new view.center that compensates for the affect of the anchorPoint
  CGFloat const newXConstraintConstant = oldXConstraintConstant + delta.x;
  CGFloat const newYConstraintConstant = oldYConstraintConstant + delta.y;

  view.layer.anchorPoint = newAnchorPoint;
  xConstraint.constant = newXConstraintConstant;
  yConstraint.constant = newYConstraintConstant;
  [view setNeedsLayout];
}

通常、anchorPointを変更する唯一の理由は変換を設定することであるため、これがおそらくあなたが望んでいたすべてではないことを認めます。これには、transformプロパティ自体によって引き起こされる可能性のあるすべてのフレーム変更を反映するようにレイアウト制約を更新する、より複雑な関数が必要になります。変換はフレームに対して多くのことができるため、これはトリッキーです。スケーリングまたは回転変換はフレームを大きくするため、幅や高さの制約などを更新する必要があります。

一時的なアニメーションの変換のみを使用している場合は、自動レイアウトによってインフライトアニメーションが制約の単なる一時的な違反を表す画像を表示できないとは思わないので、上記で十分です。


残念ながらトランスフォームを使用しています。ビューがレイアウトされるたびにメソッドが呼び出されるため、位置を設定することは問題ありません。layoutRectをオーバーライドする方が良い解決策になると考えています(以前の回答の1つで説明されています)が、まだ試していません。
jrturton 2012年

ちなみに、これが私が使ってきたテストリグです。誰かがこれを理解したとしたら素晴らしいでしょう:github.com/algal/AutolayoutAnchorPointTestRig
algal

これは受け入れられる答えになるはずです。@mattの答えはアンカーポイントについてでもありません。
Iulian Onofrei 2017年

3

tl:dr:制約の1つにアウトレットを作成して、削除して再度追加できるようにすることができます。


新しいプロジェクトを作成し、中央に固定サイズのビューを追加しました。以下の図に制約を示します。

私が考えることができる最小の例の制約。

次に、回転するビューと中心x配置の制約のためのアウトレットを追加しました。

@property (weak, nonatomic) IBOutlet UIView *rotatingView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *xAlignmentContstraint;

後でviewDidAppear新しいアンカーポイントを計算します

UIView *view = self.rotatingView;

CGPoint rotationPoint = // The point I'm rotating around... (only X differs)
CGPoint anchorPoint = CGPointMake((rotationPoint.x-CGRectGetMinX(view.frame))/CGRectGetWidth(view.frame),
                                  (rotationPoint.y-CGRectGetMinY(view.frame))/CGRectGetHeight(view.bounds));

CGFloat xCenterDifference = rotationPoint.x-CGRectGetMidX(view.frame);

view.layer.anchorPoint = anchorPoint;

次に、コンセントがある制約を削除し、オフセットされた新しい制約を作成して、再度追加します。その後、変更された制約を含むビューに、制約を更新する必要があることを伝えます。

[self.view removeConstraint:self.xAlignmentContstraint];
self.xAlignmentContstraint = [NSLayoutConstraint constraintWithItem:self.rotatingView
                                                          attribute:NSLayoutAttributeCenterX
                                                          relatedBy:NSLayoutRelationEqual
                                                             toItem:self.view
                                                          attribute:NSLayoutAttributeCenterX
                                                         multiplier:1.0
                                                           constant:xDiff];
[self.view addConstraint:self.xAlignmentContstraint];
[self.view needsUpdateConstraints];

最後に、回転アニメーションを回転ビューに追加します。

CABasicAnimation *rotate = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotate.toValue = @(-M_PI_2);
rotate.autoreverses = YES;
rotate.repeatCount = INFINITY;
rotate.duration = 1.0;
rotate.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]; 

[view.layer addAnimation:rotate forKey:@"myRotationAnimation"];

回転するレイヤーは、デバイスを回転させたり、その他の方法で制約を更新したりしても、中央に留まるように見えます(そうする必要があります)。新しい制約と変更されたアンカーポイントは、互いに視覚的に相殺されます。


1
これは私の特定の状況で機能しますが、素晴らしい一般的な解決策が可能であるようには見えません。
jrturton 2013年

1

現在の解決策は、でレイヤーの位置を手動で調整することviewDidLayoutSubviewsです。このコードはlayoutSubviewsビューサブクラスにも使用できますが、私の場合、ビューはビューコントローラー内のトップレベルビューであるため、UIViewサブクラスを作成する必要はありませんでした。

努力が多すぎるようですので、他の回答は大歓迎です。

-(void)viewDidLayoutSubviews
{
    for (UIView *view in self.view.subviews)
    {
        CGPoint anchorPoint = view.layer.anchorPoint;
        // We're only interested in views with a non-standard anchor point
        if (!CGPointEqualToPoint(CGPointMake(0.5, 0.5),anchorPoint))
        {
            CGFloat xDifference = anchorPoint.x - 0.5;
            CGFloat yDifference = anchorPoint.y - 0.5;
            CGPoint currentPosition = view.layer.position;

            // Use transforms if we can, otherwise manually calculate the frame change
            // Assuming a transform is in use since we are changing the anchor point. 
            if (CATransform3DIsAffine(view.layer.transform))
            {
                CGAffineTransform current = CATransform3DGetAffineTransform(view.layer.transform);
                CGAffineTransform invert = CGAffineTransformInvert(current);
                currentPosition = CGPointApplyAffineTransform(currentPosition, invert);
                currentPosition.x += (view.bounds.size.width * xDifference);
                currentPosition.y += (view.bounds.size.height * yDifference);
                currentPosition = CGPointApplyAffineTransform(currentPosition, current);
            }
            else
            {
                CGFloat transformXRatio = view.bounds.size.width / view.frame.size.width;

                if (xDifference < 0)
                    transformXRatio = 1.0/transformXRatio;

                CGFloat transformYRatio = view.bounds.size.height / view.frame.size.height;
                if (yDifference < 0)
                    transformYRatio = 1.0/transformYRatio;

                currentPosition.x += (view.bounds.size.width * xDifference) * transformXRatio;
                currentPosition.y += (view.bounds.size.height * yDifference) * transformYRatio;
            }
            view.layer.position = currentPosition;
        }

    }
}

1

私のマットの答えを刺激して、私は別のアプローチを試すことにしました。制約が適切に適用されたコンテナビューを使用できます。次に、アンカーポイントが変更されたビューを、自動サイズ変更マスクと明示的なフレーム設定を使用して、古き良き時代と同じようにコンテナビュー内に配置できます。

それはとにかく私の状況のた​​めに、それは御馳走を働かせます。ビューは、ここでviewDidLoadで設定されます。

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    UIView *redView = [UIView new];
    redView.translatesAutoresizingMaskIntoConstraints = NO;
    redView.backgroundColor = [UIColor redColor];
    [self.view addSubview:redView];

    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"|-[redView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    [self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|-[redView]-|" options:0 metrics:nil views:NSDictionaryOfVariableBindings(redView)]];
    self.redView = redView;

    UIView *greenView = [UIView new];
    greenView.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
    greenView.layer.anchorPoint = CGPointMake(1.0, 0.5);
    greenView.frame = redView.bounds;
    greenView.backgroundColor = [UIColor greenColor];
    [redView addSubview:greenView];
    self.greenView = greenView;

    CATransform3D perspective = CATransform3DIdentity;
    perspective.m34 = 0.005;
    self.redView.layer.sublayerTransform = perspective;
}

緑のビューの自動サイズ変更マスクのため、赤のビューのフレームがこの時点でゼロであることは重要ではありません。

アクションメソッドに回転変換を追加したところ、次のような結果になりました。

ここに画像の説明を入力してください

デバイスのローテーション中にそれ自体が失われるようだったので、これをviewDidLayoutSubviewsメソッドに追加しました。

-(void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [CATransaction begin];
    [CATransaction setDisableActions:YES];
    CATransform3D transform = self.greenView.layer.transform;
    self.greenView.layer.transform = CATransform3DIdentity;
    self.greenView.frame = self.redView.bounds;
    self.greenView.layer.transform = transform;
    [CATransaction commit];

}

あなたの場合、そのままにview.layerしてすべての作業をのサブレイヤーで行うのは簡単ではなかったでしょうかview.layer。つまり、ビューは単なるホストであり、すべての描画とサブレイヤーの変換などは、制約の影響を受けずに1つ下のレベルになります。
2013年

1
さて、あなたのサブビューソリューションに触発されて、私はそれを私のエッセイに追加しました!サンドボックスで遊んでくれてありがとう...
matt

0

あなたはその方法で自動レイアウトの目的を打ち負かしていると思います。幅と右端はスーパービューに依存することをおっしゃっていましたが、その考え方に沿って制約を追加してみませんか?

anchorPoint / transformパラダイムを失って、以下を試してください:

[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
                             attribute:NSLayoutAttributeRight
                             relatedBy:NSLayoutRelationEqual 
                                toItem:self.view 
                             attribute:NSLayoutAttributeWidth 
                            multiplier:1.0f
                              constant:-somePadding]];
[self.view addConstraint:
[NSLayoutConstraint constraintWithItem:layerView
                             attribute:NSLayoutAttributeWidth
                             relatedBy:NSLayoutRelationEqual 
                                toItem:someViewWeDependTheWidthOn
                             attribute:NSLayoutAttributeWidth 
                            multiplier:0.5f // because you want it to be half of someViewWeDependTheWidthOn
                              constant:-20.0f]]; // your 20pt offset from the left

NSLayoutAttributeRight正確のような制約手段anchorPoint = CGPointMake(1.0, 0.5)、およびNSLayoutAttributeWidth制約があなたの前のコードのとほぼ同等ですNSLayoutAttributeLeft


回答ありがとうございます。「アンカーポイントを失う/パラダイムを変える」ことはできません。変換を適用し、アンカーポイントを調整して正しい変換を行う必要があります。
jrturton 2012年

さらに説明すると、この特定のケースでは、変換されたビューは、右端のY軸に沿って回転することによって画面に折りたたむ必要がある場合があります。したがって、アンカーポイントを移動する必要があります。一般的な解決策も探しています。
jrturton 2012年

もちろん、を維持するanchorPointことはできますが、測定には使用しないでください。UIView自動レイアウトシステムは、CALayer変換から独立している必要があります。したがって、UIView:layout、CALayer:appearance / animations
John Estropia

1
あるはずですが、そうではありません。実際にこれを試しましたか?アンカーポイントを変更すると、自動レイアウトが機能したにレイヤーの位置がオフセットされます。ソリューションは、変更されたアンカーポイントでは機能しません。
jrturton 2012年

はい、制約付きでレイアウトされたビューに別のanchorPointsを使用できます。あなたの答えはそれviewDidLayoutSubviewsを修正する必要があります。position常に一緒に行くanchorPoint。私の答えは、恒等変換の制約を定義する方法を示すだけです。
ジョンエストロピア

0

この質問と回答に触発されて、Autolayoutとスケーリングに関する自分の問題を解決しましたが、Scrollviewに関する問題が解決しました。私はgithubで私のソリューションの例を作成しました:

https://github.com/hansdesmedt/AutoLayout-scrollview-scale

これは、AutoLayoutで完全に作成されたカスタムページングを使用したUIScrollViewの例であり、長押ししてタップするとズームできるスケーラブル(CATransform3DMakeScale)です。iOS 6および7互換。


0

これは大きなトピックであり、すべてのコメントを読んだわけではありませんが、同じ問題に直面していました。

自動レイアウトを使用してXIBからのビューがありました。そして、私はその変換プロパティを更新したかった。ビューをコンテナービューに埋め込んでも、自動レイアウトがコンテナービューで奇妙に動作していたため、問題が解決しません。そのため、ビューを含むコンテナービューを含めるために2番目のコンテナービューを追加し、それに変換を適用しました。


0

tl; drアンカーポイントを(0、0)に変更したとします。アンカーポイントが左上になりました。自動レイアウトで中央の単語が表示されている場合は、常に左上を考える必要があります。

anchorPointを調整するときは、AutoLayoutのセマンティクスを変更するだけです。自動レイアウトは、anchorPointを妨害したり、その逆を行ったりすることはありません。これを理解しないと、あなたは悪い時間を過ごすことになります


例:

図A. アンカーポイントの変更なし

#Before changing anchor point to top-left
view.size == superview.size
view.center == superview.center

図B. アンカーポイントが左上に変更されました

view.layer.anchorPoint = CGPointMake(0, 0)
view.size == superview.size
view.center == superview.topLeft                <----- L0-0K, center is now top-left

図Aと図Bはまったく同じに見えます。何も変わっていません。どのセンターが何を参照するかの定義が変更されました。


これで問題は解決しましたが、制約がセンターに関連していない場合の対処法はわかりません。
jrturton、2015
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.