- If I draw my chart inside
- (void)drawRect:(CGRect)rect
is 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. - If I create a view like a subview using
- (id)initWithFrame:(CGRect)frame
and then add it in view controller like[self.view addSubview:chartView];
. How in this case I can handle rotation to redraw my chart?
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];
}
While a preferred solution requires zero lines of code, if you must trigger a redraw, do so in setNeedsDisplay
, which in turn invokes drawRect
.
No need to listen to notifications nor refactor the code.
Swift
override func layoutSubviews() {
super.layoutSubviews()
self.setNeedsDisplay()
}
Objective-C
- (void)layoutSubviews {
[super layoutSubviews];
[self setNeedsDisplay];
}
Note:
layoutSubviews
is a UIView
method, not a UIViewController
method.
layoutSubviews
is a UIView
method, not a UIViewController
method. You need to make a subclass of UITableView
, not UITableViewController
, which can be done in IB. You may want to read more about layoutSubviews on https://mcmap.net/q/56540/-when-is-layoutsubviews-called. –
Wifely 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];
}
Zero Lines of Code
Use .redraw
Programmatically invoking myView.contentMode = .redraw
when creating the custom view should suffice. It is a single flag in IB and, as such, the 0 lines of code prefered way. See Stack Overflow How to trigger drawRect on UIView subclass.
Go here to 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!
The code you'll add to your view controller:
- (void)updateViewConstraints
{
[super updateViewConstraints];
[_chartView setNeedsDisplay];
}
Unfortunately some answers suggest to override controller methods, but I've some custom UITableViewCells
with 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 UIDeviceOrientationDidChange
notification within my custom UITableViewCell
and then call setNeedsDisplay()
as suggested.
Swift 4.0 Code example in one of my custom UITableViewCells
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: Logger
is a typealias
to SwiftyBeaver
.
Thanks to @Aderis pointing me to the right direction.
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.
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! :)
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.
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:
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
}
© 2022 - 2024 — McMap. All rights reserved.