Як налаштувати опорну точку шару CAL, коли використовується автоматичний макет?


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

Відповіді:


361

[EDIT: Попередження: вся наступна дискусія, можливо, застаріла або, принаймні, сильно пом'якшиться за допомогою iOS 8, що більше не може зробити помилку запускати макет під час застосування трансформації перегляду.]

Автоматичний розклад проти перегляду трансформацій

Автовипуск зовсім не добре грає з перетвореннями перегляду. Наскільки я можу помітити, причина полягає в тому, що ви не маєте возитися з кадром виду, який має перетворення (крім трансформації ідентичності за замовчуванням) - але саме це робить авторозкладка. Те, як працює авторозкладка, полягає в тому, що під layoutSubviewsчас виконання відбувається обмеження всіх обмежень і відповідно встановлення кадрів усіх переглядів.

Іншими словами, обмеження не є магічними; вони просто список справ. layoutSubviewsце те, де виконується список справ. І це робиться, встановлюючи кадри.

Я не можу не сприймати це як помилку. Якщо застосувати це перетворення до подання:

v.transform = CGAffineTransformMakeScale(0.5,0.5);

Я очікую, що вид буде з центром у тому самому місці, що і раніше, і в половині розміру. Але залежно від її обмежень це може бути зовсім не тим, що я бачу.

[Насправді тут є друга несподіванка: застосування трансформації до виду запускає макет негайно. Це здається мені ще однією помилкою. А може, це серце першого клопа. Я б очікував, що я можу піти з трансформацією принаймні до моменту розміщення, наприклад, пристрій повернутись так само, як я можу піти з анімацією кадрів до моменту компонування. Але насправді час компонування негайний, що здається просто неправильним.]

Рішення 1: Без обмежень

Одне з поточних рішень полягає в тому, якщо я збираюся застосувати напівперманентне перетворення до подання (а не просто тимчасово помахувати ним), щоб усунути всі обмеження, що впливають на нього. На жаль, це зазвичай призводить до того, що подання зникає з екрану, оскільки авторозкладка все ще має місце, і тепер немає обмежень, щоб сказати нам, куди слід подати подання. Отже, крім усунення обмежень, я встановив вигляд " translatesAutoresizingMaskIntoConstraintsТАК". Перегляд тепер працює за старим способом, фактично не впливаючи на авторозкладку. (Очевидно, на це впливає авторозмітка, але неявні обмеження автоматичної маски призводять до того, що її поведінка є такою, якою вона була до автоматичного розкладу.)

Рішення 2: Використовуйте лише відповідні обмеження

Якщо це здається трохи драстичним, іншим рішенням є встановлення обмежень для правильної роботи з передбачуваною трансформацією. Якщо розмір виду має розмір чистої внутрішньої фіксованої ширини та висоти і розміщений виключно по центру, наприклад, моє масштабне перетворення працюватиме так, як я очікую. У цьому коді я видаляю наявні обмеження в підгляді ( otherView) і замінюю їх на ці чотири обмеження, надаючи йому фіксовану ширину та висоту і чітко закріплюючи його по центру. Після цього моя трансформація масштабу працює:

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причин його макета відбулося, а обмеження можуть змусити погляд перейти навколо. (Це відчувається як помилка чи що?) Але якщо ми зробимо те саме з Core Animation (використовуючи 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

1
Я щось тут не розумію. Рішення4: Коли трансформація застосована до резервного шару, то трансформація також впливає на авторозкладку, оскільки властивість перетворення подання має на увазі трансформацію резервного шару
Luca Bartoletti

1
@Анди навпаки, на iOS 8 проблема повністю зникла, і вся моя відповідь непотрібна
мат

1
@Sunkas Я відповів у вашому питанні.
Бен Сінклер

2
На iOS 8 трансформація шарів також запускає автоматичний макет
CarmeloS

41

У мене був подібний Isuue і щойно я почув Back від команди Autolayout в Apple. Вони пропонують використовувати матовий підхід Container View Approach, але вони створюють підклас 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

Як бачимо, він вперше захоплює центральну точку перегляду при першому виклику та повторно використовує цю позицію при подальших викликах, щоб відповідно розмістити Погляд. Це перезаписує Код автоматичного вимикання в тому сенсі, що він відбувається після [супер layoutSubviews]; який містить код авторозкладки.

На кшталт того, що більше не потрібно уникати Autolayout, але ви можете створити свій власний авторозклад, коли поведінка за замовчуванням більше не підходить. Звичайно, ви можете застосувати складніші речі, ніж те, що є в тому прикладі, але це було все, що мені було потрібно, оскільки мій додаток може використовувати лише портретний режим.


5
Дякуємо, що опублікували це. Оскільки я написав свою відповідь, я, безумовно, зрозумів значення переваги layoutSubviews. Я хотів би лише додати, що Apple тут просто змушує вас робити те, що, на мою думку, вони повинні були робити (при їх реалізації Autolayout) весь час.
мат

Ви маєте рацію, але це, мабуть, насправді не пов'язане з самим Випуском. Оскільки вони надали вищезазначений Кодекс, я задоволений цим!
sensslen

4
Сумно і абсурдно, що команда авторозподілів рекомендує створити спеціальний підклас контейнерів просто для вирішення того, як авторозкладка порушує багаторічну та інтуїтивну поведінку в системі перегляду.
водорості

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 переміститься вліво з відстанню на половину довжини ширини перегляду, тому вам потрібно це компенсувати.

Я не розумію обмеження у питанні. Отже, припустимо, що ви додаєте обмеження centerX щодо superView centerX з константою: layerView.centerX = superView.centerX + константа

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

Келих найкращого пива для вас, мій друже. Це настільки точне вирішення: D
Błażej

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, є встановлення перетворення. Для цього знадобиться більш складна функція, яка оновлює обмеження макета, щоб відобразити всі зміни кадру, які могли бути викликані самим властивістю перетворення. Це складно, оскільки перетворення можуть зробити багато для кадру. Перетворення масштабування або обертання зробить кадр більшим, тому нам знадобиться оновити будь-які обмеження по ширині чи висоті тощо.

Якщо ви використовуєте перетворення лише для тимчасової анімації, то того, що вище, може бути достатньо, оскільки я не вірю, що автоматичний макет не дозволить анімації під час польоту представляти зображення, що представляють суто тимчасові порушення обмежень.


На жаль, я використовую перетворення. Встановлення позиції є прекрасним, оскільки метод викликається кожного разу, коли вигляд викладається, щоб він не зациклювався. Я думаю, що переоформлення layoutRect може бути кращим рішенням (згадувалося в одній з ваших попередніх відповідей), але я ще цього не пробував.
jrturton

До речі, ось тестова установка, яку я використовував. Було б чудово , якби хто - то зрозумів це: github.com/algal/AutolayoutAnchorPointTestRig
водоростеві

Це має бути прийнятою відповіддю. @ matt відповідь навіть не в прив'язці.
Юліан Онофрей

3

tl: dr: Ви можете створити розетку для одного з обмежень, щоб його можна було зняти і знову додати.


Я створив новий проект і додав вигляд із фіксованим розміром у центрі. Обмеження показані на зображенні нижче.

Обмеження для найменшого прикладу, про який я міг придумати.

Далі я додав розетку для подання, яке буде обертатися, і для обмеження центру 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

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
Гаразд, натхненний вашим рішенням про підзор, я додав це до свого реферату! Дякуємо, що дозволили мені грати у вашій пісочниці ...
мат

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

Щоб пояснити далі, в цьому конкретному випадку перетворений вигляд іноді потрібно буде скласти на екран, обертаючись по осі Y на його правому крайньому краю. Отже, точку прив’язки потрібно перемістити. Я також шукаю загальне рішення.
jrturton

Звичайно, ви все ще можете дотриматись anchorPoint, я вважаю, що ви не повинні використовувати його для вимірювання. Система автоматичного вимикання UIView повинна бути незалежною від перетворень CALayer. Тож UIView: макет, CALayer: поява / анімація
Джон Естропія

1
Це має бути, але це не так. Ви насправді пробували це? Зміна точки прив’язки компенсує положення шару після того, як автоматичне розташування виконало свою роботу. Ваше рішення не працює зі зміненою точкою прив’язки.
jrturton

Так, я можу використовувати різні точки прив'язки для моїх поглядів, викладених із обмеженнями. Ваша відповідь у цьому viewDidLayoutSubviewsмає виправити це; positionзавжди йде разом з anchorPoint. Моя відповідь лише показує, як визначити обмеження для трансформації ідентичності.
Джон Естропія

0

Це питання та відповіді надихнули мене вирішити власні проблеми з автоматичним вимиканням та масштабуванням, але з прокрутками. Я створив приклад свого рішення на github:

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

Це приклад UIScrollView з користувацьким підкачкою, повністю створеним у програмі AutoLayout і масштабованим (CATransform3DMakeScale) з довгим натисканням та торкніться для збільшення. iOS 6 та 7 сумісні.


0

Це велика тема, і я не прочитав усіх коментарів, але зіткнувся з тим же питанням.

У мене був вид з XIB з автоматичним розкладом. І я хотів оновити властивість перетворення. Вставлення подання у подання контейнера не вирішує мою проблему, оскільки авторозмітка дивно діяла на подання контейнера. Ось чому я тільки що додав другий вигляд контейнера, щоб містити вигляд контейнера, який містить мій погляд, і застосовував перетворення на ньому.


0

tl; dr. Скажімо, ви змінили опорну точку на (0, 0). Точка прив’язки тепер ліворуч вгорі. Щоразу, коли ви бачите центр слів у автоматичному макеті, вам слід думати зверху ліворуч .

Налаштовуючи anchorPoint, ви просто змінюєте семантику AutoLayout. Автоматичний макет не буде заважати вашому anchorPoint, ні навпаки. Якщо ви цього не розумієте, вам буде погано провести час .


Приклад:

Малюнок А. Ніяких змін точки прив’язки

#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

Малюнок А і Фігура В виглядають абсолютно однаково. Нічого не змінилося. Змінено лише визначення того, на який центр посилається.


Це все добре і добре, але не відповідає на питання, що робити, коли ваші обмеження не пов'язані з центром.
jrturton
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.