SwiftUI

プログラミング
  1. SwiftUIプロジェクトの新規作成
  2. VStackとHStackとZStack
  3. Xcodeで定義されている要素の内容や説明をみる
  4. VStackのサンプルコード
  5. HStackのサンプルコード
  6. ZStackのサンプルコード
  7. SwiftUIでのprint関数の使い方
  8. SwiftUI内でのfor文の使い方
  9. SwiftUI内でのForEach文の使い方
  10. SwiftUIのボタンタップでテキストを変更する
  11. SwiftUIのリストの基本形
  12. SwiftUIのリストにセクションを追加
  13. SwiftUIのリストにナビバーを追加
  14. SwiftUIでナビゲーションによる画面遷移
  15. SwiftUIのモーダルビュー
  16. SwiftUIのモーダルフルスクリーン
  17. SwiftUIでナビバーを非表示にして、戻る。
  18. NavigationStackとよる画面遷移
  19. ButtonによるViewの入れ替え
  20. SwiftUIのCharts(iOS16〜)
  21. SwiftUIのChartsのBarMarkの積層(iOS16〜)
  22. SwiftUIのChartsのBarMarkの並列(iOS16〜)
  23. SwiftUIのテキストフィールド付きのAlert
  24. SwiftUIのPickerの横向き
  25. UIKit内でSwiftUIを表示する
  26. SwiftUIでの図形表示
  27. SwiftUIでつまんで動かす
  28. SwiftUIでの時間付きアニメーション
  29. SwiftUIのToggleによるアニメーション
  30. SwiftUIのボタンのアニメーション
  31. SwiftUIにおけるボタンエフェクト
  32. SwiftUIの.timingCurve
  33. SwiftUIのアニメーションの演習
  34. RealityKitとSwiftUIで、球体とボックスと平面を表示する。
  35. RealityKitとSwiftUIで、文字オブジェクトを表示する。
  36. RealityKitとSwiftUIで、usdzファイルを表示する。端末基準。
  37. RealityKitとSwiftUIで、usdzファイルを表示する。平面基準。
  38. RealityKitとSwiftUIで、3つのusdzファイルを表示する。平面基準。

SwiftUIプロジェクトの新規作成

1。Xcodeを起動する。

2。「Create New Project」をクリック。

3。上のタブのiOSを選択する。(iOSアプリを作成すれば、ipad、mac、VisionProでも配信できる)

3。「App」を選択し、「next」をクリック。

4。プロジェクトの項目を入力する。

  • Product Name:プロジェクト名。(自分がわかりやすいもの)
  • Team:開発者登録をしていないのであれば「None」のまま。登録していればApple IDの名前。
  • Organization Identifier:開発者(組織)の識別子。他と被らないように、自分のwebサイトアドレスを逆転したものが推奨されている。(例:com.xxxxxxxx)
  • Bundle Identifier:上の情報から自動生成される。後で変更することができる。アプリを配信する場合は、この識別子に対して配布証明書を作成する。
  • Interface:「SwiftUI」を選択。
  • Language:「Swift」
  • Strage:「None」
  • Host in CloudKit:初期設定のまま「チェックなし」
  • Include Tests:後から追加できるので「チェックなし」。テストファイルを作成するかどうか。
  • 「Next」をクリック。
  • Create Git repository on my Mac:「チェックなし」。リポジトリとは、ファイルやディレクトリの状態を記録する場所のこと。gitを使用しないのであれば、チェックを外す。
  • ファイルを保存先を選択し、「Create」をクリック。

5。Xcodeのプロジェクトが起動される。左上の再生ボタンで、シュミレーター上で動作させてみる。

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack {
            Image(systemName: "globe")
                .imageScale(.large)
                .foregroundStyle(.tint)
            Text("Hello, world!")
        }
        .padding()
    }
}

#Preview {
    ContentView()
}

VStackとHStackとZStack

1。レイアウトコードは基本的に「var body: some View」の中に書いていく。

2。VStack:縦方向(Vertical:垂直、Stack:積み重ね)

3。HStack:横方向(Horizon:水平)

4。ZStack:奥行き(Z:Z軸)

import SwiftUI

struct ContentView: View {
    var body: some View {
        
        //縦方向、上から下へ。
        VStack {
            Text("縦その1")
            Text("縦その2")
        }
        
        //横方向、左から右へ。
        HStack {
            Text("横その1")
            Text("横その2")
        }
        
        //奥行き方向、奥から手前へ。
        ZStack {
            Text("奥行きその1")
            Text("奥行きその2")
        }
        
    }
}


//右サイドのプレビューを実施している。
#Preview {
    ContentView()
}

Xcodeで定義されている要素の内容や説明をみる

「VStack」のコード上で、option + クリックすると、要素の説明と簡単なサンプルが表示される。

「VStack」のコード上で、command + クリックすると、要素を宣言しているコードが表示される。

VStackのサンプルコード

import SwiftUI

struct ContentView: View {
    var body: some View {
        VStack(alignment: .trailing, spacing: 10)
        {
            ForEach(1...10, id: \.self)
            {
                Text("Item \($0)")
            }
        }
    }
}


//右サイドのプレビューを実施している。
#Preview {
    ContentView()
}
 alignment(並べること)
(デフォルトは.center)
 .leading 左合わせ
 .center センター合わせ
 .trailing 右合わせ
 spacing(CGFloat)
(デフォルトはnull)
要素と要素の間の余白
マイナスにすると順番が逆になる

HStackのサンプルコード

import SwiftUI

