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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24683837/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 01:19:14  来源:igfitidea点击:

redraw a custom uiview when changing a device orientation

iosuiviewcore-graphicsquartz-core

提问by pvllnspk

  1. If I draw my chart inside - (void)drawRect:(CGRect)rectis just enough to set [_chartView setContentMode:UIViewContentModeRedraw]and this method will be called when device changes it's orienatation and it's possible to calculate f.e. new center point for my chart.
  2. If I create a view like a subview using - (id)initWithFrame:(CGRect)frameand then add it in view controller like [self.view addSubview:chartView];. How in this case I can handle rotation to redraw my chart?
  1. 如果我在里面绘制图表- (void)drawRect:(CGRect)rect就足以设置 [_chartView setContentMode:UIViewContentModeRedraw]并且当设备改变它的方向时将调用此方法,并且可以计算图表的新中心点。
  2. 如果我创建一个像子视图一样的视图- (id)initWithFrame:(CGRect)frame,然后将它添加到像[self.view addSubview:chartView];. 在这种情况下,我如何处理旋转以重绘图表?

采纳答案by Keenle

To make your chart rendered correctly when device orientation changes you need to update chart's layout, here is the code that you should add to your view controller:

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

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

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

回答by SwiftArchitect

While a preferred solution requires zero lines of code, if you musttrigger a redraw, do so in setNeedsDisplay, which in turn invokes drawRect.
No need to listen to notifications nor refactor the code.

虽然首选解决方案需要零行代码,但如果您必须触发重绘,请在 中执行此操作setNeedsDisplay,这又会调用drawRect.
无需监听通知,也无需重构代码。

Swift

迅速

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

Objective-C

目标-C

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


Note:
layoutSubviewsis a UIViewmethod, nota UIViewControllermethod.

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

回答by Adam Evans

Go hereto learn how to receive notifications for when the device orientation changes. When the orientation does change, just call [chartView setNeedsDisplay];to make drawRect:get called so you can update your view. Hope this helps!

转到此处了解如何在设备方向更改时接收通知。当方向发生变化时,只需调用[chartView setNeedsDisplay];make drawRect:get 即可更新视图。希望这可以帮助!

回答by 2cupsOfTech

The code you'll add to your view controller:

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

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

回答by Sal

Unfortunately some answers suggest to override controller methods, but I've some custom UITableViewCellswith a shadow around and rotating the device stretches the cells but doesn't redraw the shadow. So I don't want to put my code within a controller to (re)draw a subview. The solution for me is to listen to a UIDeviceOrientationDidChangenotification within my custom UITableViewCelland then call setNeedsDisplay()as suggested.

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

Swift 4.0 Code example in one of my custom UITableViewCells

我的自定义 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: Loggeris a typealiasto SwiftyBeaver. Thanks to @Aderis pointing me to the right direction.

BTW:LoggertypealiasSwiftyBeaver。感谢@Aderis 为我指明了正确的方向。

回答by SwiftArchitect

Zero Lines of Code

零行代码

Use .redraw

.redraw

Programmatically invoking myView.contentMode = .redrawwhen creating the custom view should suffice. It is a single flag in IBand, as such, the 0 lines of codeprefered way. See Stack Overflow How to trigger drawRect on UIView subclass.

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

回答by Dave G

I tried "setNeedsDisplay" in a dozen ways and it didn't work for adjusting the shadow of a view I was animating to a new position.

我以十几种方式尝试了“setNeedsDisplay”,但它无法将我正在制作动画的视图的阴影调整到新位置。

I did solve my problem with this though. If your shadow doesn't seem to want to cooperate/update, you could try just setting the shadow to nil, then setting it again:

尽管如此,我确实解决了我的问题。如果您的影子似乎不想合作/更新,您可以尝试将影子设置为 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
    })

If you don't even have a shadow yet and need that code, here's that:

如果您甚至还没有影子并且需要该代码,请使用以下代码:

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
}

回答by David West

Thanks Keenle, for the above ObjC solution. I was messing around with creating programmed constraints all morning, killing my brain, not understanding why they would not recompile/realign the view. I guess because I had created the UIView programmatically using CGRect...this was taking precedence.

感谢 Keenle,提供上述 ObjC 解决方案。我整个早上都在忙于创建程序化约束,扼杀了我的大脑,不明白为什么他们不会重新编译/重新调整视图。我猜是因为我使用 CGRect 以编程方式创建了 UIView ......这是优先的。

However, here was my solution in swift:

但是,这是我快速的解决方案:

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

}

So relieved! :)

好释怀!:)