Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

106
Views
¿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 answers
Answer question

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 Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!