Перерисовка пользовательского интерфейса при изменении ориентации устройства

  • Если я рисую диаграмму внутри - (void)drawRect:(CGRect)rect, достаточно установить [_chartView setContentMode:UIViewContentModeRedraw], и этот метод будет вызываться, когда устройство изменит его ориентацию, и можно вычислить f.e. новый центр для моей диаграммы.
  • Если я создаю представление, подобное subview, используя - (id)initWithFrame:(CGRect)frame, а затем добавьте его в контроллер вида, например [self.view addSubview:chartView];. Как в этом случае я могу обрабатывать поворот, чтобы перерисовать диаграмму?

Ответ 1

Чтобы ваша диаграмма была правильно отображена при изменении ориентации устройства, вам необходимо обновить схему диаграммы, вот код, который вы должны добавить в свой контроллер:

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

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

Ответ 2

Использование .Redraw

Программный вызов myView.contentMode = .Redraw при создании пользовательского представления должен быть достаточным. Это единственный флаг в IB и, как таковой, предпочтительнее 0 строк кода. См. "Переполнение стека Как вызвать drawRect в подклассе UIView.


Использование setNeedsDisplay()

Если вы должны вызвать перерисовку, сделайте это в setNeedsDisplay, которая, в свою очередь, вызовет drawRect.
Нет необходимости слушать уведомления и рефакторировать код.

Swift

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

Objective-C

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

Примечание:
layoutSubviews - это метод UIView, не a UIViewController.

Ответ 3

Go здесь, чтобы узнать, как получать уведомления, когда меняется ориентация устройства. Когда ориентация изменится, просто вызовите [chartView setNeedsDisplay];, чтобы вызвать drawRect:, чтобы вы могли обновить свое представление. Надеюсь, это поможет!

Ответ 4

Код, который вы добавите в контроллер вида:

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

Ответ 5

Спасибо Keenle за вышеупомянутое решение ObjC. Я возился с созданием запрограммированных ограничений все утро, убивая свой мозг, не понимая, почему они не будут перекомпилировать/перестроить представление. Думаю, потому, что я создал UIView программно, используя CGRect... это имело приоритет.

Однако, вот мое решение было быстрым:

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

}

Так с облегчением!:)

Ответ 6

К сожалению, некоторые ответы предлагают переопределить методы контроллера, но у меня есть пользовательский UITableViewCells с теневым окружением и поворот устройства растягивает ячейки, но не перерисовывает тень. Поэтому я не хочу, чтобы мой код в контроллере (re) рисовал subview. Решением для меня является прослушивание уведомления UIDeviceOrientationDidChange в моем пользовательском UITableViewCell, а затем вызов setNeedsDisplay(), как было предложено.

Пример кода Swift 4.0 в одном из моих пользовательских 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 - от typealias до SwiftyBeaver. Благодаря @Aderis указывая мне в правильном направлении.