更改设备方向时重新绘制自定义uiview

时间:2014-07-10 18:31:57

标签: ios uiview core-graphics quartz-core

  1. 如果我在- (void)drawRect:(CGRect)rect内绘制我的图表就足以设置[_chartView setContentMode:UIViewContentModeRedraw],当设备更改它的定向时将调用此方法,并且可以计算f.e.我的图表的新中心点。
  2. 如果我使用- (id)initWithFrame:(CGRect)frame创建类似子视图的视图,然后将其添加到视图控制器中,例如[self.view addSubview:chartView];。在这种情况下,我如何处理轮换以重绘我的图表?

8 个答案:

答案 0 :(得分:28)

使用.Redraw

在创建自定义视图时以编程方式调用myView.contentMode = .Redraw就足够了。它是 IB 中的单个标记,因此 0行代码是首选方式。请参阅堆栈溢出How to trigger drawRect on UIView subclass

使用setNeedsDisplay()

如果您必须触发重绘,请在setNeedsDisplay中执行此操作,然后再调用drawRect
无需收听通知也不需要重构代码。

<强>夫特

override func layoutSubviews() {
    super.layoutSubviews()
    self.setNeedsDisplay()
}

<强>目标C

- (void)layoutSubviews {
    [super layoutSubviews];
    [self setNeedsDisplay];
}

注意:
layoutSubviews是一种UIView方法,不是一种UIViewController方法。

答案 1 :(得分:14)

要在设备方向更改时正确呈现图表,您需要更新图表的布局,以下是您应添加到视图控制器的代码:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    _chartView.frame = self.view.bounds;
    [_chartView strokeChart];
}

答案 2 :(得分:4)

转到here了解如何接收设备方向更改时的通知。如果方向确实发生变化,只需致电[chartView setNeedsDisplay];即可调用drawRect:,以便您更新视图。希望这有帮助!

答案 3 :(得分:2)

您将添加到视图控制器的代码:

- (void)updateViewConstraints
{
    [super updateViewConstraints];
    [_chartView setNeedsDisplay];
}

答案 4 :(得分:0)

感谢Keenle,对于上述ObjC解决方案。我整天早上都在制造程序设计的约束,扼杀我的大脑,不理解为什么他们不会重新编译/重新调整视图。我猜是因为我以编程方式使用CGRect创建了UIView ...这是优先考虑的。

但是,这是我在swift中的解决方案:

    override func viewDidLayoutSubviews() {
    super.viewDidLayoutSubviews()
    myUIView.center = CGPoint(x: (UIScreen.mainScreen().bounds.width / 2), y: (UIScreen.mainScreen().bounds.height / 2))

}

松了一口气! :)

答案 5 :(得分:0)

不幸的是,有些答案建议覆盖控制器方法,但我有一些带有阴影的自定义UITableViewCells并且旋转设备会拉伸单元格,但不会重绘阴影。所以我不想把我的代码放在一个控制器中来(重新)绘制一个子视图。 对我而言,解决方案是在我的自定义UIDeviceOrientationDidChange中收听UITableViewCell通知,然后按照建议拨打setNeedsDisplay()

我的一个自定义UITableViewCells中的Swift 4.0代码示例

override func awakeFromNib() {
    super.awakeFromNib()

    NotificationCenter.default.addObserver(self, selector: #selector(deviceOrientationDidChangeNotification), name: NSNotification.Name.UIDeviceOrientationDidChange, object: nil)
}

@objc func deviceOrientationDidChangeNotification(_ notification: Any) {
        Logger.info("Orientation changed: \(notification)")
        setNeedsLayout()
}

BTW:LoggertypealiasSwiftyBeaver。 感谢@Aderis指出我正确的方向。

答案 6 :(得分:0)

我以十几种方式尝试了“setNeedsDisplay”,它无法调整视图的阴影,我正在为一个新的位置设置动画。

我确实解决了我的问题。如果您的影子似乎不想合作/更新,您可以尝试将阴影设置为nil,然后再次设置:

    UIView.animateKeyframes(withDuration: 0.2 /*Total*/, delay: 0.0, options: UIViewKeyframeAnimationOptions(), animations: {
        UIView.addKeyframe(withRelativeStartTime: 0.0, relativeDuration: 10/10, animations:{
            // Other things to animate

            //Set shadow to nil
            self.viewWithShadow.layer.shadowPath = nil
        })
    }, completion: { finished in
        if (!finished) { return }
        // When the view is moved, set the shadow again
        self.viewWithShadow.layer.shadowPath = UIBezierPath(rect: self.descTextView.bounds).cgPath
    })

如果你还没有阴影并且需要那个代码,那就是:

func addShadowTo (view: UIView) {
    view.layer.masksToBounds = false
    view.layer.shadowColor = UIColor.gray.cgColor
    view.layer.shadowOffset = CGSize( width: 1.0, height: 1.0)
    view.layer.shadowOpacity = 0.5
    view.layer.shadowRadius = 6.0
    view.layer.shadowPath = UIBezierPath(rect: view.bounds).cgPath
    view.layer.shouldRasterize = true
}

答案 7 :(得分:0)

零代码行

使用.redraw

在创建自定义视图时以编程方式调用myView.contentMode = .redraw就足够了。它是 IB 中的单个标志,因此, 0行代码是首选方式。请参阅堆栈溢出How to trigger drawRect on UIView subclass