Làm cách nào để áp dụng chuyển đổi phối cảnh cho UIView?


199

Tôi đang tìm cách thực hiện chuyển đổi phối cảnh trên một UIView (chẳng hạn như nhìn thấy trong dòng chảy)

Có ai biết nếu điều này là có thể?

Tôi đã điều tra bằng cách sử dụng CALayervà đã chạy qua tất cả các podcast lập trình Core Animation thực dụng, nhưng tôi vẫn chưa rõ về cách tạo loại biến đổi này trên iPhone.

Bất kỳ trợ giúp, con trỏ hoặc đoạn mã ví dụ sẽ được thực sự đánh giá cao!


Tôi không chắc điều này có phù hợp với bạn hay không nhưng khi tôi làm hoạt hình, tôi thấy m14 tốt hơn cho tôi Chỉ để tham khảo :)
b123400

Cảm ơn! - những giá trị nào bạn đưa ra điều này?
Nick Cartwright

1
Bằng cách đặt m14, bạn thực sự làm lệch hướng chế độ xem trên trục X một cách kỳ lạ. Toán học là hoàn toàn hợp lệ nhưng nó sẽ làm cho mọi thứ trở nên khó hiểu trong trường hợp chung.
lông mịn

Một bài viết rất, rất hay về chuyển đổi và phối cảnh 3D của CALayer, bao gồm giải thích cặn kẽ về trường m34, có thể được tìm thấy trong bài viết xuất sắc này: mô hình lõi-hoạt hình-3d
Markus

Câu trả lời:


329

Như Ben đã nói, bạn sẽ cần phải làm việc với UIView'slớp, sử dụng một CATransform3Dđể thực hiện layer's rotation. Mẹo để làm cho phối cảnh hoạt động, như được mô tả ở đây , là truy cập trực tiếp vào một trong các ma trận cellscủa CATransform3D(m34). Ma trận toán học chưa bao giờ là chuyện của tôi, vì vậy tôi không thể giải thích chính xác tại sao nó lại hoạt động, nhưng nó thì có. Bạn sẽ cần đặt giá trị này thành phân số âm cho biến đổi ban đầu của mình, sau đó áp dụng biến đổi xoay vòng lớp của bạn cho biến đổi đó. Bạn cũng có thể làm như sau:

Mục tiêu-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;

Swift 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
}

mà xây dựng lại biến đổi lớp từ đầu cho mỗi vòng quay.

Một ví dụ đầy đủ về điều này (có mã) có thể được tìm thấy ở đây , nơi tôi đã thực hiện xoay vòng dựa trên cảm ứng và nhân rộng trên một vài CALayersví dụ, dựa trên một ví dụ của Bill Dudney. Phiên bản mới nhất của chương trình, ở dưới cùng của trang, thực hiện loại hoạt động phối cảnh này. Mã phải đơn giản hợp lý để đọc.

Các sublayerTransformbạn tham khảo trong phản hồi của bạn là một biến đổi được áp dụng cho các lớp con của bạn UIView's CALayer. Nếu bạn không có bất kỳ lớp con nào, đừng lo lắng về nó. Tôi sử dụng sublayerTransform trong ví dụ của mình đơn giản vì có hai cái được CALayerschứa trong một lớp mà tôi đang xoay.


1
Cảm ơn Brad - bạn là một ngôi sao. PS: Xin lỗi vì đánh dấu vào câu trả lời tuyệt vời của bạn! Nick.
Nick Cartwright

Điều này hoạt động tốt đối với tôi, ngoại trừ tôi dường như mất một nửa hình ảnh của mình (dọc theo một bộ phận dọc) - đôi khi LHS, đôi khi RHS.
iPadDeveloper2011

18
@ iPadDeveloper2011 - Điều lạ lùng là, bạn đang cố gắng xoay chế độ xem hoặc lớp khi có một chế độ xem mờ hoặc lớp khác trên cùng một mặt phẳng. Một nửa chế độ xem hoặc lớp của bạn nằm ngoài màn hình sẽ nằm dưới chế độ xem khác này và do đó sẽ bị ẩn. Bạn có thể sắp xếp lại thứ bậc chế độ xem của mình để ngăn chặn điều này hoặc sử dụng thuộc tính zPocation để di chuyển chế độ xem nền trước của bạn đủ cao so với chế độ xem trước của nó.
Brad Larson

26
FYI, lý do tế bào m34 ảnh hưởng đến biến đổi phối cảnh là vì ô trong ma trận ảnh hưởng đến cách giá trị Z trong không gian thế giới ánh xạ tới giá trị W của không gian clip (được sử dụng để chiếu phối cảnh). Đọc về ma trận biến đổi đồng nhất để biết thêm thông tin.
lông mịn

