Vraag Hoe een UIView met beperkingen in Swift animeren?


In mijn geconcipieerde voorbeeld heb ik de volgende enkele weergave:

enter image description here

Zoals je ziet, bestaat het uit een paar eenvoudige beperkingen:

  1. Lijn horizontale en verticale centra uit,
  2. Hoogte (ingesteld op een constante)
  3. Voorloop- en volgspaties (ingesteld op constant)

Wat ik probeer te bereiken is om deze roodachtige / roze weergave vanaf de top te laten "binnenkomen". Traditioneel zou ik in een wereld zonder beperkingen alleen het kader binnenin aanpassen UIView.animateWithDuration, maar ik weet niet zeker hoe ik het vergelijkbare doe in een constraint-wereld.

Om mijn vraag te herhalen, hoe kan ik ervoor zorgen dat mijn beeld van de scène begint en het uitzicht vanuit de top vanaf de top animeert?

Ik heb overwogen de verticale centra-beperking te animeren (en vervolgens te callen) layoutIfNeeded), maar het gewenste effect wordt niet bereikt.

Bedankt voor je hulp.


37
2017-12-09 05:18


oorsprong


antwoorden:


Wat u kunt doen is de volgende code toevoegen in uw viewDidAppear methode. Je maakt eerst een IBOutlet eigenschap van de Y-beperking van uw weergave in het midden en wijzig vervolgens de constante waarde ervan.

self.centerYConstraint.constant = 500.0
self.view.layoutIfNeeded()

UIView.animateWithDuration(Double(0.5), animations: {
        self.centerYConstraint.constant = 0
        self.view.layoutIfNeeded()
    })

61
2017-12-09 05:43



Wat je wilt is eigenlijk vrij eenvoudig en ik zal gedetailleerd beschrijven hoe het moet worden gedaan zonder te rommelen met prioriteiten of funky constanten. Op deze manier kunnen we een animatie krijgen die op elk schermformaat werkt.

De TL; DR is dat je je beperkingen moet configureren en vervolgens layoutIfNeeded in je animatieblok moet oproepen om de wijzigingen te animeren. Voor meer zie deze SO post.

We hebben dus twee reeksen beperkingen nodig om het zicht te verbergen en te tonen. In viewDidLoad het uitzicht zal verborgen zijn, en dan in viewDidAppear of waar we ook willen dat die weergave inzoomt.

Storyboard / XIB-installatie

Dus het eerste is om de beperkingen te configureren die niet veranderen in IB (of code, waar je je ook prettig bij voelt). Namelijk; de hoogte van het rode beeld en de voorloop- en volgruimte naar de container. Dus je beperkingen kunnen er zo uitzien (Notitie: Ik heb geen breedtebeperking ingesteld maar laat de begin- en volgspaties de breedte definiëren):

Constraints

Nu zul je zien dat IB je zal waarschuwen dat er geen constraint is geconfigureerd voor de Y-positie van je zicht (vandaar de rode stippellijnen)

View with warnings

U kunt nu de bovenste spatie toevoegen aan containerbeperking en deze instellen als een tijdelijke aanduidingbeperking (aanvinkvakje dat zegt "verwijderen tijdens bouwtijd"). We doen dit omdat we willen bepalen waar de weergave programmatisch is.

enter image description here

Dit betekent dat deze beperking niet bestaat wanneer de weergave is geladen, maar dient om al uw waarschuwingen te verwijderen, omdat u IB vertelt dat u weet hoe u met deze beperking moet omgaan wanneer de weergave is geladen.

Coderingstijd

Nu hebben we een methode nodig om de weergave te verbergen, een methode om de weergave te tonen. Hiervoor gaan we de Y-positioneringbeperking in de weergave opslaan en vervolgens animeren. Onze viewController kan er als volgt uitzien:

@IBOutlet weak var redView: UIView!
var redViewYPositionConstraint: NSLayoutConstraint?

override func viewDidLoad() {
    super.viewDidLoad()
    self.hideRedViewAnimated(false)
}

override func viewDidAppear(animated: Bool) {
    super.viewDidAppear(animated)
    self.showRedViewAnimated(true)
}

Hiding

Onze methode om de weergave te verbergen kan eenvoudig de positiebeperking verwijderen en er vervolgens een toevoegen met de rode weergaven onderaan gelijk aan de weergave bovenaan de weergave:

func hideRedViewAnimated(animated: Bool) {
    //remove current constraint
    self.removeRedViewYPositionConstraint()
    let hideConstraint = NSLayoutConstraint(item: self.redView,
        attribute: .Bottom,
        relatedBy: .Equal,
        toItem: self.view,
        attribute: .Top,
        multiplier: 1,
        constant: 0)
    self.redViewYPositionConstraint = hideConstraint
    self.view.addConstraint(hideConstraint)
    //animate changes
    self.performConstraintLayout(animated: animated)
}

