UIView에 Perspective 변환을 어떻게 적용합니까?


199

UIView에서 원근 변환을 수행하려고합니다 (예 : coverflow)

이것이 가능한지 아는 사람이 있습니까?

나는 CALayer실용적인 프로그래머 인 Core Animation 팟 캐스트를 사용 하고 조사 했지만 iPhone에서 이런 종류의 변형을 만드는 방법에 대해서는 아직 명확하지 않습니다.

모든 도움, 포인터 또는 예제 코드 스 니펫은 정말 감사하겠습니다!


이것이 u에 적합한 지 확실하지 않지만 애니메이션을 만들 때 m14가 나에게 더 낫다는 것을 알았습니다. 참조를 위해 :)
b123400

감사! -어떤 값을 주나요?
Nick Cartwright

1
m14를 설정하면 실제로 X 축의 뷰 프러스 텀이 이상하게 왜곡됩니다. 수학은 완벽하게 유효하지만 일반적인 경우에는 혼란 스러울 것입니다.
푹신한

m34 필드에 대한 철저한 설명을 포함하여 CALayer 3D 변형 및 관점에 대한 매우 훌륭한 기사는이 훌륭한 기사에서 찾을 수 있습니다. 핵심 애니메이션 3d 모델
Markus

답변:


329

Ben이 말했듯이 UIView'sa CATransform3D를 사용하여 레이어를 사용 하여을 수행해야합니다 layer's rotation. 여기설명 된 것처럼 원근법을 작동시키는 요령 cellsCATransform3D(m34) 의 행렬 중 하나에 직접 액세스하는 것입니다 . 매트릭스 수학은 결코 내 일이 아니기 때문에 이것이 왜 효과가 있는지 정확히 설명 할 수는 없지만 그렇게합니다. 초기 변환의 경우이 값을 음의 분수로 설정 한 다음 레이어 회전 변환을 적용해야합니다. 또한 다음을 수행 할 수 있어야합니다.

목표 -C

UIView *myView = [[self subviews] objectAtIndex:0];
CALayer *layer = myView.layer;
CATransform3D rotationAndPerspectiveTransform = CATransform3DIdentity;
rotationAndPerspectiveTransform.m34 = 1.0 / -500;
rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 45.0f * M_PI / 180.0f, 0.0f, 1.0f, 0.0f);
layer.transform = rotationAndPerspectiveTransform;

스위프트 5.0

if let myView = self.subviews.first {
    let layer = myView.layer
    var rotationAndPerspectiveTransform = CATransform3DIdentity
    rotationAndPerspectiveTransform.m34 = 1.0 / -500
    rotationAndPerspectiveTransform = CATransform3DRotate(rotationAndPerspectiveTransform, 45.0 * .pi / 180.0, 0.0, 1.0, 0.0)
    layer.transform = rotationAndPerspectiveTransform
}

각 회전마다 레이어 변형을 처음부터 다시 작성합니다.

Bill Dudney의 예제를 기반으로 터치 기반 회전 및 스케일링을 구현 한 코드의 전체 예제는 여기 에서 확인할 수 있습니다 CALayers. 페이지 맨 아래에있는 최신 버전의 프로그램은 이러한 종류의 원근법 조작을 구현합니다. 코드는 읽기 편해야합니다.

sublayerTransform당신이 당신의 응답을 참조는 당신의 서브 레이어에 적용되는 변환입니다 UIView's CALayer. 하위 계층이 없으면 걱정하지 마십시오. 예제에서 sublayerTransform을 사용하는 이유 CALayers는 하나의 레이어 안에 두 개의 회전 이 있기 때문 입니다.


1
감사합니다 브래드-당신은 스타입니다. 추신 : 훌륭한 답변을 늦게 늦어서 죄송합니다. 새긴 ​​금.
Nick Cartwright

LHS, 때로는 RHS 인 이미지의 절반을 잃어 버리는 것을 제외하고는 잘 작동합니다.
iPadDeveloper2011

18
@ iPadDeveloper2011-홀수입니다. 같은 평면에 다른 불투명 한 뷰나 레이어가있을 때 뷰나 레이어를 회전하려고합니다. 그런 다음 화면에서 떨어진 뷰 또는 레이어의 절반이이 다른 뷰 아래에있게되어 숨겨집니다. 이를 방지하기 위해 뷰 계층 구조를 재정렬하거나 zPosition 속성을 사용하여 전경 뷰를 잘라낸 뷰 위로 전경 뷰를 충분히 이동할 수 있습니다.
Brad Larson

26
참고로, m34 셀이 원근 변환에 영향을 미치는 이유는 월드 공간 Z 값이 클립 공간 W 값 (원근 투영에 사용됨)에 매핑되는 방식에 영향을주는 매트릭스의 셀이기 때문입니다. 자세한 내용은 동종 변환 행렬을 읽으십시오.
푹신한

