Cómo centrar una subvista de UIView

128

Tengo un UIViewam interior UIViewy quiero que el interior UIViewesté siempre centrado dentro del exterior, sin que tenga que cambiar el ancho y la altura.

He configurado los puntales y los resortes para que esté en la parte superior / izquierda / derecha / inferior sin configurar el cambio de tamaño. Pero todavía no se centra. ¿Alguna idea?

xonegirlz
fuente
2
La respuesta aceptada es incorrecta y se bloqueará. La respuesta de Hejazi funciona muy bien.
Fattie

Respuestas:

209

C objetivo

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)
cerdo feliz
fuente
51
Debe usar el boundsy no el frame, ya que el frameno está definido si la vista tiene un transform.
omz
1
En realidad, no hará una diferencia en este caso, ya que solo sizese está utilizando.
Peter DeWeese
1
Eso no importa, toda la framepropiedad está indefinida si la vista tiene una transformtransformación que no es la identidad; lea la documentación sobre la propiedad del marco de UIView .
omz
66
Lamentablemente, esta respuesta es realmente incorrecta . Simplemente use la respuesta correcta de Heja.
Fattie
@Fattie, ¿qué está exactamente mal aquí? Lo usé para centrar un ImageView dentro de una vista y está funcionando.
jreft56
284

Puedes hacer esto y siempre funcionará:

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

Y para Swift:

