que español ios objective-c uiview constraints autolayout

ios - español - constraints swift



Elimine todas las restricciones que afectan a UIView (12)

Detalles

Xcode 9.1, Swift 4

Solución

extension UIView { func removeConstraints() { removeConstraints(constraints) } func deactivateAllConstraints() { NSLayoutConstraint.deactivate(getAllConstraints()) } func getAllSubviews() -> [UIView] { return UIView.getAllSubviews(view: self) } func getAllConstraints() -> [NSLayoutConstraint] { var subviewsConstraints = getAllSubviews().flatMap { (view) -> [NSLayoutConstraint] in return view.constraints } if let superview = self.superview { subviewsConstraints += superview.constraints.flatMap{ (constraint) -> NSLayoutConstraint? in if let view = constraint.firstItem as? UIView { if view == self { return constraint } } return nil } } return subviewsConstraints + constraints } class func getAllSubviews(view: UIView) -> [UIView] { return view.subviews.flatMap { subView -> [UIView] in return [subView] + getAllSubviews(view: subView) } } }

Uso

view.deactivateAllConstraints()

Muestra completa

ViewController

import UIKit class ViewController: UIViewController { @IBOutlet weak var simpleView: UIView! override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. sampleWithViewFromStoryBoard() sampleWithViewGeneratedProgrammaticallyted() } private func removeConstraints(view: UIView) { print("constraints: /(view.getAllConstraints().count), subviews: /(view.getAllSubviews().count)") view.deactivateAllConstraints() print("constraints: /(view.getAllConstraints().count), subviews: /(view.getAllSubviews().count)") } func sampleWithViewFromStoryBoard() { print("/nStoryboard:") removeConstraints(view: simpleView) } func sampleWithViewGeneratedProgrammaticallyted() { print("/nProgrammatically:") let view = UIView(frame: .zero) view.translatesAutoresizingMaskIntoConstraints = false view.backgroundColor = .blue self.view.addSubview(view) view.widthAnchor.constraint(equalToConstant: 200).isActive = true view.heightAnchor.constraint(equalToConstant: 200).isActive = true view.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 100).isActive = true view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 100).isActive = true removeConstraints(view: view) } }

StoryBoard

<?xml version="1.0" encoding="UTF-8"?> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13529" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> <device id="retina4_7" orientation="portrait"> <adaptation id="fullscreen"/> </device> <dependencies> <deployment identifier="iOS"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13527"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <scenes> <!--View Controller--> <scene sceneID="tne-QT-ifu"> <objects> <viewController id="BYZ-38-t0r" customClass="ViewController" customModule="stackoverflow_24418884" customModuleProvider="target" sceneMemberID="viewController"> <view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> <rect key="frame" x="0.0" y="0.0" width="375" height="667"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5Ni-DW-acW"> <rect key="frame" x="16" y="20" width="240" height="128"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="phZ-9f-16a"> <rect key="frame" x="188" y="8" width="42" height="21"/> <constraints> <constraint firstAttribute="width" constant="42" id="QHb-On-hfY"/> <constraint firstAttribute="height" constant="21" id="Sfy-Pn-YGi"/> </constraints> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="6gs-OS-OBa"> <rect key="frame" x="97" y="98" width="46" height="30"/> <constraints> <constraint firstAttribute="height" constant="30" id="L0A-My-PAS"/> </constraints> <state key="normal" title="Button"/> </button> <stackView opaque="NO" contentMode="scaleToFill" axis="vertical" distribution="fillEqually" translatesAutoresizingMaskIntoConstraints="NO" id="TvD-24-wfT"> <rect key="frame" x="20" y="20" width="60" height="80"/> <subviews> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="hIi-fL-pqH"> <rect key="frame" x="0.0" y="0.0" width="60" height="26.5"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Ahb-L9-itj"> <rect key="frame" x="0.0" y="26.5" width="60" height="27"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Label" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="A5a-DJ-Mem"> <rect key="frame" x="0.0" y="53.5" width="60" height="26.5"/> <fontDescription key="fontDescription" type="system" pointSize="17"/> <nil key="textColor"/> <nil key="highlightedColor"/> </label> </subviews> <constraints> <constraint firstAttribute="height" constant="80" id="uwc-lA-VQH"/> <constraint firstAttribute="width" constant="60" id="xzx-yt-Svs"/> </constraints> </stackView> </subviews> <color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/> <constraints> <constraint firstItem="phZ-9f-16a" firstAttribute="top" secondItem="5Ni-DW-acW" secondAttribute="top" constant="8" id="1y5-vl-Tar"/> <constraint firstAttribute="trailing" secondItem="phZ-9f-16a" secondAttribute="trailing" constant="10" id="8DX-L0-aFJ"/> <constraint firstItem="TvD-24-wfT" firstAttribute="leading" secondItem="5Ni-DW-acW" secondAttribute="leading" constant="20" id="azT-VR-ipJ"/> <constraint firstAttribute="height" constant="128" id="dDD-5k-oXP"/> <constraint firstAttribute="bottom" secondItem="6gs-OS-OBa" secondAttribute="bottom" id="jjx-wV-0pX"/> <constraint firstAttribute="width" constant="240" id="ojW-Rq-z0h"/> <constraint firstItem="TvD-24-wfT" firstAttribute="top" secondItem="5Ni-DW-acW" secondAttribute="top" constant="20" id="vgM-Do-HvO"/> <constraint firstItem="6gs-OS-OBa" firstAttribute="centerX" secondItem="5Ni-DW-acW" secondAttribute="centerX" id="wjV-CZ-xYY"/> </constraints> </view> </subviews> <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> <constraints> <constraint firstItem="5Ni-DW-acW" firstAttribute="top" secondItem="6Tk-OE-BBY" secondAttribute="top" id="546-OU-Up3"/> <constraint firstItem="5Ni-DW-acW" firstAttribute="leading" secondItem="6Tk-OE-BBY" secondAttribute="leading" constant="16" id="Okf-rU-y08"/> </constraints> <viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> </view> <connections> <outlet property="simpleView" destination="5Ni-DW-acW" id="a56-pn-GXE"/> </connections> </viewController> <placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> </objects> <point key="canvasLocation" x="32.799999999999997" y="70.614692653673174"/> </scene> </scenes> </document>

