UIView.animateWithDuration Не анимация Swift (снова)

Примечание. Ive уже проверила следующие проблемы с переполнением стека:

27907570, 32229252, 26118141, 31604300

Все, что я пытаюсь сделать, - это оживить анимацию в представлении (по альфе) при вызове IBAction, прикрепленного к кнопке. Затем реверсируйте при нажатии кнопки на экране.

Моей морщиной может быть то, что я использую вторичный вид, который находится на ViewDock в представлении раскадровки. Представление добавляется в подпункт во время viewDidLoad, где рамки/границы установлены так же, как и надстройка (для полной прокладки)

Причина, по которой это делается как представление наложения, поскольку оно является индикатором учебника.

Результат (как и многие другие, кто перечислил эту проблему) заключается в том, что представление (и содержащиеся элементы управления) просто появляется мгновенно и исчезает как мгновенно. Не угасать.

Я попробовал animationWithDuration с задержкой, с завершением и без завершения, с переходом и даже начал со старых UIView.beginAnimations.

Ничего не работает. Предложения тепло приветствовали.

Код примерно такой же прямой, как я могу это сделать:
Изменить: расширен код для всех соответствующих
Edit2: TL; DR Все работает, за исключением UIViewAnimateWithDuration, который, кажется, игнорирует блок и продолжительность и просто запускает встроенный код как немедленное изменение пользовательского интерфейса. Решение этого получает щедрость

@IBOutlet var infoDetailView: UIView! // Connected to the view in the SceneDock

override func viewDidLoad() {
    super.viewDidLoad()

    // Cut other vDL code that isn't relevant

    setupInfoView()
}

func setupInfoView() {
    infoDetailView.alpha = 0.0
    view.addSubview(infoDetailView)
    updateInfoViewRect(infoDetailView.superview!.bounds.size)
}

func updateInfoViewRect(size:CGSize) {
    let viewRect = CGRect(origin: CGPointZero, size: size)

    infoDetailView.frame = viewRect
    infoDetailView.bounds = viewRect

    infoDetailView.layoutIfNeeded()
    infoDetailView.setNeedsDisplay()
}

override func viewWillTransitionToSize(size: CGSize, withTransitionCoordinator coordinator: UIViewControllerTransitionCoordinator) {
    super.viewWillTransitionToSize(size, withTransitionCoordinator: coordinator)
    updateInfoViewRect(size)
}

func hideInfoView() {
    AFLog.enter(thisClass)
    UIView.animateWithDuration(
        2.0,
        animations:
        {
            self.infoDetailView.alpha = 0.0
        },
        completion:
        { (finished) in
            return true
        }
    )
    AFLog.exit(thisClass)
}

func showInfoView() {
    AFLog.enter(thisClass)
    UIView.animateWithDuration(
        2.0,
        animations:
        {
            self.infoDetailView.alpha = 0.75
        },
        completion:
        { (finished) in
            return true
        }
    )
    AFLog.exit(thisClass)
}

// MARK: - IBActions

@IBAction func openInfoView(sender: UIButton) {
    showInfoView()
}

@IBAction func closeInfoView(sender: UIButton) {
    hideInfoView()
}

Обратите внимание, что я начал со следующего:

func showInfoView() {
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.75
    })
}

func hideInfoView() {
    UIView.animateWithDuration(2.0, animations: { () -> Void in
        self.infoDetailView.alpha = 0.00
    })
}

Ответ 1

Если ваш infoDetailView находится под автоматическими ограничениями макета, вам нужно вызвать layoutIfNeeded в родительском представлении внутри animateWithDuration:

func showInfoView() {
    self.view.layoutIfNeeded() // call it also here to finish pending layout operations
    UIView.animate(withDuration: 2.0, animations: {
        self.infoDetailView.alpha = 0.75
        self.view.layoutIfNeeded()
    })
}

Теоретически это не нужно, если вы просто измените значение .alpha, но, возможно, это может быть проблемой в этом случае.

Ответ 2

Есть несколько странных вещей, которые я вижу,

сначала удалите:

infoDetailView.layoutIfNeeded()
infoDetailView.setNeedsDisplay()

Обычно вам не нужно вызывать эти методы вручную, если вы точно не знаете, что делаете.

Кроме того, когда вы меняете размер:

infoDetailView.frame = viewRect
infoDetailView.bounds = viewRect

Вам никогда не нужно устанавливать bounds и frame. Просто установите frame.

Кроме того, вы должны, вероятно, убедиться, что представление фактически не игнорирует фрейм, установив:

infoDetailView.translatesAutoresizingMaskIntoConstraints = true

Вместо сброса кадра просто установите маску авторазмера:

infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]

В результате чего:

override func viewDidLoad() {
    super.viewDidLoad()

    // Cut other vDL code that isn't relevant

    setupInfoView()
}

func setupInfoView() {
    infoDetailView.alpha = 0.0
    infoDetailView.translatesAutoresizingMaskIntoConstraints = true
    infoDetailView.autoresizingMask = [.FlexibleWidth, .FlexibleHeight]
    infoDetailView.frame = view.bounds
    view.addSubview(infoDetailView)
}

func hideInfoView() {
  ...
}

