パースペクティブ変換をUIViewに適用するにはどうすればよいですか?


199

UIViewでパースペクティブ変換を実行したい(カバーフローで見られるような)

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

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

ヘルプ、ポインタ、またはサンプルのコードスニペットをいただければ幸いです。


これがuに適しているかどうかはわかりませんが、アニメーションを作成すると、m14のほうが適していることがわかりました。参考までに:)
b123400

ありがとう!-あなたはこれにどの値を与えますか?
Nick Cartwright

1
m14を設定することで、実際にX軸上の錐台を奇妙に歪めています。数学は完全に有効ですが、一般的なケースでは混乱を招きます。
ふわふわ

m34フィールドの詳細な説明を含む、CALayer 3D変換とパースペクティブに関する非常に優れた記事は、この優れた記事にあります:core-animation-3d-model
Markus

回答:


329

ベンが言っUIView'sCATransform3Dように、を実行するためにa を使用して、レイヤーを操作する必要がありlayer's rotationます。ここ説明するように、パースペクティブを機能させるコツcellsは、CATransform3D(m34)のマトリックスの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
}

これにより、回転ごとにレイヤー変換がゼロから再構築されます。

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

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


1
ありがとうブラッド-あなたはスターです。PS:あなたの素晴らしい答えが遅くなってすみません!ニック。
Nick Cartwright

これは私にとってはうまく機能しますが、(垂直分割に沿って)画像の半分を失うように見える場合があります-LHSの場合もあれば、RHSの場合もあります。
iPadDeveloper2011

18
@ iPadDeveloper2011-同じ平面に別の不透明なビューまたはレイヤーがあるときに、ビューまたはレイヤーを回転させようとしている可能性があります。画面から突出するビューまたはレイヤーの半分は、この他のビューの下にあり、したがって非表示になります。これを回避するためにビュー階層を並べ替えるか、zPositionプロパティを使用して、フォアグラウンドビューを、それを遮っているビューの上に十分に高く移動することができます。
ブラッド・ラーソン

26
参考までに、m34セルが透視変換に影響を与える理由は、ワールドスペースZ値がクリップスペースW値(透視投影に使用される)にマップする方法に影響を与えるマトリックスのセルです。詳細については、同種の変換行列を参照してください。
ふわふわした

2
@uerceg-別の質問として、できれば何が起こっているのか、何が起こりたいのかを説明する画像を使って質問したいと思うでしょう。
ブラッド・ラーソン

7

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

Xcodeに付属する「CovertFlow」サンプルを確認してください。これはMac専用です(つまり、iPhone向けではありません)が、多くの概念はうまく移行します。


/ coverer / Examplesでこのカバーフローのサンプルを探していますが、成功しません。どこにありますか?
Alex

それは実際には「CovertFlow」であり、/ Developer / Examples / Quartz / Core Animation /にあります
Ben Gottlieb

3

ブラッドの答えに加え、具体的な例を示すために、私は同様のトピックに関する別の投稿で自分の答えを借りています。私の答えでは、私はあなたができることを、簡単なスウィフトの遊び場を作成してダウンロードしてプレイ私は層の簡単な階層でのUIViewの遠近効果を作成する方法を示し、そして私が使用しての間で異なる結果を示している、transformとしますsublayerTransform。見てみな。

これが投稿の画像の一部です。

.sublayerTransformオプション

.transformオプション


コードはテキストとして投稿する必要があります。画像のコードを読み取るのは本当に難しいです。さらに、画像内のコードは参照、コピー、または検索できません。
rmaddy 2018

@rmaddy、私は私の答えのBitbucketリンクで利用可能なコードを持っています。
HuaTham 2018

時間の経過とともにリンクが機能しなくなります。重要なコードをテキストとして直接回答に貼り付けることをお勧めします。
rmaddy 2018

-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ブリッジヘッダーを構成しますか?」というメッセージを表示します。[Create Bridging Header]をクリックします。プロジェクトに、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
    }
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.