[SwiftUI] テキストの装飾

VStackとHStack

HStack {
            Text("おはよう!")
                .padding()
            Text("Placeholder")
            Text("Placeholder 2")
        }

横並びか縦並びかの違い

式の値を返す変数
L 式の値が1つだけならreturnを省略できる

var num:Int {
    let result = 2 * 5
    return result
}

print(num)

return HStackのreturnが省略されている
read onlyでgetが省略されている

    var body: some View {
        HStack {
            Text("おはよう!")
                .padding()
            Text("Placeholder")
            Text("Placeholder 2")
        }
    }

getterとsetter

var radius = 10.0

var diameter: Double {
    get {
        radius * 2
    }
    set (length){
        radius = length / 2
    }
}

var around:Double {
    get {
        let length = 2 * radius * Double.pi
        return length
    }
    set(length) {
        radius = length / (2 * Double.pi)
    }
}

print("半径が\(radius)の時、直径の長さは\(diameter)")
diameter = 30
print("直径が\(diameter)の時、半径は\(radius)")
around = 100
print("円周の長さが\(around)の時、円の半径は\(radius)")

libraryからコードを配置

    var body: some View {
        VStack {
            HStack {
                Text("Hello, world")
                    .padding()
                Text(/*@START_MENU_TOKEN@*/"Placeholder"/*@END_MENU_TOKEN@*/)
            }
            HStack {
                Text(/*@START_MENU_TOKEN@*/"Placeholder"/*@END_MENU_TOKEN@*/)
                Text(/*@START_MENU_TOKEN@*/"Placeholder"/*@END_MENU_TOKEN@*/)
            }
        }
    }

### フォントや縦横サイズの設定
font(), fontWeight(), foregroundColor(), frame(), padding()

フォントサイズ編集

        VStack {
            Text("Bicycle for the Mind")
                .font(.title)
                .fontWeight(.thin)
                .padding(.all, 40)
            Text("知性の自転車")
                .foregroundColor(Color.red)
        }

Line Limitとフレーム

        VStack {
            Text("春はあけぼの。やうやう白くなりゆく山ぎは、すこしあかりて、紫だちたる雲のほそくたなびきたる。")
                .lineLimit(2)
                .frame(width: 200.0)
        }

alignment

        VStack {
            Text("The quick brown for jumps over the lazy dog.")
                .font(.largeTitle)
                .multilineTextAlignment(.trailing)
                .frame(width: 200.0)
        }

Border
L 色は、red, orange, yellow, green, mint, teal, cyan, blue, indigo, purple, pink, brown, white, gray, black, clear, primary, secondaryが選べる

        VStack {
            Text("Bicycle for the Mind")
                .font(.title)
                .frame(width: 200.0, height: 200.0)
                .border(Color.green, width: 5)
        }

font size

        VStack {
            Text("Hello World")
                .padding()
                .font(.system(size: 100))
        }

frameの中での位置指定

        VStack {
            Text("The quick brown for \n jumps over \n the lazy dog.")
                .frame(width: 250, height: 200, alignment: .bottomTrailing)
                .padding()
        }

.titleや.heavyは Font.title, Font.heavyのFontを省略している

Inherited
L 上位の階層の設定があった場合に引き継ぐ

        VStack {
            Text("春はあけぼの")
            Text("夏は夜")
                .foregroundColor(.red)
            Text("秋は夕暮")
            Text("冬はつとめて")
        }
        .font(.title)
        .foregroundColor(.blue)

テキストを連結して表示

        VStack {
            Text("No.").bold() + Text("123").font(.largeTitle).foregroundColor(.red)
        }

とっつきにくい印象だったが、触ってみるとeasyね。

Swiftシンタックスの基礎

### 変数、タプル、型、繰り返し

var tanka = 120
var ninzu = 3 + 2
var price = tanka * ninzu

600

var km = 10
km += 5
km += 5
km += 5
var value = 0
value += 2
value *= 5
value /= 2

### 型推論

var title = "為替計算"
var dollar = 250
var rate = 108.5

