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

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

person pvllnspk    schedule 10.07.2014    source источник
comment
@ Keenle, @ Kijug, когда вы рисуете вторым способом, вы не используете метод drawRect, см. Fe github.com/kevinzhow/PNChart/blob/master/PNChart/PNPieChart/   -  person pvllnspk    schedule 11.07.2014
comment
+ необходимо вызывать метод перерисовки только в первый раз, когда ориентация устройства изменяется, как это делает drawRect   -  person pvllnspk    schedule 11.07.2014
comment
Я обновил ответ. Пришлось создать тестовый проект с контролем диаграммы, чтобы выяснить проблему. Кстати, компонент диаграмм прост и великолепен!   -  person Keenle    schedule 11.07.2014


Ответы (8)


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

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

    _chartView.frame = self.view.bounds;
    [_chartView strokeChart];
}
person Keenle    schedule 10.07.2014
comment
Я считаю, что очень не рекомендуется устанавливать фрейм в коде, так как появились автоматические макеты, проверьте мой ответ - person 2cupsOfTech; 23.02.2015

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

Swift

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

Цель-C

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

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

person SwiftArchitect    schedule 02.10.2015
comment
Это кажется хорошим решением, но когда я помещаю его в свой TableViewController, он не вызывается при вращении. Возможно, это моя целевая версия iOS (8.1) или что-то в этом роде, но она не работает. - person Damien Del Russo; 30.12.2015
comment
layoutSubviews - это UIView метод, а не UIViewController метод. Вам необходимо создать подкласс UITableView, а не UITableViewController, что можно сделать в IB. Вы можете узнать больше о layoutSubviews на stackoverflow.com/a/5330162/218152. - person SwiftArchitect; 30.12.2015
comment
Хорошо, спасибо. Мои представления фактически перерисовывались уже после установки contentMode = .Redraw в TableView в IB. Проблема, с которой я столкнулся, была моя собственная ошибка, так как исправлена. Спасибо! - person Damien Del Russo; 31.12.2015
comment
Это не работает в моем тестировании. Изменение ориентации не вызывает перерисовки. И я использую это в классе, который я создал, эти подклассы UIView - person johnny kehr; 26.07.2019

Ноль строк кода

Используйте .redraw

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

person SwiftArchitect    schedule 26.11.2019

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

person Adam Evans    schedule 10.07.2014
comment
Это правильный ответ, подкласс UIView сам с этим справится. - person Chris; 02.02.2016

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

- (void)updateViewConstraints
{
    [super updateViewConstraints];
    [_chartView setNeedsDisplay];
}
person 2cupsOfTech    schedule 23.02.2015
comment
Я пробовал это, но при повороте устройства это не происходит. - person Damien Del Russo; 30.12.2015
comment
@DamienDelRusso может быть другая причина, по которой он не вызывается для вас при ротации устройства, посмотрите вокруг - person 2cupsOfTech; 30.12.2015
comment
Я бы посмотрел, но обнаружил, что мои представления перерисовываются с параметром contentMode, установленным на .Redraw. Причина, по которой это не работало для меня, была моя собственная тупая ошибка, которая была исправлена. Спасибо! - person Damien Del Russo; 31.12.2015

К сожалению, в некоторых ответах предлагается переопределить методы контроллера, но у меня есть несколько пользовательских UITableViewCells с тенью вокруг, и вращение устройства растягивает ячейки, но не перерисовывает тень. Поэтому я не хочу помещать свой код в контроллер, чтобы (пере) рисовать подпредставление. Решение для меня - прослушать 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()
}

Кстати: Logger - это от typealias до SwiftyBeaver. Спасибо @Aderis, указывающему мне правильное направление.

person Sal    schedule 02.01.2018

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

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

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

}

Так приятно! :)

person David West    schedule 09.01.2016

Я пробовал "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
}
person Dave G    schedule 08.06.2018