15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

swiftUIで画面回転に対応してみる

Last updated at Posted at 2019-09-04

やってみたこと

  • 回転によるレイアウト変更時にアニメーションを入れてみる
  • 画面回転の対応

ssss.gif

まずレイアウト変更時のアニメーションから

スクリーンショット 2019-09-04 12.28.43.png
VStack {
  Text("Top And Left")
    .padding(50)
  Text("Bottom And Right")
    .padding(50)
}

まずこんな感じのレイアウトを用意しました。

次は、VStackとHStackを用意して

  • 端末が縦: VStackで表示
  • 端末が横: HStackで表示

にしたいと思います。

まずは試しに縦横の変数を用意して、ボタンで切り替えてみたいと思います

とりあえず横縦の管理は

@State var isPortrait = true

これで行います。

続けて、フラグを切り替えるためのテスト用のボタンを配置しました。

VStack {
    if isPortrait {
        VStack {
            Text("Top And Left")
                .padding(50)
            Text("Bottom And Right")
                .padding(50)
        }
    } else {
        HStack {
            Text("Top And Left")
                .padding(30)
            Text("Bottom And Right")
                .padding(30)
        }
    }
    Button(action: {
        self.isPortrait.toggle()
    }) {
        Text("回転したとき")
    }.padding(.all)
}

これでボタンをタップしたらisPortraitが切り替わり、VStackとHStackの表示が切り替わります。

いよいよ最後のステップ、アニメーション追加です。

Button(action: {
    withAnimation {
        self.isPortrait.toggle()
    }
})

withAnimationを追加するだけで、アニメーションしてくれます。

アニメーションをカスタマイズしたい場合は、VStackとHStackに transition でアニメーションを指定するだけです。
swiftui animation tutorial

とても細かいところまでこだわろうとすると色々理解する必要がありますが、
何も知識がなくても簡単にできちゃうのはすごいですね。

画面の回転を検知してみる

参考にしたのはstackoverflowです。

まずは縦横情報をObservableObjectにしたいので、modelを作成します。

final class OrientationModel: ObservableObject {
    @Published var orientation: UIInterfaceOrientation = .unknown
}

次は定義したものを宣言

SceneDelegate.swift
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
    @ObservedObject(initialValue: OrientationModel()) var model: OrientationModel

次に画面回転をハンドリング

SceneDelegate.swift
func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {
    model.orientation = windowScene.interfaceOrientation
}

次は挙動を確認するためにViewを作成しました。

struct CheckOrient: View {
    @EnvironmentObject var model: OrientationModel
    var body: some View {
        Text(model.orientation.isLandscape ? "横" : "縦")
            .font(.title).bold()
    }
}

最後にSceneDelegateからmodelを渡すようにします。

SceneDelegate.swift
window.rootViewController = UIHostingController(rootView: CheckOrient().environmentObject(model))

これで回転したらラベルが切り替わることが確認出来ます。

最後の仕上げ

まずは最初に作ったContentViewの処理をOrientationModelに置き換えです。

ContentView.swift
struct ContentView: View {
    @EnvironmentObject var model: OrientationModel
    var body: some View {
        Group {
            if model.orientation.isPortrait {
                VStack {
                    Text("Top And Left")
                        .padding(50)
                    Text("Bottom And Right")
                        .padding(50)
                }
            } else {
                HStack {
                    Text("Top And Left")
                        .padding(30)
                    Text("Bottom And Right")
                        .padding(30)
                }
            }
        }
    }
}
SceneDelegate.swift
window.rootViewController = UIHostingController(rootView: ContentView().environmentObject(model))

これで画面回転でVStackとHStackの切り替えが完了しました。

アニメーションも加えてみる

SceneDelegate.swift
func windowScene(_ windowScene: UIWindowScene, didUpdate previousCoordinateSpace: UICoordinateSpace, interfaceOrientation previousInterfaceOrientation: UIInterfaceOrientation, traitCollection previousTraitCollection: UITraitCollection) {
    withAnimation {
        model.orientation = windowScene.interfaceOrientation
    }
}
ContentView.swift
var body: some View {
    VStack {  // <= これを最初はGroupにしたけど、そうするとアニメーションを自動でやってくれない
        if model.orientation.isPortrait {
            VStack {
                Text("Top And Left")
                    .padding(50)
                Text("Bottom And Right")
                    .padding(50)
            }
        } else {
            HStack {
                Text("Top And Left")
                    .padding(30)
                Text("Bottom And Right")
                    .padding(30)
            }
        }
    }
}

これで回転したときに、フェードアニメーションで中身が切り替わるようになりました!

その他

Groupだとアニメーションしてくれなくてちょっと焦りました。
なにか他の方法もありそうですね。
もっといい方法あれば教えて下さい!!

15
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?