20210606のSwiftに関する記事は7件です。

xcodeprojeにSwiftLintを導入する

はじめに xcodeに初めてSwiftLintを入れるので、メモとして記事を書いています。 他の初学者の方の参考になれば幸いです。 xcodeprojeにSwiftLintを入れるための前準備 CocoaPodsをinstallしておく projectを作成しておく SwiftLintの導入方法 ターミナルを開き、cdコマンドで導入したいprojectがあるファイルに移動 pod initコマンドでPodfileを作成 作成されたPodfileを開き、#Pods for ディレクトリ名 の下の行に pod 'SwiftLint'を入力 ターミナルでpod installコマンドを入力 $cd ディレクトリ名 $pod init // 作成されたPodfileにpod 'SwiftLint'を入力 $pod install
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SQLite.swift でSQLiteを操作する

まえがき Swiftに入門中の友人に向けて説明している記事になります。 SQLite.swift 導入手順 今回はSwift Package Managerで導入する Xcodeから File > Swift Package > Add Package Dependency を選択 https://github.com/stephencelis/SQLite.swift.git で検索 Versionを選択(今回は特に何も考えずデフォルト設定) Finish! XcodeのUI上で入れたPackageも確認できる! SQLiteを操作してみる 今回やることは以下 - データベースファイルを作成 - userテーブルを作成 - userの追加(Insert) - userの検索(Select) 1. データベースファイルを作成 Databaseクラス作成を作成して下記を実装 (ViewControllerクラスで実装してもいいけど分けておいたほうがわかりやすそうなので今回はクラスを分ける) Database.swift import Foundation import SQLite let FILE_NAME = "sample.db" class Database { var db: Connection init() { // DBファイルの作成先のパスを生成 let filePath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(FILE_NAME).path // DBファイル作成/開く db = try! Connection(filePath) } } ちゃんとViewController側で初期化することを忘れずに。 ViewController.swift import UIKit class ViewController: UIViewController { var database = Database() override func viewDidLoad() { super.viewDidLoad() } } 実行後Finderでディレクトリを見てみると無事ファイルが生成されています。 2.userテーブルを作成 Database.swift class Datastore { var db: Connection init() { // DBファイルの作成先のパスを生成 let filePath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(FILE_NAME).path // DBファイル作成/開く db = try! Connection(filePath) // DBにテーブル作成 let users = Table("users") do { try db.run(users.create { t in t.column(Expression<Int64>("id"), primaryKey: true) t.column(Expression<String?>("name")) t.column(Expression<String>("email"), unique: true) }) } catch {} } } do {} catch {} でくくってる理由は2回目移行で動かす時にすでにテーブルが作成されている状態になるのでもう一度作ろうとしてエラーになるのでそれを無視するため。(もっといい書き方ありそうなきもするけど一旦これでいいかな) SQLiteの中を見れるGUIで確認するとちゃんと作成できてることが確認できる。 ごちゃごちゃしてきたのでUserDatastoreってクラス作ってUserテーブルはそっちで触るような実装に整理することにした。 Database.swift class Database { let db: Connection let userDatastore: UserDatastore init() { // DBファイルの作成先のパスを生成 let filePath = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false).appendingPathComponent(FILE_NAME).path // DBファイル作成/開く db = try! Connection(filePath) // UserDatastoreを初期化 userDatastore = UserDatastore(db: db) } } class UserDatastore { private let table = Table("users") private let id = Expression<Int64>("id") private let name = Expression<String>("name") private let email = Expression<String>("email") private let db: Connection init(db: Connection) { self.db = db do { try self.db.run(table.create { t in t.column(Expression<Int64>("id"), primaryKey: true) t.column(Expression<String>("name")) t.column(Expression<String>("email"), unique: true) }) } catch {} } } 3. userの追加(Insert) 初期データでも入れてみる。 userテーブルの初期データというていで実装する(マイグレーション) Database.swift class Database { 省略... } class UserDatastore { private let table = Table("users") private let id = Expression<Int64>("id") private let name = Expression<String>("name") private let email = Expression<String>("email") private let db: Connection init(db: Connection) { self.db = db do { try self.db.run(table.create { t in t.column(Expression<Int64>("id"), primaryKey: true) t.column(Expression<String>("name")) t.column(Expression<String>("email"), unique: true) }) // 初期データを入れる let migrationItems = [ ["name": "Alice", "email":"alice@mac.com"], ["name": "Bob", "email":"bob@mac.com"] ] migrationItems.forEach { row in try? insert(name: row["name"]!, email: row["email"]!) } } catch {} } func insert(name: String, email: String) throws { let insert = table.insert(self.name <- name, self.email <- email) try db.run(insert) } } 内容的にはinsertの関数を作成、データでぐるぐるループしてinsertの関数を実行する。 try self.db.run(table.create... の実行で2回目移行はエラーが発生して後続の処理(ループしてインサートする処理)が動かなくなるので初回の1回目しか実行されないため初期データが2重で入ることもない。 (ちゃんとマイグレーションするなら作り込んだほうがいいかもだけど一旦これで。) 中みるとちゃんとデータが入ってる。(2回実行されてもデータが増えない) データが入らない場合はsample.dbのファイルごと一回消してやってみる。 4.userの検索(Select) Userテーブルに入ってるすべてのデータを取得してTableViewで表示してみる Database.swift class UserDatastore { 省略... func find() -> [User] { var results = [User]() // エラー起こした場合は空の配列を返却 guard let users = try? db.prepare(table) else { return results } for row in users { results.append(User(id: row[self.id], name: row[self.name], email: row[self.email])) } return results } } class User { let id: Int64 let name: String let email: String init(id: Int64, name: String, email: String) { self.id = id self.name = name self.email = email } } Userクラスを追加したのとUserDatastoreクラスにfindの関数を実装 ViewController.swift class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var database = Database() var datas = [User]() override func viewDidLoad() { super.viewDidLoad() datas = database.userDatastore.find() } // Sectionの個数 func numberOfSections(in tableView: UITableView) -> Int { return 1 } func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return datas.count } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let identifier = "HogeCell" let cell: UITableViewCell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath) cell.textLabel?.text = datas[indexPath.row].name return cell } } ユーザIDで検索もしたい。 Database.swift class UserDatastore { 省略... func findById(id: Int64) -> [User] { var results = [User]() // エラー起こした場合は空の配列を返却 guard let users = try? db.prepare(table.where(self.id == id)) else { return results } for row in users { results.append(User(id: row[self.id], name: row[self.name], email: row[self.email])) } return results } } ViewController.swift class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { var database = Database() var datas = [User]() override func viewDidLoad() { super.viewDidLoad() // datas = database.userDatastore.find() datas = database.userDatastore.findById(id: 2) } 省略... 感想 初めてちゃんとQita書いた気がするけどなんかちょっとモチベーション上がったから定期的にかけるといいな。 Swift Package Manager 初めて使ってみたがわかりやすくて好き。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SwiftUI】TabViewに立体感を出してみる