struct ContentView: View {
    var body: some View {
        HStack(alignment: .top, spacing: 10
        ) {
            ForEach(1...5, id: \.self) {
                Text("Item \($0)")
            }
        }
    }
}


//右サイドのプレビューを実施している。
#Preview {
    ContentView()
}
 alignment(並べること)
(デフォルトは.center)
 .top 上合わせ
 .center センター合わせ
 .bottom 下合わせ
 .firstTextBaseline 最初の文字のベースラインを合わせる
 .lastTextBaseline 最後の文字のベースラインを合わせる
 spacing(CGFloat)
(デフォルトはnull)
要素と要素の間の余白
マイナスにすると順番が逆になる

ZStackのサンプルコード

import SwiftUI

struct ContentView: View {

        let colors: [Color] = [.red, .orange, .yellow, .green, .blue, .purple]


        var body: some View {
            ZStack {
                ForEach(0..<colors.count) {
                    Rectangle()
                        .fill(colors[$0])
                        .frame(width: 100, height: 100)
                        .offset(x: CGFloat($0) * 10.0,
                                y: CGFloat($0) * 10.0)
                }
            }
        }
}


//右サイドのプレビューを実施している。
#Preview {
    ContentView()
}

SwiftUIでのprint関数の使い方

import SwiftUI

struct ContentView: View {
    
    
    var body: some View {
        VStack {
        }
        .onAppear{
            //onAppear内であれば、print関数が使用できる。
            print("東京")
            //東京
        }
    }
}


#Preview {
    ContentView()
}

SwiftUI内でのfor文の使い方

import SwiftUI

struct ContentView: View {
    

    var body: some View {
        VStack {
        }
        .onAppear{
            //onAppear内であれば、print関数が使用できる。
            let stringArray:[String] = ["東京", "大阪", "福岡"]
            for number in stringArray.indices {
                print(stringArray[number])
            }
            //東京
            //大阪
            //福岡
        }
    }
}


#Preview {
    ContentView()
}

SwiftUI内でのForEach文の使い方

ForEach文で要素を繰り返し作成することができる。

「Non-constant range: not an integer range」のアラートが出たら、「, id: \.self」を追加する。

import SwiftUI

struct ContentView: View {
    
    let stringArray:[String] = ["東京", "大阪", "福岡","沖縄"]
    
    var body: some View {
        //VStack内は「@ViewBuilder」という、ビューを構築する部分なので、for文は使用できない。
        VStack {
            ForEach(stringArray.indices, id: \.self) {
                Text(stringArray[$0])
            }
        }
    }
}

#Preview {
    ContentView()
}

SwiftUIのボタンタップでテキストを変更する

import SwiftUI


var MainStringArray:[String] = ["東京", "大阪", "福岡","沖縄"]

struct ContentView: View {
    
    
    @State var bottomTap = false
    @State var buttonTitle = "en"
    @State var buttonBackGroundColor:Color = .mint
    @State var stringArray = MainStringArray
    
    
    var body: some View {
        VStack {
            
            //テキスト群
            ForEach(stringArray.indices, id: \.self) {
                Text(stringArray[$0])
            }
            .padding()
            
            
            //ボタン、枠線付き。
            Button(action: {
                buttonAction()
            }) {
                Text(buttonTitle)
                    .accentColor(Color.primary)
                    //.background(buttonBackGroundColor)
                    .padding()
                    .frame(width: UIScreen.main.bounds.size.width - 100, height: 40)
                    .shadow(color: .gray, radius: 1, x: 0, y: 0)
            }
            .padding()
            //.background(buttonBackGroundColor)
            .cornerRadius(20)
            .overlay(
                RoundedRectangle(cornerRadius: 20)
                .stroke(buttonBackGroundColor, lineWidth: 2)
            )
        }
    }
    
    
    //ボタンアクション
    private func buttonAction(){
        if bottomTap == false {
            bottomTap = true
            buttonTitle = "jp"
            MainStringArray = ["Tokyo", "Osaka", "Fukuoka","Okinawa"]
            stringArray = MainStringArray
            buttonBackGroundColor = .orange
        } else {
            bottomTap = false
            buttonTitle = "en"
            MainStringArray = ["東京", "大阪", "福岡","沖縄"]
            stringArray = MainStringArray
            buttonBackGroundColor = .mint
        }
        print(stringArray)
    }
}


#Preview {
    ContentView()
}

SwiftUIのリストの基本形

import SwiftUI

struct ContentView: View {
    
    let areaName = ["東京", "大阪", "福岡", "沖縄"]
    var body: some View {
        
        List {
            ForEach(areaName.indices, id: \.self) {
                Text(areaName[$0])
            }
        }
    }
}
    
#Preview {
    ContentView()
}

SwiftUIのリストにセクションを追加

import SwiftUI

struct ContentView: View {
    
    let areaName = ["東京", "大阪", "福岡", "沖縄"]
    var body: some View {
        
        List {
            Section(header: Text("日本の都市名")) {
                ForEach(areaName.indices, id: \.self) {
                    Text(areaName[$0])
                }
            }
        }
        .listStyle(InsetListStyle())//セルと近いセクションデザイン。
        //.listStyle モディファイア一覧。
        //.listStyle(DefaultListStyle())//デフォルト
        //.listStyle(InsetGroupedListStyle())//デフォルトに近いデザイン。
        //.listStyle(PlainListStyle())//セルと近いセクションデザイン。
        //.listStyle(InsetListStyle())//セルと近いセクションデザイン。
        //.listStyle(GroupedListStyle())//設定画面に近いスタイル
        //.listStyle(SidebarListStyle())//折りたたみデザイン。
    }
}
    