child.center = parent.convert(parent.center, from:parent.superview)
Hejazi
fuente
1
y no olvide después, child.frame = CGRectIntegral (child.frame);
Fattie
8
Uno: esto solo funciona si no ha cambiado el centro / ubicación de su vista principal. Segundo: si está utilizando este método, no hay necesidad de convertir el punto (ya está en el formato correcto), simplemente use child.center = parent.center. Usaría `child.center = CGPointMake (parent.bounds.height / 2, parent.bounds.width / 2) '. Esto siempre tendrá su subvista centrada independientemente de lo que esté configurado su centro de vista principal.
Nombre antiguo
1
Tampoco es útil si la vista aún no se ha agregado a la jerarquía de vistas (como al iniciar el objeto)
Victor Jalencas
1
@Hejazi Sería bueno agregar una respuesta rápida también;)
Milad Faridnia
1
@Soumen No, hay una diferencia. UIView.boundses relativo a la vista en sí (y, por bounds.originlo tanto, es inicialmente cero), mientras que UIView.centerse especifica en el sistema de coordenadas de la supervista .
Hejazi
41

Antes de comenzar, recordemos que el punto de origen es la esquina superior izquierda CGPointde una vista. Una cosa importante para entender sobre las opiniones y los padres.

Echemos un vistazo a este código simple, un controlador de vista que agrega a su vista un cuadrado negro:

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

}

Esto creará esta vista: el origen y centro del rectángulo negro se ajusta a las mismas coordenadas que su padre

ingrese la descripción de la imagen aquí

Ahora intentemos agregar subView a otro SubSubView y darle a subSubview el mismo origen que subView, pero haga que subSubView sea una vista secundaria de subView

Agregaremos 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)

Y este es el resultado:

ingrese la descripción de la imagen aquí

Debido a esta línea:

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

Esperas que el origen del rectángulo púrpura sea el mismo que el padre (el rectángulo negro) pero se encuentra debajo de él, y ¿por qué es eso? Debido a que cuando agrega una vista a otra vista, el "mundo" del marco subView ahora es su RECTÁNGULO CONDUCIDO padre, si tiene una vista de que su origen en la pantalla principal está en las coordenadas (15,15) para todas sus vistas secundarias, el la esquina superior izquierda será (0,0)

Es por eso que siempre debe referirse a un padre por su rectángulo encuadernado, que es el "mundo" de sus subVistas, arreglemos esta línea para:

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

Y vea la magia, la subvista secundaria ahora se encuentra exactamente en su origen principal:

ingrese la descripción de la imagen aquí

Entonces, te gusta "ok, solo quería centrar mi punto de vista por el de mis padres, ¿cuál es el problema?" bueno, no es gran cosa, solo necesitas "traducir" el punto central principal que se toma de su marco al centro de límites de los padres haciendo esto:

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

En realidad le estás diciendo "toma el centro de visualización de los padres y conviértelo en el mundo subSubView".

Y obtendrás este resultado:

ingrese la descripción de la imagen aquí

Daniel Krom
fuente
¿Dónde se colocará la línea 'subSubView.center = subView.convertPoint (subView.center, fromView: subSubView)'?
Thamarai T
26

Yo usaría:

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

Me gusta usar las CGRectopciones ...

SWIFT 3:

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

1. Si tiene habilitada la distribución automática:

  • Sugerencia: para centrar una vista en otra vista con autolayout, puede usar el mismo código para dos vistas que compartan al menos una vista principal.

En primer lugar, deshabilitar las vistas secundarias de autoresizing

UIView *view1, *view2;
[childview setTranslatesAutoresizingMaskIntoConstraints:NO];
  1. Si eres UIView + Autolayout o Purelayout :

    [view1 autoAlignAxis:ALAxisHorizontal toSameAxisOfView:view2];
    [view1 autoAlignAxis:ALAxisVertical toSameAxisOfView:view2];
  2. Si está utilizando solo métodos de distribución automática de nivel 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. Sin autolayout:

Yo prefiero:

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
fuente
66
Cabe señalar que, a diferencia de la respuesta aceptada, esta solución se alineará limpiamente en los límites de píxeles y evitará que la vista se vea borrosa para ciertos anchos.
Brad Larson
1
Si no me equivoco, child.frame = CGRectIntegral (child.frame); es una solución elegante para el problema que BL describe.
Fattie
1
@ JoeBlow: Gracias por el aviso. Solía amor redondeo pero con estilo de bloque es más elegante de utilizarCGRectIntegral
Cemal Eker
¿Podría explicar la sintaxis que utiliza para establecer el marco? No lo he visto antes. ¿Es siempre la última declaración en el "cierre" que se asigna a la propiedad? ¿Y dónde puedo encontrarlo en los documentos de Apple?
Johannes
"Si está utilizando solo métodos de distribución automática de nivel UIKit:" produce errores.
Jonny
13

La forma más fácil:

child.center = parent.center
juancazalla
fuente
Lo que quiero decir es que deberías agregar más explicaciones / descripciones de cómo funciona
Tushar
Busqué muchas respuestas de este tipo, esta simple me sirvió. Gracias.
gbossa
9

ingrese la descripción de la imagen aquí

Establezca esta máscara de autoresizing a su vista interna.

Mayank Jain
fuente
1
Con la distribución automática, no hay una ventana de tamaño automático.
Allen
@Allen tiene que deshabilitar la distribución automática si desea utilizar el tamaño automático.
Mayank Jain
8

Con IOS9 puede usar la API de anclaje de diseño.

El código se vería así:

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

La ventaja de este sobre CGPointMake, o CGRectes que con esos métodos se está ajustando el centro de la vista a una constante, pero con esta técnica está estableciendo una relación entre los dos puntos de vista que ha de tener, no importa cómo los parentviewcambios.

Solo asegúrate antes de hacer esto:

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

y para configurar el translatesAutoresizingMaskIntoConstraints para cada vista en falso.

Esto evitará que se bloquee y que AutoLayout interfiera.

Roymunson
fuente
8

Puedes usar

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

Y en Swift 3.0

yourView.center = CGPoint(x: superview.bounds.midX, y: superview.bounds.midY)
Sayali Shinde
fuente
1
El segundo ejemplo de código funciona perfectamente en swift 4. ¡GRAN 👍🏻!
iGhost
¡SI! Gracias por fin. No sabía sobre esa cosa midX / midY. Perfecto
Dave Y
5

Usar el mismo centro en la vista y subvista es la forma más sencilla de hacerlo. Puedes hacer algo como esto

UIView *innerView = ....;
innerView.view.center = self.view.center;
[self.view addSubView:innerView];
codeFood
fuente
Esto centrará la vista secundaria con respecto a la vista súper vista. En el caso anterior, funciona porque el origen está en (0, 0).
Abdurrahman Mubeen Ali
3

Otra solución con PureLayout usando autoCenterInSuperview.

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

[outerview addSubview:innerView];

[innerView autoCenterInSuperview];

Así es como se ve:

Centro con PureLayout

H6.
fuente
2

En c # o Xamarin.ios, podemos usar así

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

Anisetti Nagendra
fuente
1

Yo usaría:

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

Esto es simple, corto y dulce. ¡Si usa la respuesta de @Hejazi anterior y parent.centerestá configurada para otra cosa que no sea (0,0)su subvista, no estará centrada!

Viejo nombre
fuente
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
fuente