はじめに 今回は、SwiftUIのTabViewに少し手を加えてちょっとおしゃれに移動するようにしたいと思います。 1.作ったもの こちらです。画面遷移の際にViewがズームアウト→移動→ズームインで元に戻る。 といった動作をします。 ※gifなのでカクカクしてますが、本来はスムーズに動作します。 このようにすることで移動動作に立体感がでて、背景色を統一することでシームレスに移動している感じが出ます。 2.ベースの実装 まずはベースとなるPageViewを作る ベースは.tabViewStyle(PageTabViewStyle())で指定している通りPageViewとなります。 今回はサンプルとして四角形3つをPageViewで切り替えるViewとして定義しています。 現在のViewを示すtag番号をselectionで定義しており、 BACKボタン、NEXTボタンで更新して遷移するようにしています。 ContentView.swift struct ContentView: View { @State private var selection : Int = 0 var body: some View { VStack { TabView(selection: self.$selection) { Rectangle() .fill(Color(.white)) .border(Color(.black)) .tag(0) .scaleEffect(self.ratio) Rectangle() .fill(Color(.red)) .border(Color(.black)) .tag(1) .scaleEffect(self.ratio) Rectangle() .fill(Color(.blue)) .border(Color(.black)) .tag(2) .scaleEffect(self.ratio) } .tabViewStyle(PageTabViewStyle()) HStack { Button("BACK") { if self.selection > 0 { self.selection -= 1 } } Button("GO") { if self.selection < 3 { self.selection += 1 } } } } } } 動作を見てみる ご覧の通りベースはできました。ここからズームインアウトのアニメーションをつけていきます。 ※解説用にデザインを簡略化して載せています。 3.ズームインアウト動作を実装する やりかた さて、本題ですがViewの大きさを.scaleEffect()の値を操作することでズームインアウトのアニメーションを実現しています。 今回の流れとしては  GOボタンを押す  →scaleEffect(0.5)にしてViewを小さくする。  →selectionを更新してViewを移動  →secaleEffect(1.0)にして倍率を戻す。 となります。 実装 Viewの倍率を状態変数で定義する。 Viewの倍率を状態変数ratioとして定義します。 そして各Rectangle()のモディファイアに.scaleEffect(self.ratio)を設定します。 こうすることでself.ratioを変えることでスケールを自由に変えることができます。 また、.transition(.slide)と.animation(.easeInOut)を設定することで 遷移するときのアニメーションを設定しています。 struct ContentView: View { @State private var ratio : CGFloat = 1.0 var body: some View { VStack { TabView(selection: self.$selection) { Rectangle() .scaleEffect(self.ratio) Rectangle() .scaleEffect(self.ratio) Rectangle() .scaleEffect(self.ratio) } .tabViewStyle(PageTabViewStyle()) .transition(.slide) .animation(.easeInOut) } } ボタンのアクションに組み込む 先ほど定義してself.ratioをボタンを押した時に0.5、 1秒後にselectionを進めてその1秒後にself.ratioを1.0に戻しています。 ”1秒後に”の部分の実装はTimerを使っています。 (Timerについてはこちらに記載していますので興味のある方はご覧ください。) Button("BACK") { if self.selection > 0 { self.ratio = 0.5 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) {timer in self.selection -= 1 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in self.ratio = 1.0 } } } } Button("GO") { if self.selection < 3 { self.ratio = 0.5 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) {timer in self.selection += 1 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in self.ratio = 1.0 } } } } 動作を見てみる いい感じに完成しました! あとはRectangleの部分を自分の好きなViewにすることでカスタマイズができるかと思います。 おわりに 作ってみて思いましたが、Viewの遷移に毎回2秒かかるのは結構ストレスなので、 メイン画面のメニューとしては使えないかなと。 アプリのチュートリアル画面とかで順番に見せるとかであれば使えそうです。 また、一番最初のデモで見せたように枠線をなくして背景色を全部同じにすると、 シームレスに移動しているように見えます。 そしてスケールする対象を変えるとこのようにボタンだけ正面に残しておく といったこともできますので自由にカスタマイズしてみてください。 おまけ 今回使用したコードの全文をこちらです。 ContentView.swift import SwiftUI struct ContentView: View { @State private var selection : Int = 0 @State private var ratio : CGFloat = 1.0 var body: some View { VStack { TabView(selection: self.$selection) { Rectangle() .fill(Color(.white)) .border(Color(.black)) .tag(0) .scaleEffect(self.ratio) Rectangle() .fill(Color(.red)) .border(Color(.black)) .tag(1) .scaleEffect(self.ratio) Rectangle() .fill(Color(.blue)) .border(Color(.black)) .tag(2) .scaleEffect(self.ratio) } .tabViewStyle(PageTabViewStyle()) .transition(.slide) .animation(.easeInOut) HStack { Button("BACK") { if self.selection > 0 { self.ratio = 0.5 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) {timer in self.selection -= 1 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in self.ratio = 1.0 } } } } Button("GO") { if self.selection < 3 { self.ratio = 0.5 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) {timer in self.selection += 1 Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { timer in self.ratio = 1.0 } } } } } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