#Preview {
    ContentView()
}

SwiftUIのリストにナビバーを追加

import SwiftUI

struct ContentView: View {
    
    let areaName = ["東京", "大阪", "福岡", "沖縄"]
    
    var body: some View {
        NavigationStack {
            
            List {
                Section(header: Text("日本の都市名")) {
                    ForEach(areaName.indices, id: \.self) {
                        Text(areaName[$0])
                    }
                }
            }

            .navigationTitle("Top View")
            .navigationBarTitleDisplayMode(.inline)//表示スタイル
        }
    }
}
    
#Preview {
    ContentView()
}

SwiftUIでナビゲーションによる画面遷移

import SwiftUI

struct ContentView: View {
    var body: some View {
        
        NavigationStack {
            NavigationLink {
                nextView()
            } label: {
                Text("NextViewへ")
            }
        }
    }
}


struct nextView: View {
    var body: some View {
            Text("NextViewだよ。")
    }
}

    
#Preview {
    ContentView()
}

SwiftUIのモーダルビュー

import SwiftUI


struct ContentView: View {
    
    @State private var present = false
   
    var body: some View {

        Button("モーダルビュー") {
            present = true
        }
        .sheet(isPresented: $present) {
            ModalView()
        }

    }
    
}


struct ModalView: View {

    @Environment(\.dismiss) private var dismiss

    var body: some View {
        
        Button("閉じる") {
            dismiss()
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.cyan.opacity(0.1))

    }

}


#Preview {
    ContentView()
}

SwiftUIのモーダルフルスクリーン

import SwiftUI


struct ContentView: View {
        
    @State var present = false

    var body: some View {
        
        Button("モーダルフルスクリーン"){
            present = true
        }
        .fullScreenCover(isPresented: $present, onDismiss: didDismiss) {
            ModalFullScreen(present2: $present)
        }
        
    }
    
    func didDismiss() {
        print("モーダルフルスクリーンが閉じたよ。")
    }
    
}



struct ModalFullScreen: View {
    
    @Binding var present2: Bool
    
    var body: some View {
        
        Button("閉じる") {
            present2 = false
        }
        .frame(maxWidth: .infinity, maxHeight: .infinity)
        .background(Color.cyan.opacity(0.1).edgesIgnoringSafeArea(.all))
    
    }
    
}


#Preview {
    ContentView()
}

SwiftUIでナビバーを非表示にして、戻る。

import SwiftUI


struct ContentView: View {
    var body: some View {
        
        NavigationView {
            NavigationLink(destination: nextView()) {
                Text("nextViewへ。")
            }
        }
        
    }
}


struct nextView: View {
    
    @Environment(\.presentationMode) var nextScreen
    
    var body: some View {
        Button("戻る"){
            self.nextScreen.wrappedValue.dismiss()
        }
        .navigationBarHidden(true)
    }
    
}

    
#Preview {
    ContentView()
}

NavigationStackとよる画面遷移

順番に画面遷移し、戻るで最初の画面に戻る。

import SwiftUI


var CountryArray:[String] = ["Japan", "America", "England"]

var CityTwoDimArray:[[String]] = [
    ["Tokyo", "Osaka", "Fukuoka"],
    ["Los Angeles", "New York", "Seattle"],
    ["London", "Cambridge", "Glasgow"]
]



struct FirstView: View {
    
    @State var sectionNumber = 0
    @State var goToSecondView = false
    
    var body: some View {
        NavigationStack {
            List {
                ForEach(CountryArray.indices, id: \.self) {section in
                    Button(CountryArray[section]) {
                        sectionNumber = section
                        goToSecondView = true
                    }
                    .foregroundColor(.primary)
                }
                .navigationDestination(isPresented: $goToSecondView) {
                    SecondView(sectionNumber: sectionNumber)
                }
            }
            .navigationTitle("Country List")
        }
    }
}



struct SecondView:View{
    
    var sectionNumber = 0
    @State var rowNumber = 0
    @State var goToThirdView = false
    
    var body: some View {
        NavigationStack{
            List {
                ForEach(CityTwoDimArray[sectionNumber].indices, id: \.self) {row in
                    Button(CityTwoDimArray[sectionNumber][row]) {
                        rowNumber = row
                        goToThirdView = true
                    }
                    .foregroundColor(.primary)
                }
                .navigationDestination(isPresented: $goToThirdView) {
                    ThirdView()
                }
            }
            .navigationTitle("City List")
        }
    }
}



struct ThirdView:View{
    
    @Environment(\.presentationMode) var thisScreen
    
    var body: some View {
        Button("戻る"){
            self.thisScreen.wrappedValue.dismiss()
        }
        .foregroundColor(.primary)
    }
}



#Preview {
    FirstView()
}

ButtonによるViewの入れ替え

import SwiftUI


struct ContentView: View {
    
   
    @State var showViewName = "OrangeView"
    
