Как центрировать подвид UIView

128

У меня есть UIViewвнутренний UIViewметр, и я хочу, чтобы внутренний UIViewвсегда был по центру внутри внешнего, без необходимости изменять ширину и высоту.

Я установил распорки и пружины так, чтобы они находились сверху / слева / справа / снизу, без изменения размера. Но все равно не в центре. Любая идея?

xonegirlz
источник
2
Принятый ответ неверен и приведет к сбою. Ответ Хиджази отлично работает.
Fattie

Ответы:

210

Objective-C

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
Вы должны использовать, boundsа не frame, поскольку frameне определено, если в представлении есть transform.
omz
1
На самом деле в этом случае ничего не изменится, так как только sizeиспользуется.
Peter DeWeese
1
Это не имеет значения, все frameсвойство не определено, если представление имеет transformне преобразование идентичности; прочтите документацию по свойству фрейма UIView .
omz
6
К сожалению, этот ответ на самом деле неверен . Просто используйте правильный ответ Хеджи.
Fattie
@Fattie, что здесь не так? Я использовал его для центрирования ImageView внутри View, и он работает.
jreft56
284

Вы можете это сделать, и это всегда будет работать:

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

И для Swift:

child.center = parent.convert(parent.center, from:parent.superview)
Hejazi
источник
1
и не забывайте потом, child.frame = CGRectIntegral (child.frame);
Fattie
8
Первый: это работает только в том случае, если вы не изменили центр / расположение родительского представления. Во-вторых: если вы используете этот метод, нет необходимости преобразовывать точку (она уже в правильном формате), просто используйте child.center = parent.center. Я бы использовал `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. Это всегда будет иметь ваше подчиненное представление по центру, независимо от того, на что настроен ваш родительский центр просмотра.
Старое имя
1
Это также бесполезно, если представление еще не было добавлено в иерархию представлений (например, при инициализации объекта)
Виктор Яленкас
1
@Hejazi Было бы неплохо добавить и быстрый ответ;)
Милад Фаридния
1
@Soumen Нет, разница есть. UIView.boundsотносительно самого представления (и поэтому bounds.originизначально равен нулю), а UIView.centerзадается в системе координат супервизора .
Hejazi
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 "world" теперь становится его родительским BOUND RECTANGLE, если у вас есть представление, что его начало на главном экране находится в координатах (15,15) для всех его подвидов, верхний левый угол будет (0,0)

Вот почему вам нужно всегда ссылаться на родительский элемент через связанный прямоугольник, который является «миром» его подвидов, давайте исправим эту строку:

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

И посмотрите на волшебство, subSubview теперь находится точно в своем родительском источнике:

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

Итак, вам нравится: «Хорошо, я только хотел сосредоточить свое мнение на взгляде родителей, в чем дело?» ну, в этом нет ничего страшного, вам просто нужно «перевести» родительскую центральную точку, которая берется из этого кадра, в родительский центр границ, выполнив следующие действия:

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

Вы фактически говорите ему: «Возьми родительский центр просмотра и преобразуй его в мир subSubView».

И вы получите такой результат:

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

Даниэль Кром
источник
Куда поместить строку subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)?
Thamarai 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);
theprojectabot
источник
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
Джемаль Экер
Не могли бы вы объяснить синтаксис, который вы используете для установки фрейма, я его раньше не видел. Всегда ли последний оператор в «закрытии» присваивается свойству? А где его в документации Apple найти?
Johannes
«Если вы используете только методы автоматического размещения уровня UIKit:» приводит к ошибкам.
Джонни
13

Самый простой способ:

child.center = parent.center
juancazalla
источник
Я имею в виду, что вам следует добавить дополнительные объяснения / описания того, как это работает.
Тушар
Я искал много ответов такого типа, этот простой помог мне. Спасибо.
gbossa
9

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

Установите эту маску с автоизменением размеров на свой внутренний вид.

Mayank Jain
источник
1
При автоматическом раскладке нет окна автоматического изменения размера.
Аллен
@Allen, вы должны отключить автоопределение, если хотите использовать автоизменение размеров.
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для каждого представления значение false.

Это предотвратит сбой и вмешательство AutoLayout.

Roymunson
источник
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
Второй пример кода отлично работает в Swift 4. ОТЛИЧНО!
iGhost
ДА! Наконец-то спасибо. Не знал об этой вещи midX / midY. Perfecto.
Дэйв Y
5

Самый простой способ сделать это - использовать один и тот же центр в представлении и дополнительном представлении. Вы можете сделать что-то вроде этого,

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];
codeFood
источник
При этом вспомогательный вид будет центрирован относительно основного вида. В приведенном выше случае он работает, потому что начало координат находится в (0, 0).
Абдуррахман Мубин Али
3

Другое решение с использованием PureLayoutautoCenterInSuperview .

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Вот как это выглядит:

Центрировать с PureLayout

H6.
источник
2

В C # или Xamarin.ios мы можем использовать вот так

imageView.Center = новый CGPoint (tempView.Frame.Size.Width / 2, tempView.Frame.Size.Height / 2);

Анисетти Нагендра
источник
1

Я хотел бы использовать:

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

Это просто, коротко и мило. Если вы используете ответ @ Hejazi выше и для parent.centerнего установлено что-либо, кроме (0,0)вашего subview, не будет центрировано!

Старое имя
источник
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
Сидд Редкар
источник