2
@uerceg-당신은 별도의 질문으로 질문하고 싶을 것입니다.
Brad Larson

7

UIView의 변형 속성에 직접 적용된 Core Graphics (Quartz, 2D 만) 변형 만 사용할 수 있습니다. Coverflow에서 효과를 얻으려면 3D 공간에 적용되는 CATransform3D를 사용해야하므로 원하는 투시도를 제공 할 수 있습니다. 뷰가 아닌 레이어에만 CATransform3D를 적용 할 수 있으므로이를 위해 레이어로 전환해야합니다.

Xcode와 함께 제공되는 "CovertFlow"샘플을 확인하십시오. 그것은 맥 전용 (즉, iPhone이 아닌)이지만 많은 개념이 잘 전달됩니다.


성공하지 않고 / Developer / Examples에서이 커버 플로우 샘플을 찾고 있는데 어디에서 찾을 수 있습니까?
Alex

실제로 "CovertFlow"이고 / Developer / Examples / Quartz / Core Animation / "
Ben Gottlieb

3

Brad의 답변에 추가하고 구체적인 예를 제공하기 위해 비슷한 주제에 대한 다른 게시물의 내 답변 에서 빌려 왔습니다 . 내 대답에, 나는 간단한 스위프트를 생성 놀이터 당신이 할 수있는 다운로드 플레이 내가 층의 간단한 계층 구조와 UIView의 관점 효과를 만드는 방법을 보여줍니다, 그리고 내가 사용 사이의 서로 다른 결과를 보여줍니다 곳 transformsublayerTransform. 확인 해봐.

게시물의 일부 이미지는 다음과 같습니다.

.sublayerTransform 옵션

.transform 옵션


코드는 텍스트로 게시해야합니다. 이미지에서 코드를 읽는 것은 정말 어렵습니다. 또한 그림의 코드는 참조, 복사 또는 검색 할 수 없습니다.
rmaddy

@rmaddy, Bitbucket 링크에서 사용할 수있는 코드가 있습니다.
HuaTham

링크는 시간이 지남에 따라 나빠집니다. 중요한 코드를 텍스트로 직접 답변에 직접 붙여 넣는 것이 가장 좋습니다.
rmaddy

-1

iCarousel SDK를 사용하여 정확한 캐 러셀 효과를 얻을 수 있습니다.

놀라운 무료 iCarousel 라이브러리를 사용하여 iOS에서 즉각적인 Cover Flow 효과를 얻을 수 있습니다. https://github.com/nicklockwood/iCarousel 에서 다운로드 하여 브리징 헤더 (Objective-C로 작성)를 추가하여 Xcode 프로젝트에 상당히 쉽게 드롭 할 수 있습니다.

Objective-C 코드를 Swift 프로젝트에 추가하지 않은 경우 다음 단계를 수행하십시오.

  • iCarousel을 다운로드하고 압축을 풉니 다
  • 압축을 푼 폴더로 이동하여 iCarousel 하위 폴더를 연 다음 iCarousel.h 및 iCarousel.m을 선택하고 프로젝트 탐색으로 드래그합니다. Xcode의 왼쪽 창입니다. Info.plist 바로 아래가 좋습니다.
  • "필요한 경우 항목 복사"를 선택하고 완료를 클릭하십시오.
  • Xcode는 "Objective-C 브리징 헤더를 구성 하시겠습니까?"라는 메시지를 표시합니다. "브리지 헤더 만들기"를 클릭하십시오. 프로젝트에 YourProjectName-Bridging-Header.h라는 새 파일이 나타납니다.
  • 이 줄을 파일에 추가하십시오 : #import "iCarousel.h"
  • 프로젝트에 iCarousel을 추가하면 사용할 수 있습니다.
  • iCarouselDelegate 및 iCarouselDataSource 프로토콜을 모두 준수해야합니다.

스위프트 3 샘플 코드 :

    override func viewDidLoad() {
      super.viewDidLoad()
      let carousel = iCarousel(frame: CGRect(x: 0, y: 0, width: 300, height: 200))
      carousel.dataSource = self
      carousel.type = .coverFlow
      view.addSubview(carousel) 
    }

   func numberOfItems(in carousel: iCarousel) -> Int {
        return 10
    }

    func carousel(_ carousel: iCarousel, viewForItemAt index: Int, reusing view: UIView?) -> UIView {
        let imageView: UIImageView

        if view != nil {
            imageView = view as! UIImageView
        } else {
            imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 128, height: 128))
        }

        imageView.image = UIImage(named: "example")

        return imageView
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.