Я думаю, что это действительно поможет, потому что немедленная анимация часто связана с проблемами размера.

Если проблема не infoDetailView, вы должны проверить, является ли infoDetailView в вашей анимации тем же объектом, что и infoDetailView вы добавляете в контроллер.

Ответ 3

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

Вместо этого подумайте об использовании анимации ключевого кадра. Это то, что выглядит анимация встряски в объективе c.

+(CAKeyframeAnimation*)shakeAnimation {
    CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"transform"];
    animation.values = @[[NSValue valueWithCATransform3D:CATransform3DMakeTranslation(-10.0, 0.0, 0.0)],
                         [NSValue valueWithCATransform3D:CATransform3DMakeTranslation(10.0, 0.0, 0.0)]];
    animation.autoreverses = YES;
    animation.repeatCount = 2;
    animation.duration = 0.07;
    return animation;
}

Вот сообщение, в котором показано, как настроить альфа с ключевыми кадрами fooobar.com/questions/1169169/...

Ответ 4

Убедитесь, что значение infoDetailView opaque неверно.

https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/#//apple_ref/occ/instp/UIView/opaque

Это свойство дает подсказку системе рисования относительно того, как она должна обрабатывать представление. Если установлено значение true, система рисования рассматривает представление как полностью непрозрачное, что позволяет системе рисования оптимизировать некоторые операции рисования и повысить производительность. Если установлено значение false, система рисования компонует представление в обычном режиме с другим контентом. Значение по умолчанию этого свойства равно true.

Ответ 5

Используйте этот код:

UIView.animateWithDuration(0.3, animations: { () -> Void in
    self.infoDetailView.alpha = 0.0 
})

Ответ 6

Я реплицировал ваш код, и он работает хорошо, все в порядке. Вероятно, вы должны контролировать ограничения, соединения IBOutlet и IBActions. Постарайтесь изолировать этот код в новом проекте, если это необходимо.

Обновление: мой код и моя папка с раскадрой и папкой проекта:

my storyboard and project folder photo

Каждый объект (вид и кнопки) имеет настройки по умолчанию.

enter image description here

Я прокомментировал все строки AFLog (возможно, это только более "подробный режим", чтобы помочь вам), остальная часть вашего кода в порядке, и вы делаете то, что вы от нее отвлекаете, если вы нажмете кнопку "Открыть", изображение затухает и когда вы нажимаете кнопку закрытия, вид исчезает.

PS Не имеет значения, но я использую xCode 7.3, новый быстрый проект 2.2.

Ответ 7

Попробуйте код ниже. Просто играйте с альфой и продолжительностью, чтобы улучшить ее.

Скрыть функциональность

func hideInfoView() {
AFLog.enter(thisClass)
UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.8
    },
    completion:
    { (finished) in
        UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.4
    },
    completion:
    { (finished) in
        self.infoDetailView.alpha = 0.0
    }
)
    }
)
AFLog.exit(thisClass)
}

Показать func

func showInfoView() {
AFLog.enter(thisClass)
UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.3
    },
    completion:
    { (finished) in
        UIView.animateWithDuration(
    2.0,
    animations:
    {
        self.infoDetailView.alpha = 0.7
    },
    completion:
    { (finished) in
        self.infoDetailView.alpha = 1.0
    }
)
    }
)
AFLog.exit(thisClass)
}

Ответ 8

Вы пытались изменить свой showInfoView() на нечто большее, чем toggleInfoView?

func toggleInfoView() {
    let alpha = CGFloat(infoDetailView.alpha == 0 ? 1 : 0)
    infoDetailView.alpha = alpha       //this is where the toggle happens
}

В нем говорится, что если ваш альфа-просмотр равен 0, измените его на 1. Еще, сделайте это 0.

Если вам нужно, чтобы это произошло в анимации, попробуйте

@IBAction func openInfoView(sender: UIButton) {
    UIView.animate(withDuration: 2.0, animations: {
        self.toggleInfoView()           //fade in/out infoDetailView when animating
    })   
}
  • Вы все равно захотите сохранить этот infoDetailView.alpha = 0.0 там, где он есть, из viewDidLoad.

Ответ 9

Для компонента UILabel попробуйте вместо этого изменить цвет фона слоя.

Попробуйте это (проверено на Swift 4):

UIView.animate(withDuration: 0.2, animations: { 
    self.dateLabel.layer.backgroundColor = UIColor.red.cgColor;
})

Ответ 10

Была похожая проблема с анимацией не выполняется.

Изменен вызов функции use perform(aSelector: Selector, with: Any?, afterDelay: TimeInterval) в виде perform(#selector(functionThatDoesAnimationOfAlphaValue), with: nil, afterDelay: 0) и это сработало. Даже если TimeInterval установлен в 0.

На случай, если кто-то еще придет сюда, чтобы найти решение.

Ответ 11

Для тех, кто хочет запустить анимацию сразу после загрузки представления...

Анимация не будет работать, если вы вызовете UIView.animate(...) внутри viewDidLoad. Вместо этого он должен вызываться из функции viewDidAppear.

override func viewDidAppear(_ animated: Bool) {
    UIView.animate(withDuration: 3) {
        self.otherView.frame.origin.x += 500
    }
}