Як централізувати підперегляд UIView


128

У мене є UIViewвнутрішня UIViewм і я хочу, щоб внутрішня UIViewзавжди була зосереджена всередині зовнішньої, не змінюючи розміри ширини та висоти.

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


2
Прийнята відповідь невірна і зламається. Відповідь Хеджазі працює чудово.
Fattie

Відповіді:


209

Ціль-С

yourSubView.center = CGPointMake(yourView.frame.size.width  / 2, 
                                 yourView.frame.size.height / 2);

Швидкий

yourSubView.center = CGPoint(x: yourView.frame.size.width  / 2,
                             y: yourView.frame.size.height / 2)

51
Ви повинні використовувати the, boundsа не the frame, оскільки значення frameне визначено, якщо представлення має a transform.
omz

1
Насправді в цьому випадку нічого не зміниться, як тільки sizeвикористовується.
Peter DeWeese

1
Це не має значення, усе frameвластивість не визначено, якщо представлення має а, transformщо не є перетворенням ідентичності; читати документацію про властивість фрейму UIView .
omz

6
На жаль, ця відповідь насправді неправильна . Просто використовуйте правильну відповідь Хеджу.
Fattie

@Fattie, що тут точно не так? Я використовував його для центрування ImageView у представленні, і він працює.
jreft56

284

Ви можете це зробити, і це завжди буде працювати:

child.center = [parent convertPoint:parent.center fromView:parent.superview];

А для Свіфта:

child.center = parent.convert(parent.center, from:parent.superview)

1
і не забудьте згодом, child.frame = CGRectIntegral (child.frame);
Fattie