    var body: some View {
        VStack {
            
            Spacer()
            
            //ここでviewの入れ替え。
            VStack {
                if showViewName == "OrangeView" {
                    OrangeView()
                } else if showViewName == "CyanView" {
                    CyanView()
                } else if showViewName == "PinkView" {
                    PinkView()
                }
            }
            //.frame(maxWidth: .infinity, minHeight: UIScreen.main.bounds.height - 176)
            
            Spacer()
            
            //ここからボタン。
            HStack (){
                Spacer()
                Button(action: {
                    showViewName = "OrangeView"
                }) {
                    Image(systemName: "circle.fill")
                }
                .foregroundColor(.orange)
                
                Spacer()
                
                Button(action: {
                    showViewName = "CyanView"
                }) {
                    Image(systemName: "circle.fill")
                }
                .foregroundColor(.cyan)
            
                Spacer()
                
                Button(action: {
                    showViewName = "PinkView"
                }) {
                    Image(systemName: "circle.fill")
                }
                .foregroundColor(.pink)

                Spacer()
                
            }
            .font(.system(size: 25))
            .frame(maxWidth: .infinity, minHeight: 54.0)
            .background(Color.gray.opacity(0.2)) // OK
        }
        
        
        .onChange(of: showViewName) {
            print(showViewName)
        }
        
    }
}





struct OrangeView: View {
    var body: some View {
        Text("OrangeView")
            .foregroundColor(.orange)
            .font(.system(size:35))
            .fontWeight(.black)
    }
}



struct CyanView: View {
    var body: some View {
        Text("CyanView")
            .foregroundColor(.cyan)
            .font(.system(size:35))
            .fontWeight(.black)
    }
}



struct PinkView: View {
    var body: some View {
        Text("PinkView")
            .foregroundColor(.pink)
            .font(.system(size:35))
            .fontWeight(.black)
    }
}



#Preview {
    ContentView()
}

SwiftUIのCharts(iOS16〜)

import SwiftUI
import Charts



struct ContentView: View {
    

