Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

101
Vistas
¿Cómo escalar el contenido de una UIView para que se ajuste a un rectángulo de destino manteniendo la relación de aspecto?

Estoy tratando de resolver un problema sin éxito y espero que alguien pueda ayudar.

He buscado publicaciones similares pero no he podido encontrar nada que resuelva mi problema.

Mi escenario es el siguiente: tengo una UIView en la que se pueden colocar otras UIView . Estos se pueden mover, escalar y rotar usando reconocedores de gestos (aquí no hay problema). El usuario puede cambiar la relación de aspecto de la vista principal (el lienzo) y mi problema es intentar escalar el contenido del lienzo para que se ajuste al nuevo tamaño de destino.

Hay una serie de publicaciones con un tema similar, por ejemplo:

calcular nuevo tamaño y ubicación en un CGRect

Cómo crear una imagen de tamaño específico desde UIView

Pero estos no abordan el cambio de proporciones varias veces.

Mi acercamiento:

Cuando cambio la relación de aspecto del lienzo, utilizo AVFoundation para calcular un rectángulo ajustado al aspecto en el que deben ajustarse las subvistas del lienzo:

 let sourceRectangleSize = canvas.frame.size canvas.setAspect(aspect, screenSize: editorLayoutGuide.layoutFrame.size) view.layoutIfNeeded() let destinationRectangleSize = canvas.frame.size let aspectFittedFrame = AVMakeRect(aspectRatio:sourceRectangleSize, insideRect: CGRect(origin: .zero, size: destinationRectangleSize)) ratioVisualizer.frame = aspectFittedFrame

Casos de prueba El marco rojo es simplemente para visualizar el rectángulo ajustado de aspecto. Como puede ver, aunque el rectángulo de aspecto ajustado es correcto, la escala de los objetos no funciona. Esto es especialmente cierto cuando aplico escala y rotación a las subvistas (CanvasElement).

La lógica en la que estoy escalando los objetos es claramente incorrecta:

 @objc private func setRatio(_ control: UISegmentedControl) { guard let aspect = Aspect(rawValue: control.selectedSegmentIndex) else { return } let sourceRectangleSize = canvas.frame.size canvas.setAspect(aspect, screenSize: editorLayoutGuide.layoutFrame.size) view.layoutIfNeeded() let destinationRectangleSize = canvas.frame.size let aspectFittedFrame = AVMakeRect(aspectRatio:sourceRectangleSize, insideRect: CGRect(origin: .zero, size: destinationRectangleSize)) ratioVisualizer.frame = aspectFittedFrame let scale = min(aspectFittedFrame.size.width/canvas.frame.width, aspectFittedFrame.size.height/canvas.frame.height) for case let canvasElement as CanvasElement in canvas.subviews { canvasElement.frame.size = CGSize( width: canvasElement.baseFrame.width * scale, height: canvasElement.baseFrame.height * scale ) canvasElement.frame.origin = CGPoint( x: aspectFittedFrame.origin.x + canvasElement.baseFrame.origin.x * scale, y: aspectFittedFrame.origin.y + canvasElement.baseFrame.origin.y * scale ) } }

Adjunto la clase CanvasElement también si esto ayuda:

 final class CanvasElement: UIView { var rotation: CGFloat = 0 var baseFrame: CGRect = .zero var id: String = UUID().uuidString // MARK: - Initialization override init(frame: CGRect) { super.init(frame: frame) storeState() setupGesture() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) } // MARK: - Gesture Setup private func setupGesture() { let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(panGesture(_:))) let pinchGestureRecognizer = UIPinchGestureRecognizer(target: self, action: #selector(pinchGesture(_:))) let rotateGestureRecognizer = UIRotationGestureRecognizer(target: self, action: #selector(rotateGesture(_:))) addGestureRecognizer(panGestureRecognizer) addGestureRecognizer(pinchGestureRecognizer) addGestureRecognizer(rotateGestureRecognizer) } // MARK: - Touches override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { super.touchesBegan(touches, with: event) moveToFront() } //MARK: - Gestures @objc private func panGesture(_ sender: UIPanGestureRecognizer) { let move = sender.translation(in: self) transform = transform.concatenating(.init(translationX: move.x, y: move.y)) sender.setTranslation(CGPoint.zero, in: self) storeState() } @objc private func pinchGesture(_ sender: UIPinchGestureRecognizer) { transform = transform.scaledBy(x: sender.scale, y: sender.scale) sender.scale = 1 storeState() } @objc private func rotateGesture(_ sender: UIRotationGestureRecognizer) { rotation += sender.rotation transform = transform.rotated(by: sender.rotation) sender.rotation = 0 storeState() } // MARK: - Miscelaneous func moveToFront() { superview?.bringSubviewToFront(self) } public func rotated(by degrees: CGFloat) { transform = transform.rotated(by: degrees) rotation += degrees } func storeState() { print(""" Element Frame = \(frame) Element Bounds = \(bounds) Element Center = \(center) """) baseFrame = frame } }

Cualquier ayuda o consejo, enfoques, con algunos ejemplos reales sería genial. No espero que nadie proporcione el código fuente completo, sino algo que pueda usar como base.

Gracias por tomarse el tiempo de leer mi pregunta.

over 4 years ago · Santiago Trujillo
1 Respuestas
Responde la pregunta

0

Quizás puedas hacer los tres rectángulos en una vista. Y luego puede mantener la relación de aspecto para la vista.

Si está utilizando diseño automático y Snapkit. Las restricciones pueden ser así:

 view.snp.makeConstraints { make in make.width.height.lessThanOrEqualToSuperview() make.centerX.centerY.equalToSuperview() make.width.equalTo(view.snp.height) make.width.height.equalToSuperview().priority(.high) }

Entonces, esta vista se ajustará al aspecto en supervista.

Volver a los niños en esta vista. Si desea escalar a cada niño cuando cambia el marco de la vista, también debe agregar restricciones. O puede usar la máscara de tamaño automático, tal vez sea más simple.

Si no desea utilizar el diseño automático. Tal vez puedas intentar transform . Cuando transforma alguna vista, los elementos secundarios de esta vista también cambiarán.

 // The scale depends on the aspect-ratio of superview. view.transform = CGAffineTransformMakeScale(0.5, 0.5);
over 4 years ago · Santiago Trujillo Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda