1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

えーえすAdvent Calendar 2024

Day 22

Storyboardを少しずつSwiftUIに置き換えていく

Last updated at Posted at 2024-12-21

はじめに

昨今SwiftUIブームがきており、StoryboardをSwiftUIに置き換える という動きが多いです。
また、SwiftUIの学習に伴って個人開発のアプリに部分的にSwiftUIを取り入れていく、という人も多いのではないでしょうか。

そこで、見た目をSwiftUIで、処理をUIKitで 記述する方法を考えます。

SwiftUIの画面を作ろう

今回は押されたら小さくなるボタンを作ります。SwiftUIでの作り方はこのようになります。

CameraButton
struct CameraButton: View {
    var onButtonPressed: () -> Void

    @State private var pressing = false

    var body: some View {
        Circle()
            .fill(Color.white)
            .frame(width: pressing ? 60 : 80, height: pressing ? 60 : 80)
            .shadow(radius: 10)
            .onLongPressGesture(minimumDuration: 0, pressing: { pressing in
                self.pressing = pressing
                if !pressing {
                    onButtonPressed()
                }
            }, perform: {})
    }
}

Simulator Screenshot - iPhone 16 Pro - 2024-12-21 at 23.05.14.png

ここでonButtonPressedは、ボタンが押された時の処理をUIKit側で記述するためのパーツです。

このように処理だけを引き渡すことで、Storyboard側のアーキテクチャを大きく変えることなくSwiftUIに移行していけます。

HostingControllerを使おう

次はUIKit側の画面を作ります。

ViewController
import UIKit
import SwiftUI

class ViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let cameraButton = CameraButton(onButtonPressed: {
            self.cameraButtonTapped()
        })
        
        let hostingController = UIHostingController(rootView: cameraButton)
        addChild(hostingController)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        view.addSubview(hostingController.view)
        hostingController.didMove(toParent: self)
        
        NSLayoutConstraint.activate([
            hostingController.view.centerXAnchor.constraint(equalTo: view.centerXAnchor),
            hostingController.view.centerYAnchor.constraint(equalTo: view.centerYAnchor),
            hostingController.view.widthAnchor.constraint(equalToConstant: 100),
            hostingController.view.heightAnchor.constraint(equalToConstant: 100)
        ])
    }
    
    private func cameraButtonTapped() {
        print("Camera button tapped")
    }
}

このcameraButtonTappedに押された時の処理を記入することで、処理を呼び出すことができます!

おまけ

SwiftUIの強みの一つはアニメーションの充実なので、以下のようにアニメーションをつけてもいいでしょう。

CameraButton
struct CameraButton: View {
    var onButtonPressed: () -> Void

    @State private var pressing = false

    var body: some View {
        Circle()
            .fill(Color.white)
            .frame(width: pressing ? 60 : 80, height: pressing ? 60 : 80)
            .shadow(radius: 10)
            .scaleEffect(pressing ? 0.9 : 1.0)
            .animation(.spring(), value: pressing)
            .onLongPressGesture(minimumDuration: 0, pressing: { pressing in
                self.pressing = pressing
                if !pressing {
                    onButtonPressed()
                }
            }, perform: {})
    }
}

まとめ

SwiftUIとStoryboardの長所を両方組み合わせて良い開発をしていきましょう!

1
2
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
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?