    //表の基礎のなるリスト。
    @State var priceList:[[Any]] = [
        ["りんご", 200, Color(#colorLiteral(red: 1, green: 0.1857388616, blue: 0.5733950138, alpha: 1))],
        ["なし", 300, Color(#colorLiteral(red: 1, green: 0.4932718873, blue: 0.4739984274, alpha: 1))],
        ["みかん", 300, Color(#colorLiteral(red: 1, green: 0.8323456645, blue: 0.4732058644, alpha: 1))],
        ["スイカ", 1800, Color(#colorLiteral(red: 0.9995340705, green: 0.988355577, blue: 0.4726552367, alpha: 1))],
        ["ぶどう", 800,  Color(#colorLiteral(red: 0.8321695924, green: 0.985483706, blue: 0.4733308554, alpha: 1))],
        ["シャインマスカット", 1500, Color(#colorLiteral(red: 0.4500938654, green: 0.9813225865, blue: 0.4743030667, alpha: 1))],
        ["クランベリー", 800, Color(#colorLiteral(red: 0.4508578777, green: 0.9882974029, blue: 0.8376303315, alpha: 1))],
    ]
    
    
    
    var body: some View {
        
        Chart {
            ForEach(priceList.indices, id: \.self) { num in
                BarMark(
                    x: .value("fruit", priceList[num][0] as! String),
                    y: .value("Price", priceList[num][1] as! Int)
                )
                .foregroundStyle(by: .value("Shape Color", priceList[num][0] as! String))
            }
        }
        .chartForegroundStyleScale(range: graphColors(priceList:priceList))
        .padding()
        
        
        HStack (){
            Spacer()
            
            Button(action: {
                PulusButtonAction()
            }) {
                Image(systemName: "plus.circle")
            }
            .foregroundColor(.orange)
            Spacer()
            
            Button(action: {
                MinusButtonAction()
            }) {
                Image(systemName: "minus.circle")
            }
            .foregroundColor(.cyan)
            Spacer()
            
        }
        .font(.system(size: 25))
    }
    
    
    //色の配列を返すファンクション。
    func graphColors(priceList:[[Any]]) -> [Color] {
        var returnColors:[Color] = []
        for number in priceList.indices {
            returnColors.append(priceList[number][2] as! Color)
        }
        return returnColors
    }
    
    
    //プラスボタンのアクション。
    func PulusButtonAction(){
        print("プラスボタンだよ。")
        priceList.append(["メロン", 1800, Color(#colorLiteral(red: 0.476841867, green: 0.5048075914, blue: 1, alpha: 1))])
    }
    
    
    //マイナスボタンのアクション。
    func MinusButtonAction(){
        print("マイナスボタンだよ。")
        if priceList.count != 0 {
            priceList.removeLast()
        }
    }
    

}



#Preview {
    ContentView()
}

BarMark

xとyを入れ替えると、横向きになる。

PointMark

RectangleMark

LineMark

 .foregroundStyleの行を

 .foregroundStyle(.red)に変更する。

SwiftUIのChartsのBarMarkの積層(iOS16〜)

import SwiftUI
import Charts



struct ContentView: View {
    
    
    struct kamoku: Identifiable {
        var id = UUID()
        let kamoku: String
        let color: Color
    }
    
    
    
    @State var kamokuList: [kamoku] = [
        kamoku(id: UUID(), kamoku : "国語", color:Color(#colorLiteral(red: 1, green: 0.1857388616, blue: 0.5733950138, alpha: 1))),
        kamoku(id: UUID(), kamoku : "算数", color:Color(#colorLiteral(red: 0.9995340705, green: 0.988355577, blue: 0.4726552367, alpha: 1))),
        kamoku(id: UUID(), kamoku : "理科", color:Color(#colorLiteral(red: 0.2392156869, green: 0.6745098233, blue: 0.9686274529, alpha: 1))),
        kamoku(id: UUID(), kamoku : "社会", color:Color(#colorLiteral(red: 0.4508578777, green: 0.9882974029, blue: 0.8376303315, alpha: 1))),
    ]
    
    

    //表の基礎のなるリスト。
    @State var studyList:[[Any]] = [
        ["2023年1月1日", 200,"国語"],
        ["2023年1月1日", 200, "算数"],
        ["2023年1月2日", 300, "理科"],
        ["2023年1月3日", 300, "社会"],
        ["2023年1月3日", 1800, "国語"],
        ["2023年1月3日", 800,  "算数"],
        ["2023年1月4日", 1500, "理科"],
        ["2023年1月5日", 800, "社会"],
    ]
    
    
    
    var body: some View {
        
        Chart {
            ForEach(studyList.indices, id: \.self) { num in
                BarMark(
                    x: .value("日時", studyList[num][0] as! String),
                    y: .value("時間", studyList[num][1] as! Int)
                )
                .foregroundStyle(by: .value("Shape Color", studyList[num][2] as! String))
            }
            
        }
        .chartForegroundStyleScale(
            domain: kamokuList.map{ $0.kamoku }, range: kamokuList.map{ $0.color }
        )
        .padding()
        
        
        HStack (){
            Spacer()
            
            Button(action: {
                PulusButtonAction()
            }) {
                Image(systemName: "plus.circle")
            }
            .foregroundColor(.orange)
            .font(.system(size: 35))
            Spacer()
            
            
            Button(action: {
                SmallPulusButtonAction()
            }) {
                Image(systemName: "plus")
            }
            .foregroundColor(.orange)
            .font(.system(size: 25))
            Spacer()
            
        }
        .font(.system(size: 25))
    }
    

    
    //プラスボタンのアクション。
    func PulusButtonAction(){
        print("プラスボタンだよ。")
        studyList.append(["2023年1月6日", 1200, "国語"])
    }
    
    
    //マイナスボタンのアクション。
    func SmallPulusButtonAction(){
        print("スモールプラスボタンだよ。")
        kamokuList.append(kamoku(id: UUID(), kamoku : "英語", color:.red))
    }
    
}

//

#Preview {
    ContentView()
}

SwiftUIのChartsのBarMarkの並列(iOS16〜)

import SwiftUI
import Charts



struct ContentView: View {
    
    
    
    struct kamoku {
        var kamoku: String
        var color: Color
    }
    
    
    @State var kamokuList: [kamoku] = [
        kamoku(kamoku : "国語", color:Color(#colorLiteral(red: 1, green: 0.1857388616, blue: 0.5733950138, alpha: 1))),
        kamoku(kamoku : "数学", color:Color(#colorLiteral(red: 1, green: 0.8323456645, blue: 0.4732058644, alpha: 1))),
        kamoku(kamoku : "社会", color:Color(#colorLiteral(red: 0.8321695924, green: 0.985483706, blue: 0.4733308554, alpha: 1))),
    ]
        
        
    
    struct StudyRecord: Identifiable {
        var id = UUID()
        var date: String
        var kamoku: String
        var time: Int
    }
    
    
    @State var StudyList:[StudyRecord] = [
        StudyRecord(id: UUID(), date : "2023年1月4日", kamoku : "国語", time : 800),
        StudyRecord(id: UUID(), date : "2023年1月4日", kamoku : "数学", time : 1000),
        StudyRecord(id: UUID(), date : "2023年1月4日", kamoku : "社会", time : 1200),
        StudyRecord(id: UUID(), date : "2023年1月5日", kamoku : "国語", time : 1800),
        StudyRecord(id: UUID(), date : "2023年1月5日", kamoku : "数学", time : 1200),
        StudyRecord(id: UUID(), date : "2023年1月5日", kamoku : "社会", time : 700),
        StudyRecord(id: UUID(), date : "2023年1月6日", kamoku : "国語", time : 1200),
        StudyRecord(id: UUID(), date : "2023年1月6日", kamoku : "数学", time : 3000),
        StudyRecord(id: UUID(), date : "2023年1月6日", kamoku : "社会", time : 3300),
    ]
    
    
    
    var body: some View {
        
        Chart {
            ForEach(StudyList) { StudyList in
                BarMark(
                    x: .value("日時", StudyList.date),
                    y: .value("時間", StudyList.time)
                )
                .foregroundStyle(by: .value("kamoku", StudyList.kamoku))
                .position(by: .value("kamoku", StudyList.kamoku))
            }
        }
        .chartForegroundStyleScale(domain: kamokuList.map{ $0.kamoku }, range: kamokuList.map{ $0.color })
        .padding()
        
        
        HStack (){
            Spacer()
            
            Button(action: {
                PulusButtonAction()
            }) {
                Image(systemName: "plus.circle")
            }
            .foregroundColor(.orange)
            .font(.system(size: 35))
            Spacer()
            
            
            Button(action: {
                SmallPulusButtonAction()
            }) {
                Image(systemName: "plus")
            }
            .foregroundColor(.orange)
            .font(.system(size: 25))
            Spacer()
            
        }
        .font(.system(size: 25))
    }
    

    
    //プラスボタンのアクション。
    func PulusButtonAction(){
        print("プラスボタンだよ。")
        StudyList.append(StudyRecord(id: UUID(), date : "2023年1月7日", kamoku : "国語", time : 1200))
        StudyList.append(StudyRecord(id: UUID(), date : "2023年1月7日", kamoku : "数学", time : 800))
        StudyList.append(StudyRecord(id: UUID(), date : "2023年1月7日", kamoku : "社会", time : 1000))
        //StudyList.append(StudyRecord(id: UUID(), date : "2023年1月7日", kamoku : "理科", time : 1000))
    }
    
    
    
    //マイナスボタンのアクション。
    func SmallPulusButtonAction(){
        print("スモールプラスボタンだよ。")
        kamokuList.append(kamoku(kamoku : "理科",color:.red))
    }
    
    
    
}



#Preview {
    ContentView()
}

SwiftUIのテキストフィールド付きのAlert

import SwiftUI


struct ContentView: View {
    
    
    @State var textFieldString = ""
    @State var showAlert: Bool = false
    
    
    var body: some View {
        
        Button("alert") {
            textFieldString = ""
            showAlert = true
        }
        
        .alert("Alert", isPresented: $showAlert) {
            TextField("Passcode", text: $textFieldString)

            Button("OK") {
                showAlert = false
                print("OK \(textFieldString)\(showAlert)")
            }
            
            Button("Cancel", role: .cancel){
                showAlert = false
                print("Cancel \(textFieldString)\(showAlert)")
            }
            
        }
        
    }
    
}


#Preview {
    ContentView()
}

SwiftUIのPickerの横向き

import SwiftUI


struct ContentView: View {
    
    
    @State var Imageviews = [
        Image(systemName: "bicycle"),
        Image(systemName: "car"),
        Image(systemName: "bus"),
        Image(systemName: "lightrail"),
        Image(systemName: "airplane"),
    ]
    
    
    @State private var indexNumber = 0
    
    
    var body: some View {
        
        VStack {
            Picker(selection: $indexNumber, label: Text("")) {
                ForEach(Imageviews.indices, id: \.self) { indexNumber in
                    Imageviews[indexNumber]
                }
            }
            .pickerStyle(SegmentedPickerStyle())
        }
        
    }
    
    
}


#Preview {
    ContentView()
}

UIKit内でSwiftUIを表示する

import UIKit
import SwiftUI



class SecondViewController: UIViewController {

    
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        let vc: UIHostingController = UIHostingController(rootView: SubView())
        self.addChild(vc)
        self.view.addSubview(vc.view)
        vc.didMove(toParent: self)

        vc.view.translatesAutoresizingMaskIntoConstraints = false
        //vc.view.heightAnchor.constraint(equalToConstant: 320).isActive = true
        vc.view.bottomAnchor.constraint(equalTo: self.view.bottomAnchor, constant: 0).isActive = true
        vc.view.topAnchor.constraint(equalTo: self.view.topAnchor, constant: 0).isActive = true
        vc.view.leftAnchor.constraint(equalTo: self.view.leftAnchor, constant: 0).isActive = true
        vc.view.rightAnchor.constraint(equalTo: self.view.rightAnchor, constant: 0).isActive = true
        //vc.view.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
    }
    
    
    
    struct SubView : View {
  
        var body: some View {
            List {
                ForEach(0...15, id: \.self) {
                    Text("\($0)")
                }
            }
        }
    }
    
    

}

SwiftUIでの図形表示

import SwiftUI


struct ContentView: View {
    var body: some View {
        
        List() {
            //四角
            Rectangle()
                .fill(.orange)
                .frame(width:300, height: 100)
            
            //グラデーション
            let gradient = LinearGradient(gradient: Gradient(colors: [.pink, .orange]), startPoint: .topLeading, endPoint: .bottomTrailing)
            Rectangle()
                .fill(gradient)
                .frame(width:300, height: 100)
            
            //角丸
            RoundedRectangle(cornerRadius: 30)
                .fill(.pink)
                .frame(width:300, height: 100)
                .overlay(Text("momo")
                    .foregroundColor(.white))
                    .font(.title)
            
            //角丸の変形
            RoundedRectangle(cornerSize: .init(width: 100, height: 20))
                .fill(Color.red)
                .frame(width:300, height: 100)
            
            //カプセル
            Capsule()
                .fill(gradient)
                .frame(width:300, height: 100)
            
            //丸
            Circle()
                .fill(Color.orange)
                .frame(width:100, height: 100)
            
            //楕円
            Ellipse()
                .fill(Color.pink)
                .frame(width:200, height: 100)
            
        }
    }
        
}

#Preview {
    ContentView()
}

SwiftUIでつまんで動かす

import SwiftUI


struct ContentView: View {
    
    @State var center = CGPoint.zero

    var body: some View {
        
        VStack {
            
            Text("🍎")
                .font(.system(size: 50))
                .frame(width: 50, height: 50)
                .offset(x: center.x - 25, y: center.y - 25)
                .gesture(
                    DragGesture(minimumDistance: 0).onChanged { value in
                        center = value.location
                    })
            
        }
        
    }
    
}
 

#Preview {
    ContentView()
}

SwiftUIでの時間付きアニメーション

import SwiftUI


struct ContentView: View {
  
    @State var kurukuru = true
  
    var body: some View {
     VStack {
        Text("🍙")
           .font(.system(size: 100))
           .rotationEffect(Angle.degrees(kurukuru ? 0 : 720))
           .animation(Animation.easeInOut(duration:3.0), value: kurukuru)
           .padding()
        
         Button(action: {
           kurukuru.toggle()
        }) {
           Image(systemName: "arrow.clockwise")
                .font(.system(size: 50))
                .foregroundColor(.secondary)
        }
        .padding()
     }
  }
}


#Preview {
    ContentView()
}

SwiftUIのToggleによるアニメーション

import SwiftUI


struct ContentView: View {
    
    @State var sizeChangeOn = false
    
    var body: some View {
        
        VStack {
            Spacer()
            
            Circle()
                .fill(sizeChangeOn ? .orange.opacity(0.5) : .orange)
                .frame(width: 200, height: 200)
                .scaleEffect(sizeChangeOn ? 0.5 : 1.0)
            
            Spacer()
            
            Circle()
                .fill(sizeChangeOn ? .cyan : .cyan.opacity(0.5))
                .frame(width: 200, height: 200)
                .scaleEffect(sizeChangeOn ? 1.0 : 0.5)
            
            Spacer()
            
            Toggle("", isOn: $sizeChangeOn.animation(Animation.easeInOut(duration:2.0)))
                .labelsHidden()
                .tint(.orange)
            
            Spacer()
        }
        
    }
    
}
 

#Preview {
    ContentView()
}

SwiftUIのボタンのアニメーション

import SwiftUI


struct ContentView: View {

    @State private var treeOn: Bool = false

    var body: some View {
        Button {
            treeOn.toggle()
        } label: {
            VStack{
                Spacer()

                Text("🌲")
                    .font(.system(size: 50))
                    .frame(width: 50, height: 50)
                    .scaleEffect(treeOn ? 6 : 1)
                    .animation(Animation.easeInOut(duration:3.0), value: treeOn)

                Spacer()
            }
        }
    }
}
 

#Preview {
    ContentView()
}

SwiftUIにおけるボタンエフェクト

import SwiftUI


struct ContentView: View {
    var body: some View {
        
        Button(action: {
            
        }) {
            Text("Tap Me !")
        }.buttonStyle(BigButton())
        
    }
}


struct BigButton: ButtonStyle {
    func makeBody(configuration: Configuration) -> some View {
        configuration.label
            .padding()
            .background(configuration.isPressed ? .pink : .orange)
            .foregroundStyle(.white)
            .clipShape(Capsule())
            .scaleEffect(configuration.isPressed ? 4.0 : 1)
            .animation(.easeOut(duration: 2.0), value: configuration.isPressed)
    }
}

#Preview {
    ContentView()
}

SwiftUIの.timingCurve

import SwiftUI


struct ContentView: View {
    
    @State private var animate = false
    
    var body: some View {
        
        ZStack {
            
            Circle()
                .frame(width: 220, height: 220)
                .foregroundColor(.gray.opacity(0.3))
            
            Circle()
                .frame(width: 160, height: 160)
                .foregroundColor(.white)
                
            
            Circle()
                .frame(width: 30, height: 30)
                .foregroundColor(Color.orange)
                .offset(y: 95)
                .rotationEffect(.degrees(self.animate ? 540 : 180))
                .animation(
                    Animation//頂点から0.9がスタート。
                        .timingCurve(0.9, 0.2, 0.1, 0.8, duration: 3.3)
                        .repeatForever(autoreverses: false), value: animate
                )
            
            
            Circle()
                .frame(width: 20, height: 20)
                .foregroundColor(Color.pink)
                .offset(y: 90)
                .rotationEffect(.degrees(self.animate ? 540 : 180))
                .animation(
                    Animation//頂点から0.9がスタート。
                        .timingCurve(0.9, 0.2, 0.1, 0.8, duration: 4.0)
                        .repeatForever(autoreverses: false), value: animate
                )
            
            
        }
        .onAppear() {
            self.animate = true
        }
        
    }
    
}


#Preview {
    ContentView()
}

SwiftUIのアニメーションの演習

import SwiftUI


struct ContentView: View {
    
    
    @State var animationOn = false
    
    var body: some View {
        
        ZStack {
            ForEach (1...500, id:\.self) { _ in
                Circle ()
                    .foregroundColor(Color (red: .random(in: 0.0...0.4),
                                            green: .random(in: 0.8...1.0),
                                            blue: .random(in: 0.3...0.7)))
                    .opacity(.random(in: 0.1...0.2))
                    .animation (Animation.spring (dampingFraction: 0.5)
                                .repeatForever()
                        .speed (.random(in: 0.05...0.4))
                        .delay(.random (in: 0...1)), value: animationOn
                    )
                
                    .scaleEffect(.random(in: 0.1...2))
                    .frame(width: .random(in: 15...40),
                           height: CGFloat.random (in: 15...40),
                           alignment: .center)
                    .position(CGPoint(x: .random(in: 0...400),
                                      y: .random (in: 0...834)))
            }
        }
        .opacity(animationOn ? 0.0 : 1.0)
        .animation(Animation.easeInOut(duration:3.0),value: animationOn)
        .background(.white)
        .onTapGesture {
            animationOn.toggle()
        }
    }
}

#Preview {
    ContentView()
}

RealityKitとSwiftUIで、球体とボックスと平面を表示する。


import SwiftUI
import RealityKit

struct ContentView : View {
    var body: some View {
        RealityKitSampleNo1().edgesIgnoringSafeArea(.all)
    }
}



struct RealityKitSampleNo1: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)

        let mesh = MeshResource.generateSphere(radius: 0.051)//球体。
        //let mesh = MeshResource.generateBox(size: 0.1, cornerRadius: 0.005)//box
        //let mesh = MeshResource.generatePlane(width: 0.15, height: 0.30, cornerRadius: 0.010)//平面。

        let material = SimpleMaterial(color: .cyan, roughness: 0.15, isMetallic: true)
        let model = ModelEntity(mesh: mesh, materials: [material])
        model.transform.translation.y = 0.05

        let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.2, 0.2)))
        anchor.children.append(model)

        arView.scene.anchors.append(anchor)

        return arView
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {
     
    }
    
}

RealityKitとSwiftUIで、文字オブジェクトを表示する。

import SwiftUI
import RealityKit

struct ContentView : View {
    var body: some View {
        RealityKitSampleNo1().edgesIgnoringSafeArea(.all)
    }
}


struct RealityKitSampleNo1: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        
        let arView = ARView(frame: .zero)

        let textMesh = MeshResource.generateText("Hello, world!", extrusionDepth: 0.1, font: .systemFont(ofSize: 0.5), containerFrame: CGRect.zero, alignment: .left, lineBreakMode: .byTruncatingTail)
        let textMaterial = SimpleMaterial(color: .systemCyan, roughness: 0.0, isMetallic: true)
                let textModel = ModelEntity(mesh: textMesh, materials: [textMaterial])
                textModel.scale = SIMD3<Float>(0.1, 0.1, 0.1)
                textModel.position = SIMD3<Float>(0.0, 0.0, -0.2)

        let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.2, 0.2)))
        anchor.children.append(textModel)

        arView.scene.anchors.append(anchor)

        return arView
        
    }
    
    func updateUIView(_ uiView: ARView, context: Context) {}
    
}

RealityKitとSwiftUIで、usdzファイルを表示する。端末基準。

import SwiftUI
import RealityKit


struct ContentView : View {
    var body: some View {
        RealityKitSampleNo1().edgesIgnoringSafeArea(.all)
    }
}


struct RealityKitSampleNo1: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        let filename = "toy_drummer_idle"
        let modelUrl = Bundle.main.url(forResource: filename, withExtension: "usdz")!
        let anchor = AnchorEntity(world: [0, -0.2, -0.2])//自分から見て前方下に配置。

        arView.scene.addAnchor(anchor)

        if let modelEntity = try? ModelEntity.load(contentsOf: modelUrl) {
            modelEntity.scale = SIMD3<Float>(0.01, 0.01, 0.01)
            modelEntity.availableAnimations.forEach {
                modelEntity.playAnimation($0.repeat())
            }

            anchor.addChild(modelEntity)
        }

        return arView
    }

    func updateUIView(_ uiView: ARView, context: Context) {}
}

RealityKitとSwiftUIで、usdzファイルを表示する。平面基準。


import SwiftUI
import RealityKit


struct ContentView : View {
    var body: some View {
        RealityKitSampleNo1().edgesIgnoringSafeArea(.all)
    }
}


struct RealityKitSampleNo1: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        let filename = "toy_drummer_idle"
        let modelUrl = Bundle.main.url(forResource: filename, withExtension: "usdz")!
        let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.2, 0.2)))
        //平面を取得して、平面を基準にオブジェクトを配置。
        if let modelEntity = try? ModelEntity.load(contentsOf: modelUrl) {
            modelEntity.scale = SIMD3<Float>(0.01, 0.01, 0.01)
            modelEntity.availableAnimations.forEach {
                modelEntity.playAnimation($0.repeat())
            }
            anchor.addChild(modelEntity)
        }
        
        arView.scene.addAnchor(anchor)

        return arView
    }

