Центрирование UIImageView не работает во время анимации

#ios #swift #xcode #animation #autolayout

#iOS #swift #xcode #Анимация #автозапуск

Вопрос:

Я пытаюсь заставить набор представлений изображений анимироваться внутри и снаружи точки, например, как работает расширяющееся меню, страница создается с уже отображаемыми кнопками, и во время viewDidLayoutSubviews () я анимирую их. При нажатии кнопки я затем возвращаю их в исходное положение, все анимации основаны на изменении центра изображения. Проблема, с которой я сталкиваюсь, заключается в том, что по какой-то причине анимация немного смещена вправо. на больших устройствах это не так уж плохо, но на устройствах меньшего размера это большая проблема. весь пользовательский интерфейс построен с использованием автозапуска:

макет внутри автозапуска

Вот код для настройки расположения центров, он запускается перед выполнением любой анимации:

         micContainerLocation = micContainer.center
        cameraContainerLocation = cameraContainer.center
        pencilContainerLocation = pencilContainer.center
        calendarContainerLocation = calendarContainer.center
  

Вот код анимации для анимации кнопок:

     UIView.animate(withDuration: 0.3, animations: {
                self.calendarContainer.center = self.calendarContainerLocation
                self.cameraContainer.center = self.cameraContainerLocation
                self.micContainer.center = self.micContainerLocation
                self.pencilContainer.center = self.pencilContainerLocation
                self.sendMessageButton.alpha = 0
                self.openMenuButton.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi / 4))

            })    
  

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

результат анимации

Любой совет был бы высоко оценен. Спасибо.

Редактировать:

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

постоянное изображение

и подробный список ограничений:

Постоянная деталь

Комментарии:

1. Используете ли вы автоматическую компоновку и ограничения? Если вы их вообще не перемещаете (ни в сторону, ни назад), находятся ли кнопки в нужных местах?

2. Да, я использую автоматическую компоновку и ограничения. Если я закомментирую код, который перемещает их в viewDidLayoutSubviews (), тогда они находятся в правильном положении «открыто». Когда я затем нажимаю кнопку, чтобы фактически открыть их, они смещаются в положение смещения, которое можно увидеть на скриншоте.

3. Возможно, вы столкнулись с конфликтами между ограничениями и пытаетесь явно задать .center свойства. Покажите, как у вас ограничены кнопки для начала.

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

Ответ №1:

Я подозреваю, что проблема (или, по крайней мере, часть проблемы) заключается в смешивании явных .center значений с ограничениями автоматической компоновки. Также возможно, что вы не получаете «истинные» значения центра.

Другой подход, использующий только автоматическую компоновку, заключается в создании массива ограничений для «скрытых» позиций и другого массива для «видимых» позиций. Затем отключите / активируйте, чтобы показать / скрыть кнопки.

И… это проще сделать, чем сказано 🙂

  • Сначала расположите свои кнопки и контейнеры в раскадровке, как вы уже сделали.
  • Затем выберите каждое из ограничений, влияющих на начальный и конечный края контейнеров.
  • Установите эти ограничения в качестве заполнителей, чтобы они были удалены во время сборки (мы установим соответствующие ограничения в коде, поэтому нам не понадобится целая куча @IBOutlet ов).
  • Затем, как вы могли догадаться, установите ограничения в своем коде.

Дополнительным преимуществом является то, что кнопки автоматически изменят свой размер / положение, даже если ширина супервизора изменится — например, при повороте устройства — без необходимости в каком-либо коде для переоценки .center свойств.

Вот изображение настройки заполнителя ограничения раскадровки:

введите описание изображения здесь

Основная идея будет заключаться в:

Создайте набор ограничений, чтобы контейнеры кнопок были вне поля зрения слева от левого края. Это будут «скрытые» ограничения.

Создайте набор ограничений, чтобы контейнеры кнопок были на виду, и каждый из них был выровнен / подобран по размеру соответствующим образом. Это будут «видимые» ограничения.

Все это может показаться сложным, но если вы посмотрите на следующий пример, я думаю, вы увидите, что на самом деле происходит очень мало.