スイフト勉強_ データタイプ 深化 (コレクション型)

前回はデータタイプ安心,タイプ別称,チュープルについて調べた。 今日はそれに続いて、コレクション型について調べてみようと思う。 コレクション型(Collection Type) swiftでは、チュープルの他にも多くのデータをまとめて保存·管理できるように、ケレクションタイプを提供している。 コレクションタイプには配列(Array)、ディクショナリー(Dictionary)、セット(Set)などがある。 まずはコレクションの代表的な3タイプについて見てみよう。 1.配列(Array) 配列は同じタイプのデータを一列に並べた後、順番に保存する形のコレクションで、それぞれ違う位置に同じ値を保存することができる。 順番に保存されるという点と、同一の値を複数回保存できるという特徴がある。 配列タイプを宣言する方法は様々である。 一般的に変数を宣言する方式のように、var と let を使って宣言すればよい。 Arrayというキーワードと、配列中に保存するタイプを組み合わせて使用することもでき、大括弧を使用して配列タイプであることを表記することもできる。 空の配列も生成できる。 var name1: Array<String> = ["abc","def","ghi"] var name2: [String] = ["jkl", "mno"] var name3: Array<String> = Array<String>() var name4: [String] = [String]() var name5: [String] = [] name3.isEmpty // true name4.isEmpty // true name5.isEmpty // true name2.count //2 name1.count //3 配列の各要素はインデックス番号からアクセスできる。 上述のように配列の場合は順序どおりに保存するものであるため、当該順番に存在する値を呼ぶか、交換することが可能である。 ここで重要なことは、始める番号は0から始めるという点である。 次のコードを見て説明を続けたい。 print(name2[0]) // jkl name2[1] = "pqr" // ["jkl", "pqr"] name2[2] = "stu" // error! name2.append("stu") //name2配列の最後に追加 ["jkl", "pqr", "stu"] name2.append(contentsOf: ["vwx", "yz"]) // ["jkl", "pqr", "stu", "vwx", "yz"] name2.insert("mno", at: 1) // ["jkl", "mno", "pqr", "stu", "vwx", "yz"] // name2.insert(contentsOf: )も可能 name2[2] // pqr name2.index(of:"pqr") // 2 name2.index(of: "pqrz") // nil name2.first // jkl name2.last // yz let first = name2.removeFirst() //一番目を削除して、返上 let last = name2.removeLast() // 最後のものを削除して、返上 let num2 = name2.remove(at: 2) // 該当インデックスの要素を削除して返却·範囲を外れた場合、エラー first // jkl last // yz num2 //stu name2 // ["mno", "pqr", "vwx"] 2.ディクショナリー(Dictionary) ディクショナリーはそれぞれの要素が順番に身長と値段のペアで構成されるコレクションタイプだ。 したがって、保存される際に常に鍵と値がペアを保持するため、同一の鍵を使うことができない。 var dic1 : Dictionary<String, Int> = Dictionary<String,Int>() var dic2 : [String : Int] = [String : Int]() var dic3 : [String : Int] = [:] var dic4 : [String : Int] = ["a" :1, "b" : 2, "c" : 3] var dic5 = [1:"a", 2:"b", 3:"c"] dic1.isEmpty // true dic4.count // 3 Dictionary の値にアクセスするためには鍵を使わなければならない。 dic4["a"] // 1 dic4["d"] // nil dic4["e"] = 5 //add success dic4["f"] = 6 dic4.removeValue(forKey: "f") //delete f, f value dic4["f", default: 0] // 0 for (key,value) in dic4{ print("\(key):\(value)") // a:1 c:3 e:5 b:2 // 順序がない。 } let order1 = dic4.sorted(by: <) print(order1) // [("a", 1), ("b", 2), ("c", 3), ("e", 5)] let order2 = dic4.keys.sorted(by: <) print(order2) // ["a", "b", "c", "e"] 3.セット(Set) セットは、同タイプのデータを順番なく一つにまとめて保存する形のコレクションタイプだ。 セット内の値はすべて唯一の値、重複する値が存在しない。 それで、順序が重要でなかったり、各要素が唯一の値でなければならない場合に使用する。 var set1 : Set<String> = Set<String>() var set2 : Set<String> = [] var set3 : Set<String> = ["a", "b", "c", "c"] var set4 = [1,2,3] //タイプ推論を使うと配列と認識してしまう。 set3.isEmpty // false set3.count // 3 , 重複する値は一つだけ保存される。 set3.insert("d") set3.count // 4 set3.remove("b")// return b set3.remove("f") // nil Set は内部の値がすべて唯一であることを保障するため、集合関係を表現するときに有用に使える。 そして、sorted 関数を活用して整列された配列を返すこともできる。 let eng: Set<String> = ["a", "A", "b", "B"] let eng2: Set<String> = ["A", "B", "C", "D"] let intersect: Set<String> = eng.intersection(eng2) // ["A","B"] let symmetric: Set<String> = eng.symmetricDifference(eng2) // ["a","b","C","D"] let unionSet: Set<String> = eng.union(eng2) // ["a","A","b","B","C","D"] let substract: Set<String> = eng.substracting(eng2) // ["a","b"] unionSet.sorted() // ["A","a","B","b","C","D"] /* その他の集合関連のBool結果を示す関数 A.isDisjoint(with: B) // AとBの積集合が存在しない場合、True A.isSubset(of:B) // AがBの部分集合の場合True A.isSuperset(of:B) // AがBの全体集合の場合、True */ 次は最後に列挙形について見ていくことにする。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Xcode初心者必見】必ずボタンを配置するところまでできる方法

