更改设备方向时重绘自定义 uiview
Posted
技术标签:
【中文标题】更改设备方向时重绘自定义 uiview【英文标题】:redraw a custom uiview when changing a device orientation 【发布时间】:2014-07-10 18:31:57 【问题描述】:-
如果我在
- (void)drawRect:(CGRect)rect
内绘制图表就足以设置[_chartView setContentMode:UIViewContentModeRedraw]
,并且当设备改变它的方向时将调用此方法,并且可以计算 f.e.我的图表的新中心点。
如果我使用- (id)initWithFrame:(CGRect)frame
创建一个类似于子视图的视图,然后将其添加到视图控制器中,例如[self.view addSubview:chartView];
。在这种情况下,我如何处理旋转以重绘图表?
【问题讨论】:
@Keenle,@Kijug 使用第二种方式绘制时不使用 drawRect 方法,请参阅 f.e github.com/kevinzhow/PNChart/blob/master/PNChart/PNPieChart/… 我已经更新了答案。必须创建一个带有图表控件的测试项目来解决问题。顺便说一句,图表组件既简单又很棒! 【参考方案1】:虽然首选解决方案需要zero lines of code,但如果您必须触发重绘,请在setNeedsDisplay
中执行此操作,这反过来又会调用drawRect
。
无需监听通知,也无需重构代码。
斯威夫特
override func layoutSubviews()
super.layoutSubviews()
self.setNeedsDisplay()
Objective-C
- (void)layoutSubviews
[super layoutSubviews];
[self setNeedsDisplay];
注意:layoutSubviews
是 UIView
方法,不是 UIViewController
方法。
【讨论】:
这似乎是一个很好的解决方案,但是当我将它放入我的 TableViewController 时,它不会在旋转时被调用。也许这是我的目标 ios (8.1) 或其他版本,但它不起作用。layoutSubviews
是 UIView
方法,而不是 UIViewController
方法。您需要创建UITableView
的子类,而不是UITableViewController
,这可以在IB 中完成。您可能想在 ***.com/a/5330162/218152 上阅读有关 layoutSubviews 的更多信息。
酷,谢谢。我的视图实际上已经通过在 IB 的 TableView 上设置 contentMode = .Redraw 进行了重绘。我遇到的问题是我自己的错,因为得到了纠正。谢谢!
这在我的测试中不起作用。方向更改不会触发重绘。我在我创建的子类 UIView 的类上使用它【参考方案2】:
为了让您的图表在设备方向改变时正确呈现,您需要更新图表的布局,下面是您应该添加到视图控制器的代码:
- (void)viewDidLayoutSubviews
[super viewDidLayoutSubviews];
_chartView.frame = self.view.bounds;
[_chartView strokeChart];
【讨论】:
我相信自从自动布局问世以来,它非常不鼓励在代码中设置框架,请检查我的答案【参考方案3】:零代码行
使用.redraw
在创建自定义视图时以编程方式调用myView.contentMode = .redraw
就足够了。它是 IB 中的单个标志,因此是 0 行代码 的首选方式。请参阅堆栈溢出How to trigger drawRect on UIView subclass。
【讨论】:
【参考方案4】:转到here 了解如何在设备方向更改时接收通知。当方向发生变化时,只需调用 [chartView setNeedsDisplay];
以调用 drawRect:
以便您可以更新视图。希望这会有所帮助!
【讨论】:
这是正确的答案,UIView 子类应该自己处理。【参考方案5】:您将添加到视图控制器的代码:
- (void)updateViewConstraints
[super updateViewConstraints];
[_chartView setNeedsDisplay];
【讨论】:
我试过了,但它没有在设备旋转时调用。 @DamienDelRusso 可能有其他原因导致它在设备旋转时没有被调用,环顾四周 我会看,但我发现我的视图正在重绘,contentMode 设置为 .Redraw。它对我不起作用的原因是我自己的愚蠢错误,因为已修复。谢谢!【参考方案6】:不幸的是,一些答案建议覆盖控制器方法,但我有一些自定义 UITableViewCells
周围有阴影,旋转设备会拉伸单元格但不会重绘阴影。所以我不想将我的代码放在控制器中来(重新)绘制子视图。
我的解决方案是在我的自定义UITableViewCell
中收听UIDeviceOrientationDidChange
通知,然后按照建议调用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()
顺便说一句:Logger
是 typealias
到 SwiftyBeaver
。
感谢@Aderis 为我指明了正确的方向。
【讨论】:
【参考方案7】:感谢 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))
松了一口气! :)
【讨论】:
【参考方案8】:我用十几种方法尝试了“setNeedsDisplay”,但它无法将我正在制作动画的视图的阴影调整到新位置。
不过,我确实解决了我的问题。如果您的影子似乎不想合作/更新,您可以尝试将影子设置为零,然后再次设置:
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
【讨论】:
以上是关于更改设备方向时重绘自定义 uiview的主要内容,如果未能解决你的问题,请参考以下文章
将 CALayer 添加到 UIView 并能够在方向更改时重绘