El diseño automático me dificulta la vida. En teoría, iba a ser realmente útil cuando me cambiara, pero parece que lucho todo el tiempo.
Hice un proyecto de demostración para tratar de encontrar ayuda. ¿Alguien sabe cómo hacer que los espacios entre las vistas aumenten o disminuyan de manera uniforme cada vez que se cambie el tamaño de la vista?
Aquí hay tres etiquetas (manualmente espaciadas verticalmente, incluso):
Lo que quiero es que cambien el tamaño de su espacio (no el tamaño de la vista) de manera uniforme cuando gire. Por defecto, las vistas superior e inferior se desplazan hacia el centro:
Respuestas:
Entonces mi enfoque le permite hacer esto en el generador de interfaces. Lo que debe hacer es crear 'vistas espaciadoras' que haya configurado para igualar las alturas por igual. Luego agregue restricciones superiores e inferiores a las etiquetas (vea la captura de pantalla).
Más específicamente, tengo una restricción superior en 'Vista espaciadora 1' para supervisar con una restricción de altura de menor prioridad que 1000 y con Altura igual a todas las otras 'vistas espaciadoras'. 'Spacer View 4' tiene una restricción de espacio inferior para la supervista. Cada etiqueta tiene sus respectivas restricciones superior e inferior a sus "vistas espaciadoras" más cercanas.
Nota: Asegúrese de NO tener restricciones adicionales de espacio superior / inferior en sus etiquetas para supervisar; solo los de las 'vistas espaciales'. Esto será satisfactorio ya que las restricciones superior e inferior están en 'Space View 1' y 'Spacer View 4' respectivamente.
Duh 1: Dupliqué mi vista y simplemente la puse en modo horizontal para que pudieras ver que funcionaba.
Duh 2: Las 'vistas espaciadoras' podrían haber sido transparentes.
Duh 3: este enfoque podría aplicarse horizontalmente.
fuente
¡MIRA, SIN ESPACIADORES!
Según las sugerencias en la sección de comentarios de mi respuesta original, especialmente las sugerencias útiles de @ Rivera, he simplificado mi respuesta original.
Estoy usando gifs para ilustrar cuán simple es esto. Espero que encuentres los gifs útiles. En caso de que tenga un problema con los gifs, he incluido la respuesta anterior a continuación con capturas de pantalla simples.
Instrucciones:
1) Agregue sus botones o etiquetas. Estoy usando 3 botones.
2) Agregue una restricción centro x de cada botón a la supervista:
3) Agregue una restricción de cada botón a la restricción de diseño inferior:
4) Ajuste la restricción agregada en el # 3 anterior de la siguiente manera:
a) seleccione la restricción, b) elimine la constante (establecida en 0), c) cambie el multiplicador de la siguiente manera: tome el número de botones + 1, y comience en la parte superior, configure el multiplicador como buttonCountPlus1: 1 , y luego buttonCountPlus1 : 2 , y finalmente buttonCountPlus1: 3 . (Explico de dónde obtuve esta fórmula en la respuesta anterior a continuación, si está interesado).
5) ¡ Aquí hay una demo en ejecución!
Nota: Si sus botones tienen alturas más grandes, deberá compensar esto en el valor constante ya que la restricción es desde la parte inferior del botón.
Vieja respuesta
A pesar de lo que dicen los documentos de Apple y el excelente libro de Erica Sadun ( Auto Layout Demystified ), es posible espaciar uniformemente las vistas sin espaciadores. Esto es muy simple de hacer en IB y en código para cualquier número de elementos que desee espaciar de manera uniforme. Todo lo que necesita es una fórmula matemática llamada "fórmula de sección". Es más sencillo de hacer que de explicar. Haré lo mejor que pueda al demostrarlo en IB, pero es igual de fácil hacerlo en código.
En el ejemplo en cuestión, usted
1) comience configurando cada etiqueta para que tenga una restricción central. Esto es muy sencillo de hacer. Simplemente controle el arrastre desde cada etiqueta hasta la parte inferior.
2) Mantenga presionada la tecla Mayús, ya que también podría agregar la otra restricción que vamos a utilizar, a saber, la "guía de diseño de espacio inferior a inferior".
3) Seleccione la "guía de diseño de espacio inferior a inferior" y "centrar horizontalmente en el contenedor". Haga esto para las 3 etiquetas.
Básicamente, si tomamos la etiqueta cuya coordenada deseamos determinar y la dividimos por el número total de etiquetas más 1, entonces tenemos un número que podemos agregar a IB para obtener la ubicación dinámica. Estoy simplificando la fórmula, pero podría usarla para establecer el espaciado horizontal o tanto vertical como horizontal al mismo tiempo. ¡Es súper poderoso!
Aquí están nuestros multiplicadores.
Etiqueta1 = 1/4 = .25,
Etiqueta2 = 2/4 = .5,
Etiqueta3 = 3/4 = .75
(Editar: @Rivera comentó que simplemente puede usar las proporciones directamente en el campo multiplicador, ¡y xCode con hacer los cálculos!)
4) Entonces, seleccionemos Label1 y seleccione la restricción inferior. Me gusta esto:
5) Seleccione el "Segundo elemento" en el Inspector de atributos.
6) En el menú desplegable, seleccione "Invertir primer y segundo elemento".
7) Ponga a cero la constante y el valor de wC hAny. (Puede agregar un desplazamiento aquí si lo necesita).
8) Esta es la parte crítica: en el campo multiplicador agregue nuestro primer multiplicador 0.25.
9) Mientras está en él, configure el "primer elemento" superior en "CenterY" ya que queremos centrarlo en el centro y de la etiqueta. Así es como debería verse todo eso.
10) Repita este proceso para cada etiqueta y conecte el multiplicador relevante: 0.5 para Label2 y 0.75 para Label3. ¡Aquí está el producto final en todas las orientaciones con todos los dispositivos compactos! Súper simple He estado buscando muchas soluciones que involucran resmas de código y espaciadores. Esta es de lejos la mejor solución que he visto sobre el tema.
Actualización: @kraftydevil agrega que la guía de diseño inferior solo aparece en los guiones gráficos, no en xibs. Use 'Espacio inferior al contenedor' en xibs. ¡Buena atrapada!
fuente
Solución muy rápida de Interface Builder:
Para que cualquier número de vistas esté espaciado uniformemente dentro de una supervista, simplemente asigne a cada una una restricción "Alinear centro X a supervista" para diseño horizontal, o "Alinear centro Y supervista" para diseño vertical, y configure el multiplicador para que sea
N:p
( NOTA: algunos he tenido mejor suerte conp:N
- ver más abajo )dónde
N = total number of views
yp = position of the view including spaces
La primera posición es 1, luego un espacio, haciendo la siguiente posición 3, por lo que p se convierte en una serie [1,3,5,7,9, ...]. Funciona para cualquier cantidad de vistas.
Entonces, si tiene 3 vistas para espaciar, se ve así:
EDITAR Nota: La elección de
N:p
op:N
depende del orden de relación de su restricción de alineación. Si "Primer elemento" es Superview.Center, puede usarlop:N
, mientras que si Superview.Center es "Segundo elemento", puede usarloN:p
. En caso de duda, pruebe ambos ... :-)fuente
A partir de iOS 9, Apple ha hecho esto muy fácil con el (tan esperado)
UIStackView
. Simplemente seleccione las vistas que desea contener en el Creador de interfaces y elija Editor -> Incrustar en -> Vista de pila. Establezca las restricciones de ancho / alto / margen apropiadas para la vista de pila, y asegúrese de establecer la propiedad Distribución en 'Espaciado igual':Por supuesto, si necesita admitir iOS 8 o inferior, tendrá que elegir una de las otras opciones.
fuente
He estado en una montaña rusa de amar autolayout y odiarlo. La clave para amarlo parece ser aceptar lo siguiente:
Dicho esto, lo que está intentando no es sencillo y sería difícil de lograr en el generador de interfaces. Es bastante simple de hacer en código. Este código, en
viewDidLoad
, crea y coloca tres etiquetas de cómo las solicita:Como digo, este código se simplifica mucho con un par de métodos de categoría
UIView
, pero para mayor claridad, lo he hecho hasta aquí.La categoría está aquí para aquellos interesados, y tiene un método para espaciar uniformemente una variedad de vistas a lo largo de un eje particular.
fuente
La mayoría de estas soluciones dependen de que haya un número impar de elementos para que pueda tomar el elemento central y centrarlo. ¿Qué sucede si tiene un número par de elementos que aún desea distribuir de manera uniforme? Aquí hay una solución más general. Esta categoría distribuirá uniformemente cualquier número de elementos a lo largo del eje vertical u horizontal.
Ejemplo de uso para distribuir verticalmente 4 etiquetas dentro de su supervista:
NSLayoutConstraint + EvenDistribution.h
NSLayoutConstraint + EvenDistribution.m
fuente
La forma correcta y más fácil es usar Stack Views.
fuente
Echa un vistazo a la biblioteca de código abierto PureLayout . Ofrece algunos métodos API para distribuir vistas, incluidas variantes en las que el espacio entre cada vista es fijo (el tamaño de la vista varía según sea necesario) y donde el tamaño de cada vista es fijo (el espacio entre las vistas varía según sea necesario). Tenga en cuenta que todo esto se logra sin el uso de "vistas espaciadoras".
De NSArray + PureLayout.h :
Como todo es de código abierto, si está interesado en ver cómo se logra esto sin vistas espaciadoras, simplemente eche un vistazo a la implementación. (Depende de apalancamiento tanto el
constant
ymultiplier
para las restricciones.)fuente
Tengo un problema similar y descubrí esta publicación. Sin embargo, ninguna de las respuestas proporcionadas actualmente resuelve el problema de la manera que desea. No hacen el espaciado por igual, sino que distribuyen el centro de las etiquetas por igual. Es importante entender que esto no es lo mismo. He construido un pequeño diagrama para ilustrar esto.
Hay 3 vistas, todas de 20pt de altura. El uso de cualquiera de los métodos sugeridos distribuye equitativamente los centros de las vistas y le brinda el diseño ilustrado. Observe que el centro y de las vistas está espaciado por igual. Sin embargo, el espacio entre la supervista y la vista superior es de 15 puntos, mientras que el espacio entre las subvistas es de solo 5 puntos. Para tener las vistas espaciadas por igual, ambas deben ser de 10 puntos, es decir, todas las flechas azules deben tener 10 puntos.
Sin embargo, todavía no he encontrado una buena solución genérica. Actualmente, mi mejor idea es insertar "vistas de espaciado" entre las subvistas y configurar las alturas de las vistas de espaciado para que sean iguales.
fuente
Pude resolver esto completamente en IB:
Entonces, si tiene tres etiquetas, establezca los multiplicadores para cada una de esas restricciones en 0.1666667, 0.5, 0.833333.
fuente
Encontré un método perfecto y simple. El diseño automático no le permite cambiar el tamaño de los espacios por igual, pero sí le permite cambiar el tamaño de las vistas por igual. Simplemente coloque algunas vistas invisibles entre sus campos y dígale al diseño automático que mantenga el mismo tamaño. Funciona perfectamente!
Una cosa de nota sin embargo; cuando reduje el tamaño en el diseñador de la interfaz, a veces se confundía y dejaba una etiqueta donde estaba, y tenía un conflicto si el tamaño se cambiaba en una cantidad extraña. De lo contrario, funcionó perfectamente.
editar: descubrí que el conflicto se convirtió en un problema. Debido a eso, tomé una de las restricciones de espacio, la eliminé y la reemplacé por dos restricciones, una mayor que o igual y una menor que o igual. Ambos tenían el mismo tamaño y tenían una prioridad mucho menor que las otras restricciones. El resultado no fue más conflicto.
fuente
Sobre la base de la respuesta de Ben Dolman, esto distribuye las vistas de manera más uniforme (con relleno, etc.):
fuente
consulte https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html que tiene una buena descripción sobre cómo resolver su problema.
fuente
Con etiquetas esto funciona bien al menos:
@"H:|-15-[first(==second)]-[second(==third)]-[third(==first)]-15-|
Si el primero tiene el mismo ancho que el segundo, y el segundo el tercero, y el tercero el primero, entonces todos obtendrán el mismo ancho ... Puede hacerlo tanto horizontalmente (H) como verticalmente (V).
fuente
versión swift 3
fuente
Sé que ha pasado un tiempo desde la primera respuesta, pero me encontré con el mismo problema y quiero compartir mi solución. Para las generaciones venideras ...
Configuré mis puntos de vista en viewDidLoad:
Y luego, en updateViewConstrains, primero elimino todas las restricciones, luego creo el diccionario de vistas y luego calculo el espacio que se utilizará entre las vistas. Después de eso, solo uso el formato de lenguaje visual para establecer las restricciones:
Lo bueno de este método es que tienes que hacer muy pocas matemáticas. No digo que esta sea la solución perfecta, pero trabajo para el diseño que estaba tratando de lograr.
Espero que ayude.
fuente
Aquí hay una solución que centrará verticalmente cualquier número de subvistas, incluso si tienen tamaños únicos. Lo que desea hacer es hacer un contenedor de nivel medio, centrarlo en la supervista, luego colocar todas las subvistas en el contenedor y organizarlas una con respecto a la otra. Pero, de manera crucial, también debe restringirlos a la parte superior e inferior del contenedor, para que el contenedor se pueda dimensionar y centrar correctamente en la supervista. Al calcular la altura correcta a partir de sus subvistas, el contenedor puede centrarse verticalmente.
En este ejemplo,
self
es la supervista en la que está centrando todas las subvistas.fuente
Acabo de resolver mi problema usando la función de multiplicador. No estoy seguro de que funcione para todos los casos, pero para mí funcionó perfectamente. Estoy en Xcode 6.3 FYI.
Lo que terminé haciendo fue:
1) Primero coloque mis botones en una pantalla de 320px de ancho distribuidos de la manera que quería que se viera en un dispositivo de 320px.
2) Luego agregué una restricción de espacio inicial para supervisar todos mis botones.
3) Luego modifiqué las propiedades del espacio inicial para que la constante fuera 0 y el multiplicador sea el desplazamiento x dividido por el ancho de la pantalla (por ejemplo, mi primer botón tenía 8 píxeles desde el borde izquierdo, así que configuré mi multiplicador en 8/320)
4) Entonces, el paso importante aquí es cambiar el segundo elemento en la relación de restricción para que sea la supervista.Trailing en lugar de superview.leading. Esto es clave porque la supervista. El encabezado es 0 y el final en mi caso es 320, por lo que 8/320 es 8 px en un dispositivo de 320px, luego, cuando el ancho de la supervista cambia a 640 o lo que sea, todas las vistas se mueven en una proporción relativa al ancho del tamaño de pantalla de 320px. Las matemáticas aquí son mucho más simples de entender.
fuente
Muchas respuestas no son correctas, pero obtienen muchos recuentos. Aquí solo escribo una solución mediante programación, las tres vistas están alineadas horizontalmente, sin usar vistas espaciadoras , pero solo funciona cuando se conocen los anchos de las etiquetas cuando se usan en el guión gráfico .
fuente
Aquí hay otra respuesta. Estaba respondiendo una pregunta similar y vi un enlace referenciado a esta pregunta. No vi ninguna respuesta similar a la mía. Entonces, pensé en escribirlo aquí.
Y nuevamente, esto se puede hacer con bastante facilidad con iOS9 UIStackViews también.
Tenga en cuenta que es exactamente el mismo enfoque que el anterior. Agrega cuatro vistas de contenedor que se llenan por igual y se agrega una vista a cada vista de pila que está alineada en el centro. Pero, esta versión de UIStackView reduce algo de código y se ve bien.
fuente
Otro enfoque podría ser que las etiquetas superior e inferior tengan restricciones relativas a la vista superior e inferior, respectivamente, y que la vista central tenga restricciones superior e inferior con respecto a la primera y tercera vista, respectivamente.
Tenga en cuenta que tiene más control sobre las restricciones de lo que parece al arrastrar las vistas una cerca de la otra hasta que aparezcan líneas punteadas de guiado; esto indica restricciones entre los dos objetos que se formarán en lugar de entre el objeto y la supervista.
En este caso, desearía alterar las restricciones para que sean "mayores o iguales que" el valor deseado, en lugar de "iguales a" para permitirles cambiar su tamaño. No estoy seguro si esto hará exactamente lo que quieres.
fuente
Manera muy fácil de resolver esto en InterfaceBuilder:
Establezca la etiqueta centrada (etiqueta2) en "Centro horizontal en contenedor" y "Centro vertical en contenedor"
Seleccione la etiqueta centrada y la etiqueta superior (etiqueta1 + etiqueta2) y agregue DOS restricciones para el Espaciado vertical. Uno con mayor o igual que el espacio mínimo. Uno con menos que o igual el espacio máximo.
Lo mismo para la etiqueta centrada y la etiqueta inferior (etiqueta2 + etiqueta3).
Además, también puede agregar dos restricciones a label1: espacio superior a SuperView y dos restricciones a label2: espacio inferior a SuperView.
El resultado será que los 4 espacios cambiarán sus tamaños por igual.
fuente
He hecho una función que podría ayudar. Este ejemplo de uso:
causará esa distribución vertical (lo siento, no tengo la reputación de 10 para incrustar imágenes). Y si cambia el eje y algunos valores de margen:
Obtendrás esa distribución horizontal .
Soy novato en iOS pero voilà!
EvenDistribution.h
EvenDistribution.m
fuente
Sí, puede hacerlo únicamente en el generador de interfaces y sin escribir código; la única advertencia es que está cambiando el tamaño de la etiqueta en lugar de distribuir espacios en blanco. En este caso, alinee X e Y de Label 2 con la supervista para que quede fijo en el centro. Luego establezca el espacio vertical de la etiqueta 1 en la supervista y la etiqueta 2 en el estándar, repita para la etiqueta 3. Después de configurar la etiqueta 2, la forma más fácil de configurar las etiquetas 1 y 3 es cambiar su tamaño hasta que encajen.
Aquí está la pantalla horizontal, tenga en cuenta que el espacio vertical entre las etiquetas 1 y 2 está configurado como estándar:
Y aquí está la versión vertical:
Me doy cuenta de que no están absolutamente 100% igualmente espaciados entre las líneas de base debido a la diferencia entre el espacio estándar entre etiquetas y el espacio estándar para la supervista. Si eso te molesta, establece el tamaño en 0 en lugar de estándar
fuente
Establecí un valor de ancho solo para el primer elemento (> = un ancho) y una distancia mínima entre cada elemento (> = una distancia). Luego uso Ctrl para arrastrar el segundo, tercer ... elemento en el primero para encadenar las dependencias entre los elementos.
fuente
Tarde a la fiesta, pero tengo una solución de trabajo para crear un menú horizontalmente con espaciado. Se puede hacer fácilmente usando
==
NSLayoutConstraintfuente
Android tiene un método para encadenar vistas en su sistema de diseño basado en restricciones que quería imitar. Las búsquedas me trajeron aquí, pero ninguna de las respuestas funcionó. No quería usar StackViews porque tienden a causarme más dolor en el futuro de lo que ahorran por adelantado. Terminé creando una solución que usaba UILayoutGuides colocadas entre las vistas. Controlar su ancho permite diferentes tipos de distribuciones, estilos de cadena en el lenguaje Android. La función acepta un anclaje inicial y final en lugar de una vista principal. Esto permite que la cadena se coloque entre dos vistas arbitrarias en lugar de distribuirse dentro de la vista principal. Utiliza el
UILayoutGuide
que solo está disponible en iOS 9+, pero eso ya no debería ser un problema.fuente
Quería alinear horizontalmente 5 imágenes, así que terminé siguiendo la respuesta de Mete con una pequeña diferencia.
La primera imagen se centrará horizontalmente en un contenedor igual a 0 y un multiplicador de 1: 5:
La segunda imagen se centrará horizontalmente en un contenedor igual a 0 y un multiplicador de 3: 5:
Y así para el resto de las imágenes. Por ejemplo, la quinta (y última) imagen se centrará horizontalmente en un contenedor igual a 0 y un multiplicador de 9: 5:
Como explicó Mete, el orden va 1, 3, 5, 7, 9, etc. Las posiciones siguen la misma lógica: la primera posición es 1, luego el espacio, luego la siguiente posición 3, y así sucesivamente.
fuente
¿Por qué no creas una tableView y haces
isScrollEnabled = false
fuente