8
Перший: це працює лише в тому випадку, якщо ви не змінили центр / місце розташування батьківського подання. По- друге: Якщо ви використовуєте цей метод , немає ніякої необхідності , щоб перетворити точку (це вже в правильному форматі) просто використовувати child.center = parent.center. Я б використовував `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. Це завжди буде зосереджено ваш підвід, незалежно від того, на який налаштований центр перегляду батьків.
Стара назва

1
Це також не корисно, якщо подання ще не було додано до ієрархії перегляду (наприклад, під час запуску об'єкта)
Victor Jalencas

1
@Hejazi Було б непогано також додати швидку відповідь;)
Мілад Фарідня

1
@ Сумен Ні, різниця є. UIView.boundsє відносно самого виду (і тому bounds.originспочатку дорівнює нулю), в той час UIView.centerяк задається в системі координат нагляду .
Хеджазі

41

Перш ніж розпочати, нагадаємо, що точка початку - верхній лівий кут CGPointзору. Важливо зрозуміти про погляди та батьків.

Давайте подивимось на цей простий код - контролер перегляду, який додає до його виду чорний квадрат:

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        createDummyView()
        super.view.backgroundColor = UIColor.cyanColor();
    }

    func createDummyView(){
        var subView = UIView(frame: CGRect(x: 15, y: 50, width: 50 , height: 50));
        super.view.addSubview(subView);
        view.backgroundColor = UIColor.blackColor()
    }

}

Це створить такий вигляд: початок і центр чорного прямокутника точно відповідають тим же координатам, що і його батьківський

введіть тут опис зображення

Тепер спробуємо додати subView інший SubSubView і надати subSubview того самого походження, що і subView, але зробимо subSubView дочірнім підглядом subView

Ми додамо цей код:

var subSubView = UIView();
subSubView.frame.origin = subView.frame.origin;
subSubView.frame.size = CGSizeMake(20, 20);
subSubView.backgroundColor = UIColor.purpleColor()
subView.addSubview(subSubView)

І ось результат:

введіть тут опис зображення

Через цей рядок:

subSubView.frame.origin = subView.frame.origin;

Ви очікуєте, що походження фіолетового прямокутника буде таким самим, як його батьківське (чорний прямокутник), але воно йде під ним, і чому це так? Оскільки, коли ви додаєте подання до іншого виду, кадр subView "світ" тепер є батьківським BOUND RECTANGLE, якщо у вас є подання, що його походження на головному екрані знаходиться в координатах (15,15) для всіх його переглядів, лівий верхній кут буде (0,0)

Ось чому вам потрібно завжди звертатися до батька за його зв'язаним прямокутником, який є "світом" його subView, дозволяє виправити цю лінію на:

subSubView.frame.origin = subView.bounds.origin;

І подивіться на магію, підрозгляд тепер розташований саме в його батьківському походженні:

введіть тут опис зображення

Отже, вам подобається, що "добре, я хотів лише зосередити свій погляд на моїх батьківських уявленнях, у чому полягає головна справа?" ну, це не велика справа, вам просто потрібно "перевести" батьківську точку Центру, яка взята з її фрейму, до центру меж батьків, роблячи це:

subSubView.center = subView.convertPoint(subView.center, fromView: subSubView);

Ви насправді говорите йому: "Візьміть батьківський оглядовий центр та перетворіть його у світ subSubView".

І ви отримаєте такий результат:

введіть тут опис зображення


Туди, де розміщується рядок 'subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)'?
Тамарай T

26

Я б використав:

self.childView.center = CGPointMake(CGRectGetMidX(self.parentView.bounds),
                                    CGRectGetMidY(self.parentView.bounds));

Мені подобається використовувати CGRectваріанти ...

SWIFT 3:

self.childView.center = CGPoint(x: self.parentView.bounds.midX,
                                        y: self.parentView.bounds.midY);

19

1. Якщо увімкнено автоматичний розклад:

  • Підказка: для центрування подання на іншому представленні за допомогою авторозмітки ви можете використовувати один і той же код для будь-яких двох представлень, що розділяють принаймні один батьківський вигляд.

Перш за все вимкніть автоматичне перегляд дочірніх зображень

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Якщо ви UIView + Autolayout або Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Якщо ви використовуєте лише методи авторозміщення рівня UIKit:

    [view1 addConstraints:({
        @[ [NSLayoutConstraint
           constraintWithItem:view1
           attribute:NSLayoutAttributeCenterX
           relatedBy:NSLayoutRelationEqual
           toItem:view2
           attribute:NSLayoutAttributeCenterX
           multiplier:1.f constant:0.f],
    
           [NSLayoutConstraint
            constraintWithItem:view1
            attribute:NSLayoutAttributeCenterY
            relatedBy:NSLayoutRelationEqual
            toItem:view2
            attribute:NSLayoutAttributeCenterY
            multiplier:1.f constant:0.f] ];
    })];

2. Без автоматичного розкладки:

Я віддаю перевагу:

UIView *parentView, *childView;
[childView setFrame:({
    CGRect frame = childView.frame;

    frame.origin.x = (parentView.frame.size.width - frame.size.width) / 2.0;
    frame.origin.y = (parentView.frame.size.height - frame.size.height) / 2.0;

    CGRectIntegral(frame);
})];

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

1
Якщо я не помиляюся, child.frame = CGRectIntegral (child.frame); - це елегантний різновид загальнодоступного / використання в будь-якому місці проблеми, описаного BL.
Fattie

1
@JoeBlow: Дякую за голову вгору Раніше я любив округлення, але в стилі блоків це більш елегантно використовуватиCGRectIntegral
Cemal Eker

Чи можете ви пояснити синтаксис, який ви використовуєте для встановлення кадру, я його раніше не бачив. Чи завжди це останнє твердження в "закритті", яке призначається власністю? І де його можна знайти в документах Apple?
Йоганнес

Msgstr "" "Якщо ви використовуєте лише методи авторозміщення рівня UIKit:" призводить до помилок.
Jonny

13

Найпростіший спосіб:

child.center = parent.center

Що я маю на увазі, ви повинні додати більше пояснень / описів того, як це працює.
Тушар

Шукав багато відповідей такого типу, цей простий зробив для мене трюк. Дякую.
gbossa

9

введіть тут опис зображення

Встановіть цю автоматичну маску для внутрішнього перегляду.


1
При автоматичному розкладі немає вікна автоматичного розміщення.
Аллен

@Аллен, якщо ви хочете використовувати автоматичне розміщення, вам потрібно вимкнути автоматичний розклад.
Mayank Jain

8

З IOS9 ви можете використовувати API прив’язки макета.

Код виглядатиме так:

childview.centerXAnchor.constraintEqualToAnchor(parentView.centerXAnchor).active = true
childview.centerYAnchor.constraintEqualToAnchor(parentView.centerYAnchor).active = true

Перевага цього над CGPointMakeчи в CGRectтому, що за допомогою цих методів ви встановлюєте центр погляду на постійне, але за допомогою цієї методики ви встановлюєте взаємозв'язок між двома поглядами, які будуть тривати назавжди, незалежно від parentviewзмін.

Будьте впевнені, перш ніж це зробити:

        self.view.addSubview(parentView)
        self.view.addSubView(chidview)

і встановити значення translatesAutoresizingMaskIntoConstraintsдля кожного перегляду на помилкове.

Це не дозволить перешкоджати збоїв і автоматичної розстановки.


8

Можна використовувати

yourView.center = CGPointMake(CGRectGetMidX(superview.bounds), CGRectGetMidY(superview.bounds))

І в Swift 3.0

yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)

1
Другий приклад коду прекрасно працює у швидкому 4. ВЕЛИКИЙ 👍🏻!
iGhost

ТАК! Дякую, нарешті. Я не знав про це midX / midY річ. Perfecto.
Дейв Y

5

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

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];

Це буде центрувати подання по відношенню до надзвичайного вигляду. У наведеному вище випадку він працює, оскільки походження знаходиться при (0, 0).
Абдуррахман Мубін Алі

3

Ще одне рішення з використанням PureLayoutautoCenterInSuperview .

// ...
UIView *innerView = [UIView newAutoLayoutView];
innerView.backgroundColor = [UIColor greenColor];
[innerView autoSetDimensionsToSize:CGSizeMake(100, 30)];

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Ось як це виглядає:

Центр з PureLayout



1

Я б використав:

child.center = CGPointMake(parent.bounds.height / 2, parent.bounds.width / 2)

Це просто, коротко і мило. Якщо ви використовуєте відповідь @ Hejazi вище та parent.centerвстановлено інше, ніж (0,0)ваш підвід, не буде зосереджено!


0
func callAlertView() {

    UIView.animate(withDuration: 0, animations: {
        let H = self.view.frame.height * 0.4
        let W = self.view.frame.width * 0.9
        let X = self.view.bounds.midX - (W/2)
        let Y = self.view.bounds.midY - (H/2)
        self.alertView.frame = CGRect(x:X, y: Y, width: W, height: H)
        self.alertView.layer.borderWidth = 1
        self.alertView.layer.borderColor = UIColor.red.cgColor
        self.alertView.layer.cornerRadius = 16
        self.alertView.layer.masksToBounds = true
        self.view.addSubview(self.alertView)

    })


}// calculation works adjust H and W according to your requirement
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.