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

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

7 ответов


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

- (void)viewDidLayoutSubviews {
    [super viewDidLayoutSubviews];

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

используя .Redraw

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


используя setNeedsDisplay()

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

Свифт

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

С

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

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


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


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

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

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

однако вот мое решение в swift:

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

}

такое облегчение! :)


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


я попробовал "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
}