目次 1.はじめに 2.環境 3.本題 -3-1 xcodeをインストールしたけど立ち上がらない -3-2 新規プロジェクトの設定何選べばいいの? -3-3 ボタンを追加するにはどこを押せばいいの? 4.最後に 1. はじめに xcodeをインストールしていざ書籍で勉強しよう!動画で勉強しよう!とおもってもサラッと書いてあるけどその画面に行けないんだよな..など困ることはないでしょうか。 私もその一人で本を買ったはいいけれどつまづいていました。その経験からxcodeを入れたばかりの初心者の方がつまづきやすいポイントを丁寧に解説いたします。 2. 環境 Xcode:Version 12.5 PC:MacBook Air(M1,2020) OS:macOS Big Sur バージョン11.3.1 3. 本題 3-1. xcodeをインストールしたけど立ち上がらない 1.xcodeのアイコンをタップする 2.左上に”xcode”と書かれていればOK! 3.新規プロジェクトを作成するには、File>New>Projectを選択 4.Appを選択しNextボタンを押す 5.新規プロジェクトに名前をつけるところまでいけたらOK! 3-2. 新規プロジェクトの設定何選べばいいの? 新規プロジェクトを作成する画面まで行ったら今度は各項目どれ選んだらいいのという状態だと思います。解説していきます。 項目名 説明 Product Name プロジェクトファイルの名前 Team プルダウンを押してでてくる名前があればそちらを選択します。なければプロジェクト作成後登録していきますので一旦Noneで大丈夫です。 Organization Identifier アプリをリリースしない段階でしたら適当で大丈夫です。com.appとかでいいと思います。 Bundle Identifier アプリのID名。Product NameとOrganization Identifierを入力すると自動で入力されるのでそのままで大丈夫です。 Interface story boardもしくはSwift UIを選択します。SwiftUIは2019年にできたばかりのInterfaceです。アプリを作る際に参考にする書籍がどちらで書いてあるか調べて同じにする必要があります。以下の画像のファイル構成なら"SwiftUI"です。こちらなら"story board"です。 Life Cycle UIKit App Delegate か SwiftUI Appかを選択します。Interfaceでstoryboardを選んだら UIKit AppDelegate,SwiftUIを選んだら SwiftUI Appを選択します。 Language SwiftかObject-cを選択します。基本はswiftで良いと思います。 設定をしたらNextボタンを押して次に進みます。 プロジェクトを保存する場所を聞かれるので、自分が入れたいフォルダのところを選択し作成ボタンを押します。 (先程TeamでNoneを選択した方は) Signing&Capabilitiesを選択します。 Teamのプルダウンを押して、Add an account...を選択します。 こちらからApple IDでsign upしましょう。 3-3. ボタンを追加するにはどこを押せばいいの? (storyboardの場合) こちらの画面の左側の部分で「LaunchScreen.storyboard」を選択する。 右上の"+"ボタンを押す (SwiftUIの場合) こちらの画面の左側の部分で「Main.storyboard」を選択する。 右上の"+"ボタンを押す (storyboard/SwiftUI共通) 以下画面が表示される。表示されていない場合は、プラスボタンを押した後に出てくるポップアップ画面の 真ん中の3つボタンがある部分の一番左が選択されていることを確認する。(朝日、絵の具みたいなアイコンじゃない丸の中に四角が入っているボタンを選択) Buttonを選択し、storyboard上にドラック&ドロップする 4. 最後に これでボタンの配置までできました。 Xcodeプロジェクトを新規作成する部分からボタンをstoryboard上に配置するところまでで つまづいてしまった点がございましたらコメントお願いします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【swift】textfieldを設置し文字制限をつける

