Как преобразовать CATransform3DTranslate в CGAffineTransform, чтобы он мог имитировать представление карусели - PullRequest
1 голос
/ 07 июля 2019

Мой вопрос касается того, как имитировать этот вид карусели Youtube видео только с использованием UIView, а не его слоя или CALayer , что означает на самом деле преобразование UIViews в себя.

Я нашел вопрос переполнения стека, который на самом деле способен конвертировать CATransform3D в CGAffineTransform .Это было написано неким гением здесь в качестве ответа, но моя проблема немного уникальна.

Анимация, которую вы видите ниже, использует CALayer для создания.Мне нужно создать ту же анимацию, но трансформировать UIView вместо ее слоя.

Как это должно выглядеть:

enter image description here

Код (Создает анимацию с использованием слоев): Это берет карту изображения, которая является CALayer () с прикрепленным к ней изображением, и преобразует, что помещает ее в карусель изображений.

Примечание: turnCarousel () также вызывается, когда пользователь перемещается, перемещая / анимируя карусель.

 let transformLayer = CATransformLayer()

 func turnCarousel() {
    guard let transformSubLayers = transformLayer.sublayers else {return}

    let segmentForImageCard = CGFloat(360 / transformSubLayers.count)

    var angleOffset = currentAngle

    for layer in transformSubLayers {
        var transform = CATransform3DIdentity
        transform.m34 = -1 / 500

        transform = CATransform3DRotate(transform, degreeToRadians(deg: angleOffset), 0, 1, 0)
        transform = CATransform3DTranslate(transform, 0, 0, 175)

        CATransaction.setAnimationDuration(0)

        layer.transform = transform

        angleOffset += segmentForImageCard
    }
}

Что это выглядит в данный моментКак: enter image description here

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

Для этого я использовал UIImageView в качестве базового вида для карусели, а затем добавил еще UIImageViews в качествекарты к нему.Итак, теперь мы пытаемся выполнить преобразование UIImageView / UIView

Код:

  var carouselTestView = UIImageView()

  func turnCarouselTestCarousel() {
    let segmentForImageCard = CGFloat(360 / carouselTestView.subviews.count)

    var angleOffset = currentAngleTestView

    for subview in carouselTestView.subviews {
        var transform2 = CATransform3DIdentity
        transform2.m34 = -1 / 500

        transform2 = CATransform3DRotate(transform2, degreeToRadians(deg: angleOffset), 0, 1, 0)
        transform2 = CATransform3DTranslate(transform2, 0, 0, 175)

        CATransaction.setAnimationDuration(0)

        // m13, m23, m33, m43 are not important since the destination is a flat XY plane.
        // m31, m32 are not important since they would multiply with z = 0.
        // m34 is zeroed here, so that neutralizes foreshortening. We can't avoid that.
        // m44 is implicitly 1 as CGAffineTransform's m33.
        let fullTransform: CATransform3D = transform2
        let affine = CGAffineTransform(a: fullTransform.m11, b: fullTransform.m12, c: fullTransform.m21, d: fullTransform.m22, tx: fullTransform.m41, ty: fullTransform.m42)

        subview.transform = affine

        angleOffset += segmentForImageCard
    }
}

добавлено вспомогательное изображение, которое фактически составляет карусельс этой функцией, которая просто проходит цикл for с именем 1 ... 6 в моей папке ресурсов.

Код:

 func CreateCarousel() {

    carouselTestView.frame.size = CGSize(width: self.view.frame.width, height: self.view.frame.height / 2.9)
    carouselTestView.center = CGPoint(self.view.frame.width * 0.5, self.view.frame.height * 0.5)
    carouselTestView.alpha = 1.0
    carouselTestView.backgroundColor = UIColor.clear
    carouselTestView.isUserInteractionEnabled = true
    self.view.insertSubview(carouselTestView, at: 0)

    for i in 1 ... 6 {
        addImageCardTestCarousel(name: "\(i)")
    }

    // Set the carousel for the first time. So that now we can see it like an actual carousel animation
    turnCarouselTestCarousel()

    let panGestureRecognizerTestCarousel = UIPanGestureRecognizer(target: self, action: #selector(self.performPanActionTestCarousel(recognizer:)))
    panGestureRecognizerTestCarousel.delegate = self
    carouselTestView.addGestureRecognizer(panGestureRecognizerTestCarousel)
  }

Функция addImageCardTestCarousel находится здесь:

Код:

    func addImageCardTestCarousel(name: String) {

    let imageCardSize = CGSize(width: carouselTestView.frame.width / 2, height: carouselTestView.frame.height)
    let cardPanel = UIImageView()
    cardPanel.frame.size = CGSize(width: imageCardSize.width, height: imageCardSize.height)
    cardPanel.frame.origin = CGPoint(carouselTestView.frame.size.width / 2 - imageCardSize.width / 2 , carouselTestView.frame.size.height / 2 - imageCardSize.height / 2)
    guard let imageCardImage = UIImage(named: name) else {return}
    cardPanel.image = imageCardImage
    cardPanel.contentMode = .scaleAspectFill
    cardPanel.layer.masksToBounds = true
    cardPanel.layer.borderColor = UIColor.white.cgColor
    cardPanel.layer.borderWidth = 1
    cardPanel.layer.cornerRadius = cardPanel.frame.height / 50
    carouselTestView.addSubview(cardPanel)
}

Цель:

Цель этого в том, что я хочусоздать пользовательский интерфейс, который может использовать UIViews на вращающихся картах, которые вы видите, и CALayer не может добавить UIView в качестве подпредставления.Он может только добавить слой UIView к своему собственному слою.Поэтому для решения этой проблемы мне нужно на самом деле добиться этой анимации с помощью UIViews, а не CALayers.

1 Ответ

0 голосов
/ 08 июля 2019

Я решил, что вид, который находится позади переднего вида, фактически захватывает все касание, даже если вы дотронетесь до карты прямо спереди, задняя карта предотвратит касания передней карты.Итак, я сделал функцию, которая может вычислять.Какие виды в передней.Чем отключить и включить касания на потом.Это похоже на то, что когда 2 карты сложены друг на друга, карта на оборотной стороне остановит карту с передней стороны / userInteraction.

Код:

   func DetermineFrontViews(view subview: UIView, angle angleOffset: CGFloat) {

    let looped = Int(angleOffset / 360) // must round down to Int()
    let loopSubtractingReset = CGFloat(360 * looped) // multiply 360 how ever many times we have looped

    let finalangle = angleOffset - loopSubtractingReset

    if (finalangle >= -70 && finalangle <= 70) || (finalangle >= 290) || (finalangle <= -260) {

        print("In front of view")

        if subview.isUserInteractionEnabled == false {
            subview.isUserInteractionEnabled = true
        }
    } else {
        print("Back of view")
        if subview.isUserInteractionEnabled == true {
            subview.isUserInteractionEnabled = false
        }
    }
}

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

    if subview.layer.name == "1" {
            DetermineFrontViews(view: subview, angle: angleOffset)
        }
...