inspectorで型を調べる事ができる

宣言

var title:String
var dollar:Int
var rate:Double

title = "為替計算"
dollar = 250
rate = 108.5

### varとlet(定数)

var title = "為替計算"
var dollar:Double
var rate:Double

dollar = 250
rate = 108.5

let yen = dollar * rate

### 文字列

let name = "高橋"
let who = name + " さん"

数字から文字列

let tanaka = 240
let kosu = 3
let kingaku = String(tanaka * kosu) + "円です"

文字列に変数や式を埋め込む
 L \(変数) で文字列に変数や数式を直接埋め込む事ができる

let time = 9.95
let result = "タイムは\(time)秒でした"

### タプル

var greeting = ("Hello", "こんにちは")
var guest = ("直鳥", "なおとり", 24)
var point = (23.1, 51.2, 13.8)

型指定

var greeting:(String, String) = ("Hello", "こんにちは")
var guest:(String, String, Int) = ("直鳥", "なおとり", 24)
var point:(Double, Double, Double) = (23.1, 51.2, 13.8)

型推論と型エラー
L 個数が

var greeting = ("Hello", "こんにちは")
greeting = ("宜しく", 4649)
var guest = ("直鳥", "なおとり", 24)
guest = ("金田一", "きんだいち")

### タプルの要素取り出し
使わない要素の場合は”_” を使う

var guest = ("桑原", "くわばら", 34)
let(name, _, age) = guest
let user = name + "さん、" + "\(age)歳"
print(user)

ラベルが付いているタプル

var user = (name:"鈴木", point:30)
user.point += 5
print(user.name)
print(user.point)

ラベル付きタプル

var point:(x:Double, y:Double, z:Double)
point = (4.2, 3.5, 6.1)
print(point.x)

インデックス番号でアクセス

var value = (100, 200, 300)
print(value.1)

for文

let numList = [4, 8, 15, 16, 32, 42]
var sum = 0
for num in numList {
    sum += num
}
print("合計 \(sum)")

整数のレンジから数値を順に取り出す

for x in 0 ..< 360*2 {
    let radian = Double(x) * Double.pi/180
    let y = sin(radian)
    print(x, y)
}

rangeの値を使わないforループ

var stars = ""
for _ in 1 ... 5 {
    stars += "★"
    print(stars)
}

なるほど、アンダースコア(_)の使い方がわかった
swift以外でも良く出てきてたけど、よくわかってなかったんだよね

Pythonでfor文を使って{辞書: [{辞書},{辞書},{辞書}…]}のjsonを作りたい

ありたいてに言うと、下記のような構造のjsonをfor文で作りたい

{
	"item": [
		{
			"area": "東京都","population": 1300, "capital": "東京"
		},
		{
			"area": "北海道","population": 538, "capital": "札幌市"
		},
		{
			"area": "沖縄","population": 143, "capital": "那覇市"
		}	
	]
}

for文で辞書を配列に入れて、それを辞書の中に入れてjsonにすればOK

ys = cl.OrderedDict()
result = []
for item in data:
	print(item["at"][:16] +" " + item["anm"] + " " + item["mag"] + " " + item["maxi"] + " " + item["cod"][:5] + " " + item["cod"][5:11]+ " " + item["cod"][12:-1])
	data = cl.OrderedDict()
	data["at"] = item["at"][:16]
	data["anm"] = item["anm"]
	data["mag"] = item["mag"]
	data["maxi"] = item["maxi"]
	data["tokei"] = item["cod"][:5]
	data["hokui"] = item["cod"][5:11]
	data["depth"] = item["cod"][12:-1]

	result.append(data)

ys["item"] = result
print(ys)

with open("test.json", "w") as f:
    json.dump(ys, f, ensure_ascii=False)

pythonによるjson操作と辞書の理解が浅かったので、これ作るのに丸一日かかった orz…
なんてこったい

Pythonでjson作成

import json