自身で実装した内容をまとめていきます。 指定の箇所をタップしたとき、キーボードを表示し、文字制限をつける処理を行う。 やること 1.StorybordにTextFieldを設置する 2.キーボードを閉じる動作をつける 3.入力文字制限をつける という流れになります。 1.StorybordにTextFieldを設置する まずはStorybord常にTextFieldを設置します。 右上の「+」ボタンを押し 「TextField」を選択します。 ちょっと見づらいですが、中央にTextFieldを設置することができました。 これでビルドしてみます。 先ほど設置したTextFieldをタップするとキーボードが表示されます。 もし表示されなければ [I/O]->[Keyboard]->[Toggle Software Keyboard]を選択し、再度TextFieldをタップすることでキーボードがでます。 2.キーボードを閉じる動作をつける TextFieldの設置ができました。 しかし、キーボードを閉じることができません・・・。 右下の「改行」や「return」をタップしても、キーボード外をタップしても閉じることができません。 閉じる処理をつけなければいけません。 Storybord上のTextFiledで右クリックをし[Did End On Exit]をViewControllerへドラッグします。 これで「改行」「return」で閉じることができます。 次にTextField外すなわちキーボード外をタップしたときにキーボードを閉じる処理を加えます。 「touchesBegan」メソッドをオーバーライドします。 そしてendEditingという処理を入れてあげることでキーボード外をタップしたときに閉じることができます。 swift override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.view.endEditing(true) }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【swift】textfieldを設置し文字数制限をつける