Этот пример должен выполняться как есть… просто создайте новую раскадровку и замените исходный код, а затем используйте следующий класс. Это не совсем точно то, что у вас есть, но оно должно быть достаточно близко, чтобы вы могли использовать его в качестве отправной точки.

Вот код:

 //
//  AnimButtonsViewController.swift
//
//  Created by Don Mag on 3/15/19.
//

import UIKit

class AnimButtonsViewController: UIViewController {

    @IBOutlet var pencilContainer: UIView!
    @IBOutlet var cameraContainer: UIView!
    @IBOutlet var micContainer: UIView!
    @IBOutlet var calendarContainer: UIView!

    @IBOutlet var buttonsContainer: UIView!

    var hiddenConstraints = [NSLayoutConstraint]()
    var visibleConstraints = [NSLayoutConstraint]()

    override func viewDidLoad() {
        super.viewDidLoad()

        var c = NSLayoutConstraint()

        // set up the "hidden" constraints

        // constrain pencilContainer (1) *trailing* to buttonsContainer *leading*
        //  this will place it outside the view (to the left of left edge)

        c = pencilContainer.trailingAnchor.constraint(equalTo: buttonsContainer.leadingAnchor)
        hiddenConstraints.append(c)

        // constrain leading of remaining buttons to leading of pencilContainer
        //  they are now all "overlaid" on top of each other, outside the view

        c = cameraContainer.leadingAnchor.constraint(equalTo: pencilContainer.leadingAnchor)
        hiddenConstraints.append(c)

        c = micContainer.leadingAnchor.constraint(equalTo: pencilContainer.leadingAnchor)
        hiddenConstraints.append(c)

        c = calendarContainer.leadingAnchor.constraint(equalTo: pencilContainer.leadingAnchor)
        hiddenConstraints.append(c)


        // set up the "visible" constraints

        // constrain first button (pencilContainer (1)) *leading* to buttonsContainer *leading*
        //  and each remaining button constrain its leading to the previous button's trailing

        c = pencilContainer.leadingAnchor.constraint(equalTo: buttonsContainer.leadingAnchor)
        visibleConstraints.append(c)

        c = cameraContainer.leadingAnchor.constraint(equalTo: pencilContainer.trailingAnchor)
        visibleConstraints.append(c)

        c = micContainer.leadingAnchor.constraint(equalTo: cameraContainer.trailingAnchor)
        visibleConstraints.append(c)

        c = calendarContainer.leadingAnchor.constraint(equalTo: micContainer.trailingAnchor)
        visibleConstraints.append(c)

        // contrain last button (calendarContainer (4)) trailing to buttonsContrainer trailing

        c = calendarContainer.trailingAnchor.constraint(equalTo: buttonsContainer.trailingAnchor)
        visibleConstraints.append(c)

        // activate the hidden constraints
        NSLayoutConstraint.activate(hiddenConstraints)

    }

    @IBAction func showHideTapped(_ sender: Any) {

        if let b = sender as? UIButton {

            // just for demo purposes,
            //  if the button title is " " we need to "show" the buttons
            //  if the button title is "X" we need to "hide" the buttons

            let t = b.currentTitle

            if t == " " {
                NSLayoutConstraint.deactivate(hiddenConstraints)
                NSLayoutConstraint.activate(visibleConstraints)
                b.setTitle("X", for: .normal)
            } else {
                NSLayoutConstraint.deactivate(visibleConstraints)
                NSLayoutConstraint.activate(hiddenConstraints)
                b.setTitle(" ", for: .normal)
            }

             UIView.animate(withDuration: 0.3, animations: {
                self.view.layoutIfNeeded()
            })

        }

    }

}
  

