web-dev-qa-db-ja.com

パースペクティブトランスフォームをUIViewに適用するにはどうすればよいですか?

UIViewで遠近法変換を実行しようとしています(カバーフローで見られるような)

誰でもこれが可能かどうか知っていますか?

私はCALayerを使用して調査し、すべての実用的なプログラマーCore Animationポッドキャストを実行しましたが、iPhoneでこの種の変換を作成する方法についてはまだ明確ではありません。

ヘルプ、ポインタ、またはコードスニペットの例は本当にありがたいです!

198
Nick Cartwright

Benが言ったように、UIView'sを使用してCATransform3Dを使用して、layer'srotationを実行する必要があります。 ここで説明 のようにパースペクティブを機能させるコツは、CATransform3D(m34)のマトリックスcellsの1つに直接アクセスすることです。マトリックス数学は私のものではなかったので、なぜこれが機能するのかを正確に説明することはできませんが、機能します。最初の変換ではこの値を負の分数に設定してから、レイヤー回転変換をそれに適用する必要があります。また、次のこともできるはずです。

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

回転ごとに最初からレイヤー変換を再構築します。

この完全な例(コード付き)は here にあります。ここでは、Bill Dudneyの例に基づいて、いくつかのCALayersにタッチベースの回転とスケーリングを実装しています。ページの一番下にあるプログラムの最新バージョンは、この種のパースペクティブ操作を実装しています。コードは、読みやすくする必要があります。

応答で参照するsublayerTransformは、UIView'sCALayerのサブレイヤーに適用される変換です。サブレイヤーがなくても心配する必要はありません。回転している1つのレイヤー内に2つのCALayersが含まれているため、この例ではsublayerTransformを使用しています。

325
Brad Larson

UIViewの変換プロパティに直接適用されるCore Graphics(Quartz、2Dのみ)変換のみを使用できます。 coverflowで効果を得るには、CATransform3Dを使用する必要があります。これは3D空間に適用されるため、目的のパースビューを提供できます。ビューではなくレイヤーにのみCATransform3Dを適用できるため、このためにレイヤーに切り替える必要があります。

Xcodeに付属の「CovertFlow」サンプルをご覧ください。これはMac専用です(つまり、iPhone用ではありません)が、多くの概念はうまく伝わります。

7
Ben Gottlieb

Bradの回答に追加し、具体的な例を提供するために、同様のトピックに関する別の投稿で 自分の回答 を借りています。私の答えでは、シンプルなSwiftプレイグラウンドを作成しました。これは、 ダウンロードして で遊ぶことができます。単純なレイヤーの階層を持つUIViewの場合、transformsublayerTransformを使用した場合の結果は異なります。見てみな。

投稿の画像の一部を次に示します。

.sublayerTransform option

.transform option

3
HuaTham

ICarousel SDKを使用して、正確なカルーセル効果を取得できます。

素晴らしい無料のiCarouselライブラリを使用して、iOSでインスタントカバーフローエフェクトを取得できます。 https://github.com/nicklockwood/iCarousel からダウンロードし、ブリッジングヘッダーを追加することでXcodeプロジェクトに簡単にドロップできます(Objective-Cで記述されています)。

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プロトコルの両方に準拠していることを確認してください。

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
    }
0
Tech