自身で実装した内容をまとめていきます。 指定の箇所をタップしたとき、キーボードを表示し、文字制限をつける処理を行う。 やること 1.StorybordにTextFieldを設置する 2.キーボードを閉じる動作をつける 3.入力文字制限をつける という流れになります。 1.StorybordにTextFieldを設置する まずはStorybord常にTextFieldを設置します。 右上の「+」ボタンを押し 「TextField」を選択します。 ちょっと見づらいですが、中央にTextFieldを設置することができました。 これでビルドしてみます。 先ほど設置したTextFieldをタップするとキーボードが表示されます。 もし表示されなければ [I/O]->[Keyboard]->[Toggle Software Keyboard]を選択し、再度TextFieldをタップすることでキーボードがでます。 2.キーボードを閉じる動作をつける TextFieldの設置ができました。 しかし、キーボードを閉じることができません・・・。 右下の「改行」や「return」をタップしても、キーボード外をタップしても閉じることができません。 閉じる処理をつけなければいけません。 Storybord上のTextFiledで右クリックをし[Did End On Exit]をViewControllerへcontrolキー + ドラッグします。 これで「改行」「return」で閉じることができます。 次にTextField外すなわちキーボード外をタップしたときにキーボードを閉じる処理を加えます。 Storybord上のTextFiledをViewControllerにcontrolキー + ドラッグし、IBOutletを作成します。 「touchesBegan」メソッドをオーバーライドします。 そしてendEditingという処理を入れてあげることでキーボード外をタップしたときに閉じることができます。 ViewController.swift class ViewController: UIViewController { //Storybordからcontrolキー + ドラッグ @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() } //ここでtouchesBeganをオーバーライド override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { //閉じるための処理を記述します。 self.view.endEditing(true) } } これでキーボード外をタップしたときも閉じるようになります。 3.入力文字制限をつける TextFieldに文字制限をつけてみます。 指定した文字数以上は入力できないようにします。 @objc func maxLength(textField: UITextField) { guard let text = textField.text else { return } let length = 10 textField.text = String(text.prefix(length)) } lengthで文字数を決めます。 textField.text = String(text.prefix(length)) でTextFiled内の最大文字数をlengthにします。 このメソッドをaddTargetで適用させます。 textField.addTarget(self, action: #selector(maxLength(textField:)), for: .editingChanged) これで文字数制限をつけることができました。 しかし、この状態では日本語の変換や濁点などをつけることができません 1文字入力されるたびに先ほど作成したmaxLengthメソッドの処理を行なってしまっています。文字が入力されるたびに確定されてしまうためですね。 これを避けるには if textField.markedTextRange != nil { return } をmaxLengthメソッド内に入れてあげて文字入力中はメソッドの処理を行わないようにしてあげます。 これで問題なく変換や濁点をつけることができます。 最終的に以下になります。 class ViewController: UIViewController { @IBOutlet weak var textField: UITextField! override func viewDidLoad() { super.viewDidLoad() textField.addTarget(self, action: #selector(maxLength(textField:)), for: .editingChanged) } @IBAction func textFieldClose(_ sender: Any) { } override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { self.view.endEditing(true) } @objc func maxLength(textField: UITextField) { if textField.markedTextRange != nil { return } guard let text = textField.text else { return } let length = 10 textField.text = String(text.prefix(length)) } } 以上です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む