在 layoutSubviews 中旋转视图

Rotating a view in layoutSubviews

背景和目标

目标:我想旋转翻转一个UITextView。 (为什么:看我的previous question)

问题: 如果我直接在 UITextView 上进行转换,文本布局会由于某种未知原因而变得混乱。

解决方法:UITextView放入UIView容器中,然后在容器上进行变换

新问题: 旋转视图上的自动布局(或任何类型的布局)变为 a major headache

建议的解决方案: 创建一个 UIView 的子类,作为旋转和翻转的附加容器 UIView。自动布局应该在这个自定义视图上工作。

当前问题

当所有内容首次出现时有效(UITextView 背景为黄色):

但是当方向发生变化时,会发生以下情况(蓝色是子类 UIView 背景,在 IB 中设置):

如果我禁用 rotationView.addSubview(textView) 行,那么旋转容器视图(红色)会自动重新定位,即使在方向改变时也是如此:

所以问题一定出在我添加 UITextView 的位置。但是我该怎么做呢?

代码

class MongolTextView: UIView {

    // properties
    var rotationView: UIView!
    var textView: UITextView!

    // This method gets called if you create the view in the Interface Builder
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    // This method gets called if you create the view in code
    override init(frame: CGRect){
        super.init(frame: frame)
        self.setup()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        self.setup()
    }

    func setup() {

        rotationView = UIView(frame: self.frame)
        rotationView.backgroundColor = UIColor.redColor()
        self.addSubview(rotationView)

        textView = UITextView(frame: CGRectZero)
        textView.backgroundColor = UIColor.yellowColor()
        textView.text = "This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text This is some text "

    }

    override func layoutSubviews() {
        super.layoutSubviews()

        // set the size of the rotation container view
        let width = self.bounds.width
        let height = self.bounds.height
        rotationView.frame = CGRect(origin: CGPoint(x: CGFloat(0), y: CGFloat(0)), size: CGSize(width: height, height: width))

        textView.frame = rotationView.bounds // Problem lines here???
        rotationView.addSubview(textView)    // Problem lines here???

        // rotate, translate, and flip the container view
        var rotation = CGAffineTransformMakeRotation(CGFloat(-M_PI_2))
        // the following translation repositions the top left corner at the origin of the superview
        var translation = CGAffineTransformMakeTranslation((rotationView.bounds.height / 2)-(rotationView.bounds.width / 2), (rotationView.bounds.width / 2)-(rotationView.bounds.height / 2))
        var rotationAndTranslation = CGAffineTransformConcat(rotation, translation)
        var transformPlusScale = CGAffineTransformScale(rotationAndTranslation, CGFloat(-1), CGFloat(1))

        rotationView.transform = transformPlusScale

    }
}

如果我不能让它工作...

虽然我目前 运行 在这里靠墙,但我的下一个计划是覆盖 drawRect() 来进行转换。不过,这不是我的第一选择,因为据说这样做会降低性能。

在调试模式下检查您的宽度和高度。我猜他们在旋转前后是一样的。这样您的屏幕截图将是预期的。

第二件事是你应用了两次转换。

你有旋转视图 -> 你应用变换 -> 你在 phone 旋转时改变框架 -> 以前的变换仍然应用 -> 然后你应用另一个变换。 或许你的答案就在这里。

编辑:

可能的解决方案:

您可以检测 您的方向

 UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

 if(orientation == 0) //Default orientation 
   //UI is in Default (Portrait) -- this is really a just a failsafe. 
 else if(orientation == UIInterfaceOrientationPortrait)
   //Do something if the orientation is in Portrait
 else if(orientation == UIInterfaceOrientationLandscapeLeft)
   // Do something if Left
 else if(orientation == UIInterfaceOrientationLandscapeRight)

然后决定如何处理。

如果方向是纵向而不是你

width = self.bound.size.width;
height = self.bound.size.height;

如果不是

height = self.bound.size.width;
width = self.bound.size.height;

问题中代码的问题似乎是转换不断地相互添加。为了解决这个问题,解决方案是每次都重新设置转换,即将其设置为身份转换。

rotationView.transform = CGAffineTransformIdentity

这是显示关键部分的部分实现。

import UIKit
@IBDesignable class UIVerticalTextView: UIView {

    var textView = UITextView()
    let rotationView = UIView()

    var underlyingTextView: UITextView {
        get {
            return textView
        }
        set {
            textView = newValue
        }
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

    override init(frame: CGRect){
        super.init(frame: frame)
        self.setup()
    }

    override func awakeFromNib() {
        super.awakeFromNib()
        self.setup()
    }

    func setup() {

        rotationView.backgroundColor = UIColor.redColor()
        textView.backgroundColor = UIColor.yellowColor()
        self.addSubview(rotationView)
        rotationView.addSubview(textView)

        // could also do this with auto layout constraints
        textView.frame = rotationView.bounds
    }

    override func layoutSubviews() {
        super.layoutSubviews()

        rotationView.transform = CGAffineTransformIdentity // *** key line ***

        rotationView.frame = CGRect(origin: CGPointZero, size: CGSize(width: self.bounds.height, height: self.bounds.width))
        rotationView.transform = translateRotateFlip()
    }

    func translateRotateFlip() -> CGAffineTransform {

        var transform = CGAffineTransformIdentity

        // translate to new center
        transform = CGAffineTransformTranslate(transform, (self.bounds.width / 2)-(self.bounds.height / 2), (self.bounds.height / 2)-(self.bounds.width / 2))
        // rotate counterclockwise around center
        transform = CGAffineTransformRotate(transform, CGFloat(-M_PI_2))
        // flip vertically
        transform = CGAffineTransformScale(transform, -1, 1)

        return transform
    }
}

我最近的实现最有可能在 this github link 中找到。