import SwiftUI struct ContentView: View { @State var selected = 0 @State var ItemList = ["apple", "orange", "lemon"] var body: some View { VStack { Text("Hello, World!") Picker(selection: $selected, label: Text("Please choose one")) { ForEach(0 ..< ItemList.count) { Text(self.ItemList[$0]) } } } } }
NavigationLinkを使う
import SwiftUI struct ContentView: View { var body: some View { NavigationView { NavigationLink(destination: TestView()) { Text("Go Test View") } .navigationBarTitle("Top View") } Text("Hello, world!") .padding() } } struct TestView: View { var body: some View { Text("Test View") } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
SwiftUIでチェック付きのListViewを作る
SwiftUIでチェック付きのListViewを作るのが大変でした。SwiftUI beta4 までOKだったのが Beta5でNGになったので、 検索で見つけたサンプルコードがビルドエラーに! 色々やって以下のコードに落ち着きました。 もっといい方法がありそうなんっだけど。なお、チェック部分は手抜きで文字列です。
import SwiftUI var demoData = [Person(name: "Yamada Taro"), Person(name: "Aoki Ichido"), Person(name: "Sato Koji"), Person(name: "Kojima Masao")] struct PersonView: View { @State var selectKeeper = Set<UUID>() var body: some View { VStack { NavigationView { List { ForEach(demoData) { person in SelectableRow(person: person, selectedItems: self.$selectKeeper) } .navigationBarTitle(Text("Selection Demo \(selectKeeper.count)")) } } } // VStack } } struct Person: Identifiable, Hashable { let id = UUID() let name: String } struct SelectableRow: View { var person: Person @Binding var selectedItems: Set<UUID> var isSelected: Bool { selectedItems.contains(person.id) } var isSelectedStr: String { get { if selectedItems.contains(person.id) { return "Yes" } else { return "No" } } } var body: some View { HStack { Button(action: { if(self.isSelected){ self.selectedItems.remove(self.person.id) } else{ self.selectedItems.insert(self.person.id) } }) { Text("\(isSelectedStr)") } Text(self.person.name) } } }
Swiftで正規表現と文字列置換
Swiftで正規表現で特定のパターンを見つけて文字列置換をしてみました。 StringとNSString(前からあるやつ)があって使い分けが必要なのと、文字が何文字目かでマッチした文字を取り出すみたい。
func myMethod(_ inStr: String?) -> String? { guard let html = inStr else {return nil} let html_ns = html as NSString var html_result = html let regExp = try? NSRegularExpression( pattern: ":([^_]+)_([^_]+)_([^:]*):", options: NSRegularExpression.Options()) guard let matches = regExp?.matches(in: html, options: NSRegularExpression.MatchingOptions(), range: NSMakeRange(0, html_ns.length)) else {return nil} for m in matches { let command = html_ns.substring(with: m.range(at: 1)) let param = html_ns.substring(with: m.range(at: 2)) let text = html_ns.substring(with: m.range(at: 3)) let command_esc = NSRegularExpression.escapedPattern(for: command) let param_esc = NSRegularExpression.escapedPattern(for: param) let text_esc = NSRegularExpression.escapedPattern(for: text) switch command { case "page": html_result = html_result.replacingOccurrences( of: ":\(command_esc)_\(param_esc)_\(text_esc):", with: "<button onclick=\"webkit.messageHandlers.Page.postMessage('\(param_esc)')\">\(text)</button>", options: .regularExpression, range: html_result.range(of: html_result)) default: print(“not implemented") } // switch } // for return html_result } // func
上記の関数で 「バナナの説明は:page_123_バナナの説明:をクリック」という文字列があると バナナの説明は
<button onclick="webkit.messageHandlers.Page.postMessage(‘123')">バナナの説明</button>をクリック
という風に置き換えます。
SwiftでXMLをパースする。ありがとうyahoojapan
XMLパーサーは、極論すると、これで終わる。簡単!
こんな感じ。
import SwiftyXMLParser if let path: String = Bundle.main.path(forResource: "hoge", ofType: "txt") { do { // ファイルの内容を取得する let content = try String(contentsOfFile: path) // print("content: \(content)") let xml = try XML.parse(content) var i = 0 while true { guard let str = xml["root", "data", i, "value"].text else { break; } print("\(str)") i += 1 } print("ループ終わり") } catch { print("ファイルの内容取得時に失敗") } // do } else { print("指定されたファイルが見つかりません") } // if let
真面目にやると結構大変です。XMLParser()を使うのだけれど、 要素(エレメント、属性)が1つ見つかる度に、XMLParserDelegateにあるparse(..)という名前の 関数が呼び出されて、結果を取り出して自分で使えるように加工しないといけません。 この辺りを全部やってくれるのが、上記のyahoojapanのコードです。
if let 変数 と guard let 変数
if let a = myFunc() {成功したらやること} else {失敗したらやること}
なお、myFunc()は、成功時は値を返して、失敗時はnil(NULLのこと)を返すように実装する。 これで、通常動作と失敗時の動作が両方書ける。なお、失敗時はaにはnilが入る。
if guard let a = myFunc() else {中断; returnとかexit(-1)とか}
成功時は処理を続けるが、失敗したら処理が続けることができない時の実装形式。 myFunc()は、成功時は値を返して、失敗時はnil(NULLのこと)を返すように実装する。 aには値しか入らない。nilが入ることはなく、失敗時は次の処理ができない。
失敗と成功の処理をしっかり書きなさいというルールです。 なお、if let a = の方は、aがnilかもしれないので、aの値を普通に使おうとすると、 nilを考えてないぜ! っというビルドエラーになる。
SwiftUIでコード内の文字をWebKitで表示してjavascriptの結果を受け取る
ContentView.swift
import SwiftUI struct ContentView: View { var body: some View { WebView(url: URL(string: "dummy")!) } }
WebView.swift
import SwiftUI import WebKit struct WebView: UIViewRepresentable { var url: URL func makeUIView(context: Context) -> WKWebView { let webConfig = WKWebViewConfiguration() let userController = WKUserContentController() userController.add(makeCoordinator(), name: "hoge") webConfig.userContentController = userController let wkWebView = WKWebView(frame: .zero, configuration: webConfig) return wkWebView } func updateUIView(_ uiView: WKWebView, context: Context) { // 普通にurlでブラウズするコード // let req = URLRequest(url: url) // uiView.load(req) // ローカルファイルindex.htmlを表示するコード // guard let path: String = Bundle.main.path(forResource: "index", ofType: "html") // else { return } // let localHTMLUrl = URL(fileURLWithPath: path, isDirectory: false) // uiView.loadFileURL(localHTMLUrl, allowingReadAccessTo: localHTMLUrl) let str = "<!DOCTYPE html>" + "<html>" + "<head>" + "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\"/>" + "<title>スマホでの見え方調整</title>" + "<meta name=\"viewport\" content=\"width=280\" />" + "</head>" + "<body>" + "<input type=\"button\" value=\"Exec\" onclick=\"var number = 123;" + "webkit.messageHandlers.hoge.postMessage(number);\" /><br />" + "<br />" + "</body>" + "</html>" uiView.loadHTMLString(str, baseURL: nil) } func makeCoordinator() -> WebView.Coordinator { return Coordinator() } } // struct extension WebView { class Coordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler { func userContentController( _ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "hoge" { let number = message.body as! Int print("JavaScript is sending a number \(number)") } } } } struct WebView_Previews: PreviewProvider { static var previews: some View { WebView(url: URL(string: "dummy")!) } }