Como centralizar uma subvisualização do UIView

128

Eu tenho um UIViewdentro de um UIViewme quero que o interior UIViewesteja sempre centrado dentro do exterior, sem que seja necessário redimensionar a largura e a altura.

Eu configurei os suportes e molas para que fiquem em cima / esquerda / direita / baixo sem definir o redimensionamento. Mas ainda não está centralizado. Qualquer ideia?

xonegirlz
fonte
2
A resposta aceita está errada e falhará. A resposta de Hejazi funciona muito bem.
Fattie

Respostas:

209

Objetivo-C

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

Rápido

yourSubView.center = CGPoint(x: yourView.frame.size.width  / 2,
                             y: yourView.frame.size.height / 2)
porco feliz
fonte
51
Você deve usar o boundse não o frame, pois o frameé indefinido se a visualização tiver um transform.
omz 29/06/12
1
Na verdade, não fará diferença nesse caso, pois apenas sizeestá sendo usado.
Peter DeWeese
1
Isso não importa, a framepropriedade inteira é indefinida se a visualização tiver uma transformtransformação que não seja a identidade; leia a documentação na propriedade de quadro do UIView .
omz 29/06/12
6
Infelizmente, esta resposta está realmente errada . Basta usar a resposta correta de Heja.
Fattie
@Fattie, o que está exatamente errado aqui? Usei-o para centralizar um ImageView em um View e ele está funcionando.
precisa saber é o seguinte
284

Você pode fazer isso e sempre funcionará:

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

E para Swift:

child.center = parent.convert(parent.center, from:parent.superview)
Hejazi
fonte
1
e não esqueça depois, child.frame = CGRectIntegral (child.frame);
Fattie
8
Um: Isso só funciona se você não tiver alterado o centro / local da sua visualização principal. Segundo: se você estiver usando esse método, não há necessidade de converter o ponto (ele já está no formato correto), apenas use child.center = parent.center. Eu usaria `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. Isso sempre terá sua subvisão centralizada, independentemente do seu centro de visualização principal.
Old Name
1
Também não é útil se a visualização ainda não foi adicionada à hierarquia da visualização (como quando o objeto foi inserido) #
Victor Jalencas
1
@Hejazi Seria bom para adicionar resposta rápida também;)
Milad Faridnia
1
@Soumen Não, há uma diferença. UIView.boundsé relativo à própria visão (e, portanto, bounds.originé inicialmente zero), enquanto UIView.centeré especificado no sistema de coordenadas da super visão .
precisa
41

Antes de começarmos, lembremos que o ponto de origem é o canto superior esquerdo CGPointde uma visualização. Uma coisa importante a entender sobre pontos de vista e pais.

Vamos dar uma olhada neste código simples, um controlador de exibição que adiciona um quadrado preto:

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()
    }

}

Isso criará esta visualização: a origem e o centro do retângulo preto se encaixam nas mesmas coordenadas do pai.

insira a descrição da imagem aqui

Agora vamos tentar adicionar subView outro SubSubView e dar ao subSubview a mesma origem do subView, mas tornar o subSubView uma visão filho do subView

Adicionaremos este código:

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

E este é o resultado:

insira a descrição da imagem aqui

Devido a esta linha:

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

Você espera que a origem do retângulo roxo seja a mesma de seu pai (o retângulo preto), mas fica abaixo dele, e por que isso? Como quando você adiciona uma visualização a outra, o quadro "mundo" do subView agora é o pai BOUND RECTANGLE, se você tem uma visão de que sua origem na tela principal está nas cordas (15,15) para todas as sub-vistas, o o canto superior esquerdo será (0,0)

É por isso que você sempre precisa se referir a um pai pelo retângulo vinculado, que é o "mundo" de seus subViews, vamos corrigir esta linha para:

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

E veja a mágica, o subSubview agora está localizado exatamente em sua origem pai:

insira a descrição da imagem aqui

Então, você gosta de "ok, eu só queria centralizar minha visão pela visão de meus pais, qual é o problema?" bem, não é grande coisa, você só precisa "traduzir" o ponto central pai, que é retirado de seu quadro para o centro de limites dos pais, fazendo o seguinte:

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

Na verdade, você está dizendo a ele "pegue o centro de visualização dos pais e converta-o no mundo subSubView".

E você obterá este resultado:

insira a descrição da imagem aqui

Daniel Krom
fonte
Para onde a linha 'subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)' será colocada?
Thamarai T
26

Eu usaria:

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

Eu gosto de usar as CGRectopções ...

SWIFT 3:

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

1. Se você tiver o pagamento automático ativado:

  • Dica: para centralizar uma visualização em outra visualização com o layout automático, você pode usar o mesmo código para quaisquer duas visualizações que compartilhem pelo menos uma visualização pai.

Antes de tudo, desabilite o dimensionamento automático das visualizações filho

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Se você é UIView + Autolayout ou Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Se você estiver usando apenas métodos de pagamento automático no nível do 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. Sem autolayout:

Eu prefiro:

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);
})];
Cemal Eker
fonte
6
Deve-se observar que, diferentemente da resposta aceita, esta solução alinhar-se-á perfeitamente nos limites de pixel e evitará o embaçamento da visualização em determinadas larguras.
Brad Larson
1
Se não me engano, child.frame = CGRectIntegral (child.frame); é um tipo elegante de solução prática para o problema que o BL descreve.
Fattie
1
@ JoeBlow: Obrigado pela atenção. Eu costumava amor arredondamento mas com estilo do bloco é mais elegante de usarCGRectIntegral
Cemal Eker
Você poderia explicar a sintaxe usada para definir o quadro, eu nunca vi isso antes. É sempre a última declaração no "fechamento" atribuída à propriedade? E onde posso encontrá-lo nos documentos da Apple?
Johannes
"Se você estiver usando apenas métodos de pagamento automático no nível do UIKit:", ocorrerão erros.
Jonny
13

A maneira mais fácil:

child.center = parent.center
juancazalla
fonte
O que quero dizer é que você deve adicionar mais explicações / descrições de como isso funciona.
Tushar
Pesquisei muitas respostas desse tipo, essa simples fez o truque para mim. Obrigado.
gbossa 22/07
9

insira a descrição da imagem aqui

Defina esta máscara de redimensionamento automático para sua visão interna.

Mayank Jain
fonte
1
Com o layout automático, não há janela de dimensionamento automático.
Allen
@ Allen, você precisa desativar o autolayout se quiser usar o redimensionamento automático.
Mayank Jain
8

Com o IOS9, você pode usar a API de âncora do layout.

O código ficaria assim:

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

A vantagem deste sobre CGPointMakeou CGRecté que, com esses métodos você está definindo o centro da vista a uma constante, mas com esta técnica você está definindo uma relação entre os dois pontos de vista que irá realizar para sempre, não importa como a parentviewmudanças.

Apenas certifique-se antes de fazer isso:

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

e para definir translatesAutoresizingMaskIntoConstraints de cada visualização como false.

Isso evitará falhas e o AutoLayout interferirá.

Roymunson
fonte
8

Você pode usar

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

E no Swift 3.0

yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)
Sayali Shinde
fonte
1
O segundo exemplo de código funciona perfeitamente no swift 4. GREAT 👍🏻!
iGhost 10/10/19
SIM! Obrigado, finalmente. Não sabia sobre essa coisa midX / midY. Perfecto.
Dave Y
5

Usar o mesmo centro na visualização e na subvisualização é a maneira mais simples de fazê-lo. Você pode fazer algo assim,

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];
codeFood
fonte
Isso centralizará a subvisualização em relação à super visão de visualização. No caso acima, está funcionando porque a origem está em (0, 0).
Abdurrahman Mubeen Ali 14/09/15
3

Outra solução com PureLayout usando autoCenterInSuperview.

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

É assim que se parece:

Centro com PureLayout

H6
fonte
2

Em c # ou Xamarin.ios, podemos usar assim

imageView.Center = novo CGPoint (tempView.Frame.Size.Width / 2, tempView.Frame.Size.Height / 2);

Anisetti Nagendra
fonte
1

Eu usaria:

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

Isso é simples, curto e doce. Se você usar a resposta de @ Hejazi acima e parent.centerestiver definido como algo diferente de (0,0)sua subvisão, não será centralizado!

Antigo nome
fonte
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
Sidd Redkar
fonte