str = {
	"東京":{
		"population": 1300,
		"capital": "東京"
	},
	"北海道": {
		"population": 538,
		"capital": "札幌市"
	},
	"沖縄":{
		"population": 143,
		"capital": "那覇市"
	}
}

with open("population.json", "w") as f:
	json.dump(str, f, ensure_ascii=False)

{“東京”: {“population”: 1300, “capital”: “東京”}, “北海道”: {“population”: 538, “capital”: “札幌市”}, “沖縄”: {“population”: 143, “capital”: “那覇市”}}

なるほどー

[swift] APIを使った検索機能の実装

お菓子の虜 web APIの情報を使ってiOSで表示する

お菓子の虜 Web API

e.g.: https://www.sysbird.jp/webapi/?apikey=guest&keyword=%E3%82%AB%E3%83%AC%E3%83%BC%E5%91%B3&format=json
https://www.sysbird.jp/webapi/?apikey=guest&keyword=%E3%82%AB%E3%83%AC%E3%83%BC%E5%91%B3&format=json&max=10

request parameters: id, type, year, keyword, max, order
response: status, count, item(id, name, maker, price, type, regist, url, image, comment)

@StateObject, @State, @Bindingを学ぶ
検索画面はContentView.swiftで一覧表示処理、OkashiData.swiftでカスタムクラスで実装

OkashiData.swift
L StructではObservableOjectは利用できない、 classで定義する必要がある
  L ObservableOjectはカスタムクラス内でデータの状態を管理するために利用

class OkashiData: ObservableObject {
    
    func searchOkashi(keyword: String) async {
        print(keyword)
    }
}

Taskは一連の流れを処理する
ContentView.swift

struct ContentView: View {
    
    @StateObject var okashiDataList = OkashiData()
    @State var inputText = ""
    
    var body: some View {
        VStack {
            TextField("キーワード", text: $inputText,
                      prompt: Text("キーワードを入力してください。"))
                .onSubmit {
                    Task {
                        await okashiDataList.searchOkashi(keyword: inputText)
                    }
                }
                .submitLabel(.search)
                .padding()
        }
    }
}

WebAPIのリクエストURLを組み立てる
OkashiData.swift

    func searchOkashi(keyword: String) async {
        print(keyword)
        
        guard let keyword_encode = keyword.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) else {
            return
        }
        
        guard let req_url = URL(string:
            "https://www.sysbird.jp/webapi/?apikey=guest&format=json&keyword=\(keyword_encode)&max=10&order=r") else {
            return
        }
        print(req_url)
    }

レスポンスデータ(JSON)を記憶する構造体
L Itemとすることで複数の構造体を保持できる配列として保存
  L ?を付与してnilを許容するオプショナル型として宣言する

    struct ResultJson: Codable {
        struct Item: Codable {
            let name: String?
            let url: URL?
            let image: URL?
        }
        let item: [Item]?
    }

URLSessionでデータをダウンロード
URLSession.sharedで簡素に実行

        do {
            let(data, _) = try await URLSession.shared.data(from: req_url)
            
            let decoder = JSONDecoder()
            let json = try decoder.decode(ResultJson.self, from: data)
            
            print(json)
        } catch {
            print("エラーが出ました")
        }

最近のiOSはマルチコアプロセッサが搭載されている

### 取得したデータをListで一覧表示
Itemの構造体を作成し、List表示
L Identifiableに準拠すると、一意に識別できる型として定義できる
  L uuidを用いてランダムな一意の値を生成

import SwiftUI
import UIKit

struct OkashiItem: Identifiable {
    let id = UUID()
    let name: String
    let link: URL
    let image: URL
}

@StateObject、ObservableObjectを使用すると@Publishedを使用できる
プロパティラッパーはプロパティをラップして機能を追加する

            guard let items = json.item else {return}
            
            DispatchQueue.main.async {
                self.okashiList.removeAll()
            }
            
            for item in items {
                if let name = item.name,
                   let link = item.url,
                   let image = item.image {
                   let okashi = OkashiItem(name: name, link: link, image: image)
                    DispatchQueue.main.async {
                        self.okashiList.append(okashi)
                    }
                }
            }
            print(self.okashiList)