    func updateUIView(_ uiView: ARView, context: Context) {}
}

RealityKitとSwiftUIで、3つのusdzファイルを表示する。平面基準。

Appleの3Dオブジェクトのサンプル

Quick Look Gallery - Augmented Reality - Apple Developer
Embed Quick Look views in your apps and websites to let users see incredible detailed renderings in 3D or AR.
import SwiftUI
import RealityKit


struct ContentView : View {
    var body: some View {
        RealityKitSampleNo1().edgesIgnoringSafeArea(.all)
    }
}


struct RealityKitSampleNo1: UIViewRepresentable {
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        
        let filename = "toy_drummer_idle"
        let modelUrl = Bundle.main.url(forResource: filename, withExtension: "usdz")!
        let anchor = AnchorEntity(.plane(.horizontal, classification: .any, minimumBounds: SIMD2<Float>(0.2, 0.2)))
        if let modelEntity = try? ModelEntity.load(contentsOf: modelUrl) {
            modelEntity.scale = SIMD3<Float>(0.01, 0.01, 0.01)
            modelEntity.availableAnimations.forEach {
                modelEntity.playAnimation($0.repeat())
            }
            //modelEntity.position = [0, -0.15, 0]
            anchor.addChild(modelEntity)
        }
        
        
        let filename2 = "Earth_1_12756"
        let modelUrl2 = Bundle.main.url(forResource: filename2, withExtension: "usdz")!
        if let modelEntity = try? ModelEntity.load(contentsOf: modelUrl2) {
            modelEntity.scale = SIMD3<Float>(0.0005, 0.0005, 0.0005)
            modelEntity.availableAnimations.forEach {
                modelEntity.playAnimation($0.repeat())
            }
            modelEntity.position = [0.2, 0.3, 0]
            anchor.addChild(modelEntity)
        }
        
        
        let filename3 = "toy_biplane_idle"
        let modelUrl3 = Bundle.main.url(forResource: filename3, withExtension: "usdz")!
        if let modelEntity = try? ModelEntity.load(contentsOf: modelUrl3) {
            modelEntity.scale = SIMD3<Float>(0.01, 0.01, 0.01)
            modelEntity.availableAnimations.forEach {
                modelEntity.playAnimation($0.repeat())
            }
            modelEntity.position = [-0.2, 0.1, 0]
            anchor.addChild(modelEntity)
        }
        
        arView.scene.addAnchor(anchor)

        return arView
    }

    func updateUIView(_ uiView: ARView, context: Context) {}
}