и вот источник раскадровки:

 <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="Msu-cJ-7P1">
    <device id="retina4_7" orientation="portrait">
        <adaptation id="fullscreen"/>
    </device>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
        <capability name="Safe area layout guides" minToolsVersion="9.0"/>
        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
    </dependencies>
    <scenes>
        <!--Anim Buttons View Controller-->
        <scene sceneID="LEr-rD-3kQ">
            <objects>
                <viewController id="Msu-cJ-7P1" customClass="AnimButtonsViewController" customModule="XC10SWScratch" customModuleProvider="target" sceneMemberID="viewController">
                    <view key="view" contentMode="scaleToFill" id="Efg-NM-r2G">
                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
                        <subviews>
                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="tXi-AX-zDz" userLabel="Red View">
                                <rect key="frame" x="30" y="278.5" width="315" height="110"/>
                                <subviews>
                                    <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BDK-vE-tUk">
                                        <rect key="frame" x="4" y="30" width="273" height="50"/>
                                        <subviews>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="EbR-gU-YBO">
                                                <rect key="frame" x="0.0" y="0.0" width="68.5" height="50"/>
                                                <subviews>
                                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="unV-LI-1jJ">
                                                        <rect key="frame" x="14" y="5" width="40" height="40"/>
                                                        <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                        <constraints>
                                                            <constraint firstAttribute="height" constant="40" id="F0Z-oi-HlI"/>
                                                            <constraint firstAttribute="width" constant="40" id="P3x-Ak-lZY"/>
                                                        </constraints>
                                                        <state key="normal" title="1"/>
                                                    </button>
                                                </subviews>
                                                <color key="backgroundColor" red="0.0" green="0.99143940210000003" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                <constraints>
                                                    <constraint firstItem="unV-LI-1jJ" firstAttribute="centerX" secondItem="EbR-gU-YBO" secondAttribute="centerX" id="ZEb-9h-WvV"/>
                                                    <constraint firstItem="unV-LI-1jJ" firstAttribute="centerY" secondItem="EbR-gU-YBO" secondAttribute="centerY" id="mB2-5w-Egs"/>
                                                    <constraint firstAttribute="width" relation="greaterThanOrEqual" secondItem="unV-LI-1jJ" secondAttribute="width" id="mYy-gx-PT4"/>
                                                </constraints>
                                            </view>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="QjG-7X-1Sa">
                                                <rect key="frame" x="68.5" y="0.0" width="68" height="50"/>
                                                <subviews>
                                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="qYS-Qj-f9n">
                                                        <rect key="frame" x="14" y="5" width="40" height="40"/>
                                                        <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                        <constraints>
                                                            <constraint firstAttribute="height" constant="40" id="To5-l0-frk"/>
                                                            <constraint firstAttribute="width" constant="40" id="m9L-d5-Mac"/>
                                                        </constraints>
                                                        <state key="normal" title="2"/>
                                                    </button>
                                                </subviews>
                                                <color key="backgroundColor" red="0.0" green="0.99143940210000003" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                <constraints>
                                                    <constraint firstItem="qYS-Qj-f9n" firstAttribute="centerX" secondItem="QjG-7X-1Sa" secondAttribute="centerX" id="nNp-T0-rxc"/>
                                                    <constraint firstItem="qYS-Qj-f9n" firstAttribute="centerY" secondItem="QjG-7X-1Sa" secondAttribute="centerY" id="pDK-Y0-lag"/>
                                                </constraints>
                                            </view>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="5IF-rt-c8a">
                                                <rect key="frame" x="136.5" y="0.0" width="68.5" height="50"/>
                                                <subviews>
                                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="E15-8G-pOx">
                                                        <rect key="frame" x="14" y="5" width="40" height="40"/>
                                                        <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                        <constraints>
                                                            <constraint firstAttribute="height" constant="40" id="ADz-st-xYC"/>
                                                            <constraint firstAttribute="width" constant="40" id="rIE-3o-Yih"/>
                                                        </constraints>
                                                        <state key="normal" title="3"/>
                                                    </button>
                                                </subviews>
                                                <color key="backgroundColor" red="0.0" green="0.99143940210000003" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                <constraints>
                                                    <constraint firstItem="E15-8G-pOx" firstAttribute="centerY" secondItem="5IF-rt-c8a" secondAttribute="centerY" id="NW3-qd-aRL"/>
                                                    <constraint firstItem="E15-8G-pOx" firstAttribute="centerX" secondItem="5IF-rt-c8a" secondAttribute="centerX" id="cyb-wZ-bhq"/>
                                                </constraints>
                                            </view>
                                            <view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="kHB-hc-CY5">
                                                <rect key="frame" x="205" y="0.0" width="68" height="50"/>
                                                <subviews>
                                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="QrB-eG-9oo">
                                                        <rect key="frame" x="14" y="5" width="40" height="40"/>
                                                        <color key="backgroundColor" red="1" green="0.83234566450000003" blue="0.47320586440000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                        <constraints>
                                                            <constraint firstAttribute="width" constant="40" id="4Qh-a1-bzP"/>
                                                            <constraint firstAttribute="height" constant="40" id="maJ-ei-IEH"/>
                                                        </constraints>
                                                        <state key="normal" title="4"/>
                                                    </button>
                                                </subviews>
                                                <color key="backgroundColor" red="0.0" green="0.99143940210000003" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                                <constraints>
                                                    <constraint firstItem="QrB-eG-9oo" firstAttribute="centerX" secondItem="kHB-hc-CY5" secondAttribute="centerX" id="Enu-M7-oc0"/>
                                                    <constraint firstItem="QrB-eG-9oo" firstAttribute="centerY" secondItem="kHB-hc-CY5" secondAttribute="centerY" id="iwr-AG-t6j"/>
                                                </constraints>
                                            </view>
                                        </subviews>
                                        <color key="backgroundColor" red="0.45009386540000001" green="0.98132258650000004" blue="0.4743030667" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <constraints>
                                            <constraint firstItem="kHB-hc-CY5" firstAttribute="centerY" secondItem="EbR-gU-YBO" secondAttribute="centerY" id="17U-hP-XiO"/>
                                            <constraint firstItem="EbR-gU-YBO" firstAttribute="height" secondItem="BDK-vE-tUk" secondAttribute="height" id="2Kc-yZ-8EB"/>
                                            <constraint firstItem="QjG-7X-1Sa" firstAttribute="width" secondItem="EbR-gU-YBO" secondAttribute="width" id="3bm-Ya-pZA"/>
                                            <constraint firstItem="EbR-gU-YBO" firstAttribute="leading" secondItem="BDK-vE-tUk" secondAttribute="leading" placeholder="YES" id="6E3-jg-Ku3"/>
                                            <constraint firstItem="EbR-gU-YBO" firstAttribute="centerY" secondItem="BDK-vE-tUk" secondAttribute="centerY" id="8hy-lM-jcp"/>
                                            <constraint firstAttribute="trailing" secondItem="kHB-hc-CY5" secondAttribute="trailing" placeholder="YES" id="HQQ-As-qWL"/>
                                            <constraint firstItem="QjG-7X-1Sa" firstAttribute="height" secondItem="EbR-gU-YBO" secondAttribute="height" id="HRx-Ud-bkP"/>
                                            <constraint firstItem="5IF-rt-c8a" firstAttribute="height" secondItem="EbR-gU-YBO" secondAttribute="height" id="L5Q-Ee-ZSx"/>
                                            <constraint firstItem="QjG-7X-1Sa" firstAttribute="leading" secondItem="EbR-gU-YBO" secondAttribute="trailing" placeholder="YES" id="NMH-3d-uhZ"/>
                                            <constraint firstItem="5IF-rt-c8a" firstAttribute="centerY" secondItem="EbR-gU-YBO" secondAttribute="centerY" id="Nma-OU-J25"/>
                                            <constraint firstItem="kHB-hc-CY5" firstAttribute="height" secondItem="EbR-gU-YBO" secondAttribute="height" id="WXs-c8-mbJ"/>
                                            <constraint firstItem="kHB-hc-CY5" firstAttribute="width" secondItem="EbR-gU-YBO" secondAttribute="width" id="Y87-Ph-wOu"/>
                                            <constraint firstAttribute="height" constant="50" id="YRG-m1-zQ0"/>
                                            <constraint firstItem="5IF-rt-c8a" firstAttribute="leading" secondItem="QjG-7X-1Sa" secondAttribute="trailing" placeholder="YES" id="cTU-cd-6gQ"/>
                                            <constraint firstItem="QjG-7X-1Sa" firstAttribute="centerY" secondItem="EbR-gU-YBO" secondAttribute="centerY" id="fd7-iE-WFg"/>
                                            <constraint firstItem="5IF-rt-c8a" firstAttribute="width" secondItem="EbR-gU-YBO" secondAttribute="width" id="jAO-LF-jvX"/>
                                            <constraint firstItem="kHB-hc-CY5" firstAttribute="leading" secondItem="5IF-rt-c8a" secondAttribute="trailing" placeholder="YES" id="kNi-xf-omT"/>
                                        </constraints>
                                    </view>
                                    <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="smc-cM-nTo">
                                        <rect key="frame" x="281" y="40" width="30" height="30"/>
                                        <color key="backgroundColor" red="0.75406885150000003" green="0.75408679249999999" blue="0.75407713649999997" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                        <state key="normal" title=" ">
                                            <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                                        </state>
                                        <connections>
                                            <action selector="showHideTapped:" destination="Msu-cJ-7P1" eventType="touchUpInside" id="spY-Hq-Xeu"/>
                                        </connections>
                                    </button>
                                </subviews>
                                <color key="backgroundColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
                                <constraints>
                                    <constraint firstAttribute="trailing" secondItem="smc-cM-nTo" secondAttribute="trailing" constant="4" id="3Ry-gN-0Z4"/>
                                    <constraint firstItem="smc-cM-nTo" firstAttribute="leading" secondItem="BDK-vE-tUk" secondAttribute="trailing" constant="4" id="I2C-fT-Op3"/>
                                    <constraint firstItem="smc-cM-nTo" firstAttribute="centerY" secondItem="tXi-AX-zDz" secondAttribute="centerY" id="Mmb-uk-L5E"/>
                                    <constraint firstItem="BDK-vE-tUk" firstAttribute="leading" secondItem="tXi-AX-zDz" secondAttribute="leading" constant="4" id="NXB-2K-Egb"/>
                                    <constraint firstAttribute="height" constant="110" id="inu-kU-GH9"/>
                                    <constraint firstItem="BDK-vE-tUk" firstAttribute="centerY" secondItem="tXi-AX-zDz" secondAttribute="centerY" id="kDF-XJ-qkj"/>
                                </constraints>
                            </view>
                        </subviews>
                        <color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
                        <constraints>
                            <constraint firstItem="tXi-AX-zDz" firstAttribute="leading" secondItem="12L-io-1Iw" secondAttribute="leading" constant="30" id="30d-ds-ZVg"/>
                            <constraint firstItem="12L-io-1Iw" firstAttribute="trailing" secondItem="tXi-AX-zDz" secondAttribute="trailing" constant="30" id="ofy-ZY-LjW"/>
                            <constraint firstItem="tXi-AX-zDz" firstAttribute="centerY" secondItem="Efg-NM-r2G" secondAttribute="centerY" id="rtS-1o-e1I"/>
                        </constraints>
                        <viewLayoutGuide key="safeArea" id="12L-io-1Iw"/>
                    </view>
                    <connections>
                        <outlet property="buttonsContainer" destination="BDK-vE-tUk" id="qkA-Rn-M8Z"/>
                        <outlet property="calendarContainer" destination="kHB-hc-CY5" id="red-ot-mmb"/>
                        <outlet property="cameraContainer" destination="QjG-7X-1Sa" id="P94-ES-YRb"/>
                        <outlet property="micContainer" destination="5IF-rt-c8a" id="ipp-Bt-B2m"/>
                        <outlet property="pencilContainer" destination="EbR-gU-YBO" id="Fr9-7f-BIa"/>
                    </connections>
                </viewController>
                <placeholder placeholderIdentifier="IBFirstResponder" id="Y2G-rV-gCJ" userLabel="First Responder" sceneMemberID="firstResponder"/>
            </objects>
            <point key="canvasLocation" x="-478" y="2845"/>
        </scene>
    </scenes>
</document>
  

Результат (нажатие серой кнопки приведет к анимации ввода и вывода кнопок):

введите описание изображения здесь

Комментарии:

1. Это было именно то, что я искал. Спасибо.