### リストで一覧表示

    var body: some View {
        VStack {
            TextField("キーワード", text: $inputText,
                      prompt: Text("キーワードを入力してください。"))
                .onSubmit {
                    Task {
                        await okashiDataList.searchOkashi(keyword: inputText)
                    }
                }
                .submitLabel(.search)
                .padding()
            List(okashiDataList.okashiList) { okashi in
                HStack {
                    AsyncImage(url: okashi.image) { image in
                        image
                            .resizable()
                            .aspectRatio(contentMode: .fit)
                            .frame(height: 40)
                    } placeholder: {
                        ProgressView()
                    }
                    Text(okashi.name)
                }
            }
        }
    }

### Webページの表示
SFSafariViewControllerでWebページを表示

SafariView.swift
L SafariServicesでアプリの中でsafariを起動する

import SafariServices

struct SafariView: UIViewControllerRepresentable {
    
    var url: URL
    
    func makeUIViewController(context: Context) -> SFSafariViewController {
        return SFSafariViewController(url: url)
    }
    
    func updateUIViewController(_ uiViewController: SFSafariViewController, context: Context){
        
    }
}

struct ContentView: View {
    
    @StateObject var okashiDataList = OkashiData()
    @State var inputText = ""
    @State var showSafari = false
    
    var body: some View {
        VStack {
            TextField("キーワード", text: $inputText,
                      prompt: Text("キーワードを入力してください。"))
                .onSubmit {
                    Task {
                        await okashiDataList.searchOkashi(keyword: inputText)
                    }
                }
                .submitLabel(.search)
                .padding()
            List(okashiDataList.okashiList) { okashi in
                
                Button(action: {
                    showSafari.toggle()
                }){
                    HStack {
                        AsyncImage(url: okashi.image) { image in
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                                .frame(height: 40)
                        } placeholder: {
                            ProgressView()
                        }
                        Text(okashi.name)
                    }
                }
            }
        }
    }
}

これは凄い

[swift] エフェクト編集画面の作成

EffectView.swift

struct EffectView: View {
    
    @Binding var isShowSheet: Bool
    
    let captureImage: UIImage
    
    @State var showImage: UIImage?
    @State var isShowActivity = false
    
    var body: some View {
        
        VStack {
            Spacer()
            
            if let unwrapShowImage = showImage {
                Image(uiImage: unwrapShowImage)
                    .resizable()
                    .aspectRatio(contentMode: .fit)
            }
            
            Spacer()
            
            Button(action: {}){
                Text("エフェクト")
                    .frame(maxWidth: .infinity)
                    .frame(height: 50)
                    .multilineTextAlignment(.center)
                    .background(Color.blue)
                    .foregroundColor(Color.white)
            }
            .padding()
            
            Button(action: {}){
                Text("閉じる")
                    .frame(maxWidth: .infinity)
                    .frame(height: 50)
                    .multilineTextAlignment(.center)
                    .background(Color.blue)
                    .foregroundColor(Color.white)
            }
            .padding()
        }
        .onAppear {
            showImage = captureImage
        }
    }
}

struct EffectView_Previews: PreviewProvider {
    static var previews: some View {
        EffectView(
            isShowSheet: Binding.constant(true),
            captureImage: UIImage(named: "preview_use")!)
    }
}

CoreImageに多数の編集機能がある

なるほど、カメラ機能の実装はiPhone端末がないとダメだな

[自然言語処理] Amazon Lexを使ってみる

Create botで OrderFlowersを選択する

Runtime roleはbasic Amazon Lex permissionsにします。
Idle session timeoutは5minutesにします。
そして Select languageをJapaneseにしてcreate

定義されたSlotsを回収しようとする
FlowerType
PickupDate
PickupTime

Confirmation promptにチェックがあると、すべてのスロット値が取得できた時点で確認

footerのbuildを押下します。

会話になってないね。精度はイマイチなのかな。
あまりamazon lexで開発しているって聞かないですね。