Resultados

Tengo un UIView que se coloca en la pantalla a través de varias restricciones. Algunas de las restricciones son propiedad de la supervista, otras son propiedad de otros antepasados ​​(por ejemplo, quizás la propiedad de vista de un UIViewController).

Quiero eliminar todas estas limitaciones anteriores y colocarlas en algún lugar nuevo usando nuevas restricciones.

¿Cómo puedo hacer esto sin crear un IBOutlet para cada restricción y tener que recordar qué vista posee dicha restricción?

Para elaborar, el enfoque ingenuo sería crear un grupo de IBOutlet para cada una de las restricciones, y luego incluiría un código de llamada como:

[viewA removeConstraint:self.myViewsLeftConstraint]; [viewB removeConstraint:self.myViewsTopConstraint]; [viewB removeConstraint:self.myViewsBottomConstraint]; [self.view removeConstraint:self.myViewsRightConstraint];

El problema con este código es que, incluso en el caso más simple, necesitaría crear 2 IBOutlets. Para diseños complejos, esto podría alcanzar fácilmente 4 u 8 IBOutlets requeridos. Además, tendría que asegurarme de que mi llamada para eliminar la restricción sea invocada en la vista correcta. Por ejemplo, imagine que myViewsLeftConstraint es propiedad de viewA . Si [self.view removeConstraint:self.myViewsLeftConstraint] llamar accidentalmente a [self.view removeConstraint:self.myViewsLeftConstraint] , no pasaría nada.

Nota: El método constraintsAffectingLayoutForAxis parece prometedor, pero está destinado únicamente a la depuración.

Actualización: Muchas de las respuestas que recibo tratan de self.constraints , self.superview.constraints , self.superview.constraints o alguna variante de ellas. Estas soluciones no funcionarán, ya que esos métodos solo devuelven las restricciones que posee la vista, no las que afectan a la vista.

Para aclarar el problema con estas soluciones, considere esta jerarquía de vista:

  • Abuelo
    • Padre
      • Yo
        • Hijo
        • Hija
      • Hermano
    • Tío

Ahora imagina que creamos las siguientes restricciones y siempre las adjuntas a su ancestro común más cercano:

  • C0: Yo: la misma cima que Son (propiedad de Mí)
  • C1: Yo: ancho = 100 (propiedad de Mí)
  • C2: Me: la misma altura que Brother (propiedad de Father)
  • C3: Yo: igual que el tío (propiedad de Abuelo)
  • C4: Yo: igual que el abuelo (propiedad de Abuelo)
  • C5: Hermano: el mismo dejó como padre (propiedad del padre)
  • C6: Tío: mismo que el abuelo (propiedad del abuelo)
  • C7: Hijo: lo mismo que Hija (propiedad de Mí)

