ios9 ios-autolayout uistackview

ios9 - ¿Cómo puedo crear UIStackView con espaciado variable entre vistas?



ios-autolayout (4)

A partir de respuesta creé una extensión UIStackView que podría ayudar:

extension UIStackView { func addCustomSpacing(_ spacing: CGFloat, after arrangedSubview: UIView) { if #available(iOS 11.0, *) { self.setCustomSpacing(spacing, after: arrangedSubview) } else { let separatorView = UIView(frame: .zero) separatorView.translatesAutoresizingMaskIntoConstraints = false switch axis { case .horizontal: separatorView.widthAnchor.constraint(equalToConstant: spacing).isActive = true case .vertical: separatorView.heightAnchor.constraint(equalToConstant: spacing).isActive = true } if let index = self.arrangedSubviews.firstIndex(of: arrangedSubview) { insertArrangedSubview(separatorView, at: index + 1) } } } }

Puede usarlo y modificarlo de la forma que desee, por ejemplo, si desea la referencia " separatorView ", puede devolver el UIView:

func addCustomSpacing(_ spacing: CGFloat, after arrangedSubview: UIView) -> UIView?

Tengo un UIStackView horizontal simple con varias UIViews apiladas dentro. Mi objetivo es crear un espaciado variable entre las vistas. Soy consciente de que puedo crear un espacio constante entre las subvistas usando la propiedad "espaciado". Sin embargo, mi objetivo es crear un espacio variable. Tenga en cuenta que, si es posible, me gustaría evitar el uso de vistas invisibles que actúan como espaciadores.

Lo mejor que se me ocurrió fue envolver mis UIViews en un UIStackView separado, y usar layoutMarginsRelativeArrangement = YES para respetar los márgenes de diseño de mi pila interna. Esperaba poder hacer algo similar con cualquier UIView sin recurrir a esta desagradable UIView . Aquí está mi código de muestra:

// Create stack view UIStackView *stackView = [[UIStackView alloc] init]; stackView.translatesAutoresizingMaskIntoConstraints = NO; stackView.axis = UILayoutConstraintAxisHorizontal; stackView.alignment = UIStackViewAlignmentCenter; stackView.layoutMarginsRelativeArrangement = YES; // Create subview UIView *view1 = [[UIView alloc] init]; view1.translatesAutoresizingMaskIntoConstraints = NO; // ... Add Auto Layout constraints for height / width // ... // I was hoping the layoutMargins would be respected, but they are not view1.layoutMargins = UIEdgeInsetsMake(0, 25, 0, 0); // ... Create more subviews // UIView view2 = [[UIView alloc] init]; // ... // Stack the subviews [stackView addArrangedSubview:view1]; [stackView addArrangedSubview:view2];

El resultado es una pila con vistas una al lado de la otra con espaciado:


LRCustomSpacingStackView una biblioteca LRCustomSpacingStackView para admitir el espaciado personalizado UIStackView en iOS 9 y superior.

Simplemente reemplace los métodos incorporados de UIStackView en su código con los métodos de extensión de esta biblioteca y especifique el espaciado configurando la propiedad lr_stackSpacing cualquier subvista:

import LRCustomSpacingStackView stackView.lr_addArrangedSubview(view1) view1.lr_stackSpacing = UIEdgeInsets(top: 20, left: 30, bottom: 10, right: 0)

Todos los métodos de UIStackView tienen sus reemplazos:

lr_arrangedSubviews para arrangedSubviews

lr_addArrangedSubview(_:) para addArrangedSubview(_:)

lr_removeArrangedSubview(_:) para removeArrangedSubview(_:)

lr_insertArrangedSubview(_:at:) para insertArrangedSubview(_:at:)

lr_stackSpacing es más flexible y potente que setCustomSpacing(_:after:) . Puede especificar el espaciado de una vista en 4 direcciones: superior, derecha, inferior, izquierda.


Actualización para iOS 11, StackViews con espaciado personalizado

Apple ha agregado la capacidad de establecer un espaciado personalizado en iOS 11. Simplemente tiene que especificar el espaciado después de cada subvista organizada. Lamentablemente, no puede especificar el espaciado antes.

stackView.setCustomSpacing(10.0, after: firstLabel) stackView.setCustomSpacing(10.0, after: secondLabel)

Todavía mucho mejor que usar sus propias vistas.

Para iOS 10 y menos

Simplemente puede agregar vistas transparentes a su vista de pila y agregarles restricciones de ancho.

(Etiqueta - UIView - Etiqueta - UIView -Label)

y si mantiene la distribution para llenar, puede configurar restricciones de ancho variable en sus UIViews.

Pero consideraría si esta es la situación correcta para usar stackviews si ese es el caso. Autolayout hace que sea muy fácil configurar anchos variables entre vistas.


SWIFT 4

Después de la respuesta lilpit, aquí hay una extensión de UIStackView para agregar un espacio superior e inferior a su vista previa organizada

extension UIStackView { func addCustomSpacing(top: CGFloat, bottom: CGFloat) { //If the stack view has just one arrangedView, we add a dummy one if self.arrangedSubviews.count == 1 { self.insertArrangedSubview(UIView(frame: .zero), at: 0) } //Getting the second last arrangedSubview and the current one let lastTwoArrangedSubviews = Array(self.arrangedSubviews.suffix(2)) let arrSpacing: [CGFloat] = [top, bottom] //Looping through the two last arrangedSubview to add spacing in each of them for (index, anArrangedSubview) in lastTwoArrangedSubviews.enumerated() { //After iOS 11, the stackview has a native method if #available(iOS 11.0, *) { self.setCustomSpacing(arrSpacing[index], after: anArrangedSubview) //Before iOS 11 : Adding dummy separator UIViews } else { guard let arrangedSubviewIndex = arrangedSubviews.firstIndex(of: anArrangedSubview) else { return } let separatorView = UIView(frame: .zero) separatorView.translatesAutoresizingMaskIntoConstraints = false //calculate spacing to keep a coherent spacing with the ios11 version let isBetweenExisitingViews = arrangedSubviewIndex != arrangedSubviews.count - 1 let existingSpacing = isBetweenExisitingViews ? 2 * spacing : spacing let separatorSize = arrSpacing[index] - existingSpacing guard separatorSize > 0 else { return } switch axis { case .horizontal: separatorView.widthAnchor.constraint(equalToConstant: separatorSize).isActive = true case .vertical: separatorView.heightAnchor.constraint(equalToConstant: separatorSize).isActive = true } insertArrangedSubview(separatorView, at: arrangedSubviewIndex + 1) } } } }

Entonces lo usarías así:

//Creating label to add to the UIStackview let label = UILabel(frame: .zero) //Adding label to the UIStackview stackView.addArrangedSubview(label) //Create margin on top and bottom of the UILabel stackView.addCustomSpacing(top: 40, bottom: 100)