Resultaat

Op dezelfde manier verplaatst onze showbeperking de middelpunt Y van de weergave naar het controlecentrum Y:

func showRedViewAnimated(animated: Bool) {
    //remove current constraint
    self.removeRedViewYPositionConstraint()
    let centerYConstraint = NSLayoutConstraint(item: self.redView,
        attribute: .CenterY,
        relatedBy: .Equal,
        toItem: self.view,
        attribute: .CenterY,
        multiplier: 1,
        constant: 0)
    self.redViewYPositionConstraint = centerYConstraint
    self.view.addConstraint(centerYConstraint)
    //animate changes
    self.performConstraintLayout(animated: animated)
}

Gemaksmethoden

Voor de volledigheid zien de gemaksmethoden die ik heb gebruikt er als volgt uit:

func performConstraintLayout(animated animated: Bool) {
    if animated == true {
          UIView.animateWithDuration(1,
          delay: 0,
          usingSpringWithDamping: 0.5,
          initialSpringVelocity: 0.6,
          options: .BeginFromCurrentState,
          animations: { () -> Void in
             self.view.layoutIfNeeded()
          }, completion: nil)
     } else {
          self.view.layoutIfNeeded()
     }
}

func removeRedViewYPositionConstraint() {
    if redViewYPositionConstraint != nil {
        self.view.removeConstraint(self.redViewYPositionConstraint!)
        self.redViewYPositionConstraint = nil
    }
}

Je kunt ook controleren of de rode weergave zichtbaar is door een beetje CGRect-wiskunde te gebruiken:

func isRedViewVisible() -> Bool {
    return CGRectContainsPoint(self.view.bounds, self.redView.frame.origin)
}

12
2017-12-11 07:08



Probeer dit:

class ViewController: UIViewController {

    // red view
    @IBOutlet weak var myView: UIView!
    //  vertical align contraint
    @IBOutlet weak var verticalConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        verticalConstraint.constant = (myView.bounds.height + self.view.bounds.height)/2
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.view.layoutIfNeeded()
        UIView.animateWithDuration(0.5) {
            self.verticalConstraint.constant = 0
            self.view.layoutIfNeeded()
        }
    }

}

Wees voorzichtig firstItem en secondItem volgorde in de beperking. De bovenstaande code gaat ervan uit Superview is de firstItem:

screenshot


Alternatieve manier is om te definiëren twee beperkingen:

  • Beperking Y-uitlijning (Superview.CenterY == View.CenterY) priority = 750
  • Verticale ruimtebeperking (SuperView.Top == View.Bottom) priority = 500

screenshot

En pas het aan prioriteit om te bepalen welke contraint moet worden aangenomen.

class ViewController: UIViewController {

    //  vertical align contraint
    @IBOutlet weak var centerYConstraint: NSLayoutConstraint!

    override func viewDidLoad() {
        super.viewDidLoad()
        centerYConstraint.priority = 250
    }

    override func viewDidAppear(animated: Bool) {
        super.viewDidAppear(animated)
        self.view.layoutIfNeeded()
        UIView.animateWithDuration(0.5) {
            self.centerYConstraint.priority = 750
            self.view.layoutIfNeeded()
        }
    }

}

9
2017-12-09 06:03



Voor iedereen die op zoek is naar eenvoudige animaties zoals de aanvraag:

Voor de slide-up animatie moet je [...] gebruiken    CGAffineTransformMakeTranslation (x, y).

De reden is dat je voor een slide-up animatie eerst de   vanuit het scherm bekijken en vervolgens terugzetten naar de oorspronkelijke positie. Dus in   jouw viewDidLoad gebruikt gewoon:

yourView.transform = CGAffineTransformMakeTranslation(0, 500)

Hierdoor wordt het scherm verplaatst, in dit geval onderaan. Nu in de    viewDidAppear je kunt je weergave laten zien met:

UIView.animateWithDuration(0.7, delay: 0.0, usingSpringWithDamping: 0.5,
initialSpringVelocity: 0.5, options: [], animations: {
        self.yourView.transform = CGAffineTransformMakeScale(1, 1)
    }, completion: nil)

Met deze regels kunt u de beperkingen die u wilt toevoegen aan uw UIView en deze plaatsen waar u maar wilt in uw ViewController.


6
2018-04-08 10:42



Voor mij de beste manier om te animeren Swift 3 & 4

self.constraint.constant = -150

UIView.animate(withDuration: 0.45) { [weak self] in
    self?.view.layoutIfNeeded()
}

0
2017-10-06 19:49