Ahora imagina que queremos eliminar todas las restricciones que Me afectan. Cualquier solución adecuada debería eliminar [C0,C1,C2,C3,C4] y nada más.

Si uso self.constraints (donde yo mismo soy), obtendré [C0,C1,C7] , ya que esas son las únicas restricciones que tengo. Obviamente, no sería suficiente eliminar esto ya que falta [C2,C3,C4] . Además, está eliminando C7 innecesariamente.

Si uso self.superview.constraints (donde self es Me), obtendré [C2,C5] , ya que esas son las restricciones que posee Father. Obviamente no podemos eliminar todos estos ya que C5 tiene relación alguna con Me .

Si uso grandfather.constraints , obtendré [C3,C4,C6] . Nuevamente, no podemos eliminar todos estos ya que C6 debe permanecer intacto.

El enfoque de fuerza bruta consiste en recorrer cada uno de los antecesores de la vista (incluido él mismo), y ver si firstItem o secondItem son la vista en sí; si es así, elimine esa restricción. Esto conducirá a una solución correcta, devolviendo [C0,C1,C2,C3,C4] , y solo esas restricciones.

Sin embargo, espero que haya una solución más elegante que tener que recorrer toda la lista de antepasados.


Basado en respuestas anteriores (swift 4)

Puede usar Restricciones inmediatas cuando no desee rastrear jerarquías completas.

extension UIView { /** * Deactivates immediate constraints that target this view (self + superview) */ func deactivateImmediateConstraints(){ NSLayoutConstraint.deactivate(self.immediateConstraints) } /** * Deactivates all constrains that target this view */ func deactiveAllConstraints(){ NSLayoutConstraint.deactivate(self.allConstraints) } /** * Gets self.constraints + superview?.constraints for this particular view */ var immediateConstraints:[NSLayoutConstraint]{ let constraints = self.superview?.constraints.filter{ $0.firstItem as? UIView === self || $0.secondItem as? UIView === self } ?? [] return self.constraints + constraints } /** * Crawls up superview hierarchy and gets all constraints that affect this view */ var allConstraints:[NSLayoutConstraint] { var view: UIView? = self var constraints:[NSLayoutConstraint] = [] while let currentView = view { constraints += currentView.constraints.filter { return $0.firstItem as? UIView === self || $0.secondItem as? UIView === self } view = view?.superview } return constraints } }


En Swift:

import UIKit extension UIView { /** Removes all constrains for this view */ func removeConstraints() { let constraints = self.superview?.constraints.filter{ $0.firstItem as? UIView == self || $0.secondItem as? UIView == self } ?? [] self.superview?.removeConstraints(constraints) self.removeConstraints(self.constraints) } }


Esta es la forma de desactivar todas las restricciones desde una vista específica

NSLayoutConstraint.deactivate(myView.constraints)


Este enfoque funcionó para mí:

@interface UIView (RemoveConstraints) - (void)removeAllConstraints; @end @implementation UIView (RemoveConstraints) - (void)removeAllConstraints { UIView *superview = self.superview; while (superview != nil) { for (NSLayoutConstraint *c in superview.constraints) { if (c.firstItem == self || c.secondItem == self) { [superview removeConstraint:c]; } } superview = superview.superview; } [self removeConstraints:self.constraints]; self.translatesAutoresizingMaskIntoConstraints = YES; } @end

Después de hacerlo, la ejecución de su vista permanece donde estaba porque crea restricciones de conversión automática. Cuando no hago esto, la vista generalmente desaparece. Además, no solo elimina las restricciones de la supervista, sino que atraviesa todo el camino, ya que puede haber restricciones que lo afecten en las vistas de los antepasados.


Hay dos formas de cómo lograr eso según la documentación del desarrollador de Apple

1. NSLayoutConstraint.deactivateConstraints

Este es un método de conveniencia que proporciona una manera fácil de desactivar un conjunto de restricciones con una llamada. El efecto de este método es el mismo que establecer la propiedad isActive de cada restricción en falso. Normalmente, usar este método es más eficiente que desactivar cada restricción individualmente.