2
@uerceg - Bạn sẽ muốn hỏi đó là một câu hỏi riêng biệt, tốt nhất là với hình ảnh minh họa những gì đang xảy ra và những gì bạn muốn xảy ra.
Brad Larson

7

Bạn chỉ có thể sử dụng các biến đổi Core Graphics (chỉ Quartz, 2D) được áp dụng trực tiếp cho thuộc tính biến đổi của UIView. Để có được các hiệu ứng trong coverflow, bạn sẽ phải sử dụng CATransform3D, được áp dụng trong không gian 3 chiều và do đó có thể cung cấp cho bạn chế độ xem phối cảnh mà bạn muốn. Bạn chỉ có thể áp dụng CATransform3D cho các lớp chứ không phải các chế độ xem, do đó bạn sẽ phải chuyển sang các lớp cho việc này.

Kiểm tra mẫu "CovertFlow" đi kèm với Xcode. Nó chỉ dành cho mac (tức là không dành cho iPhone), nhưng rất nhiều khái niệm chuyển giao tốt.


Tôi đang tìm kiếm mẫu coverflow này trong / Nhà phát triển / Ví dụ, nhưng không thành công, bạn có thể tìm thấy nó ở đâu?
Alex

Đó thực sự là "CovertFlow", và nó nằm trong / Nhà phát triển / Ví dụ / Quartz / Hoạt hình lõi / "
Ben Gottlieb

3

Để thêm vào câu trả lời của Brad và để cung cấp một ví dụ cụ thể, tôi mượn từ câu trả lời của chính tôi trong một bài đăng khác về một chủ đề tương tự. Trong câu trả lời của tôi, tôi đã tạo một sân chơi Swift đơn giản mà bạn có thể tải xuống và chơi cùng , trong đó tôi trình bày cách tạo hiệu ứng phối cảnh của UIView với hệ thống phân cấp các lớp đơn giản và tôi hiển thị các kết quả khác nhau giữa việc sử dụng transformsublayerTransform. Kiểm tra nó ra.

Dưới đây là một số hình ảnh từ bài viết:

tùy chọn .sublayerTransform

tùy chọn .transform


Mã nên được đăng dưới dạng văn bản. Thật sự rất khó để đọc mã trong một hình ảnh. Cộng với mã trong một hình ảnh không thể được tham chiếu, sao chép hoặc tìm kiếm.
rmaddy

@rmaddy, tôi có mã có sẵn trong liên kết Bitbucket trong câu trả lời của tôi.
HuaTham

Liên kết xấu đi theo thời gian. Luôn luôn tốt nhất để dán mã quan trọng dưới dạng văn bản trực tiếp vào câu trả lời.
rmaddy

-1

Bạn có thể nhận được hiệu ứng Carousel chính xác bằng iCarousel SDK.

Bạn có thể nhận được hiệu ứng Cover Flow ngay lập tức trên iOS bằng cách sử dụng thư viện iCarousel miễn phí và tuyệt vời. Bạn có thể tải xuống từ https://github.com/nicklockwood/iCarousel và thả nó vào dự án Xcode của bạn khá dễ dàng bằng cách thêm tiêu đề bắc cầu (được viết bằng Objective-C).

Nếu trước đó bạn chưa thêm mã Objective-C vào dự án Swift, hãy làm theo các bước sau:

  • Tải xuống iCarousel và giải nén nó
  • Đi vào thư mục bạn đã giải nén, mở thư mục con iCarousel của nó, sau đó chọn iCarousel.h và iCarousel.m và kéo chúng vào điều hướng dự án của bạn - đó là khung bên trái trong Xcode. Ngay bên dưới Info.plist là ổn.
  • Kiểm tra "Sao chép các mục nếu cần", sau đó nhấp vào Kết thúc.
  • Xcode sẽ nhắc bạn với thông báo "Bạn có muốn định cấu hình tiêu đề bắc cầu Objective-C không?" Nhấp vào "Tạo tiêu đề bắc cầu" Bạn sẽ thấy một tệp mới trong dự án của mình, được đặt tên là YourProjectName-Bridging-Header.h.
  • Thêm dòng này vào tệp: #import "iCarousel.h"
  • Khi bạn đã thêm iCarousel vào dự án của mình, bạn có thể bắt đầu sử dụng nó.
  • Hãy chắc chắn rằng bạn tuân thủ cả hai giao thức iCarouselDelegate và iCarouselDataSource.

Mã mẫu Swift 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
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.