Rápido

// Declaration class func deactivate(_ constraints: [NSLayoutConstraint]) // Usage NSLayoutConstraint.deactivate(yourView.constraints)

C objetivo

// Declaration + (void)deactivateConstraints:(NSArray<NSLayoutConstraint *> *)constraints; // Usage [NSLayoutConstraint deactivateConstraints:yourView.constraints];

2. UIView.removeConstraints ( UIView.removeConstraints para> = iOS 8.0)

Al desarrollar para iOS 8.0 o posterior, use el método deactivateConstraints de la clase NSLayoutConstraint: en lugar de llamar al método removeConstraints: directamente. El método deactivateConstraints: elimina automáticamente las restricciones de las vistas correctas.

Rápido

// Declaration func removeConstraints(_ constraints: [NSLayoutConstraint])` // Usage yourView.removeConstraints(yourView.constraints)

C objetivo

// Declaration - (void)removeConstraints:(NSArray<__kindof NSLayoutConstraint *> *)constraints; // Usage [yourView removeConstraints:yourView.constraints];

Referencias

  1. NSLayoutConstraint
  2. UIView

La única solución que he encontrado hasta ahora es eliminar la vista de su super visión:

[view removeFromSuperview]

Esto parece que elimina todas las restricciones que afectan su diseño y está listo para agregarse a una supervista y tener nuevas restricciones adjuntas. Sin embargo, eliminará incorrectamente cualquier subvista de la jerarquía y se deshará de [C7] incorrecta.


Podrías usar algo como esto:

[viewA.superview.constraints enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { NSLayoutConstraint *constraint = (NSLayoutConstraint *)obj; if (constraint.firstItem == viewA || constraint.secondItem == viewA) { [viewA.superview removeConstraint:constraint]; } }]; [viewA removeConstraints:viewA.constraints];

Básicamente, esto se enumera sobre todas las restricciones en la supervista de viewA y elimina todas las restricciones relacionadas con viewA.

Luego, la segunda parte elimina las restricciones de viewA usando la matriz de restricciones de viewA.


Puede eliminar todas las restricciones en una vista haciendo esto:

[_cell.contentView removeConstraints:_cell.contentView.constraints];

EDITAR: Para eliminar las restricciones de todas las subvistas, use la siguiente extensión en Swift:

extension UIView { func clearConstraints() { for subview in self.subviews { subview.clearConstraints() } self.removeConstraints(self.constraints) } }


Una solución Swift:

extension UIView { func removeAllConstraints() { var view: UIView? = self while let currentView = view { currentView.removeConstraints(currentView.constraints.filter { return $0.firstItem as? UIView == self || $0.secondItem as? UIView == self }) view = view?.superview } } }

Es importante analizar a todos los padres, ya que las limitaciones entre dos elementos son retenidas por los ancestros comunes, por lo que no es suficiente borrar la supervista tal como se detalla en esta respuesta , y es posible que termines teniendo una mala sorpresa más adelante.


Utilizo el siguiente método para eliminar todas las restricciones de una vista:

.h archivo:

+ (void)RemoveContraintsFromView:(UIView*)view removeParentConstraints:(bool)parent removeChildConstraints:(bool)child;

archivo .m:

+ (void)RemoveContraintsFromView:(UIView *)view removeParentConstraints:(bool)parent removeChildConstraints:(bool)child { if (parent) { // Remove constraints between view and its parent. UIView *superview = view.superview; [view removeFromSuperview]; [superview addSubview:view]; } if (child) { // Remove constraints between view and its children. [view removeConstraints:[view constraints]]; } }

Puedes leer aquí cómo funciona detrás del capó.

Si necesita un control más granular, le recomiendo encarecidamente que se cambie a Masonry , una poderosa clase de framework que puede usar cada vez que necesite manejar las restricciones de manera programática.


(A partir del 31 de julio de 2017)

SWIFT 3

self.yourCustomView.removeFromSuperview() self.yourCustomViewParentView.addSubview(self.yourCustomView)

C objetivo

[self.yourCustomView removeFromSuperview]; [self.yourCustomViewParentView addSubview:self.yourCustomView];

Esta es la forma más fácil de eliminar rápidamente todas las restricciones que existen en un UIView. Solo asegúrate de volver a agregar el UIView con sus nuevas restricciones o un nuevo marco después =)