- 投稿日:2021-01-27T21:43:53+09:00
?yawacom - ?Storyboardを使わず画面遷移を行う
2021/01/27現在編集中
Storyboardの削除
Storyboardはぱっと見わかりやすくて最高だとおもっていたのですが,画面が増えるにつれ重くなっていったり,いろいろなプロパティを直接Storyboardに記述することになるので後々修正が大変だったりします.なので今回はStoryboardを使わずコードとxibで作っていきます.
ということで
?Main.storyboard はいらないので削除
?General -> Deployment Info -> Main Interface のMainという文字列を消して空欄に
?Info.plistのApplication Scene Manifest -> Scene Configuration -> Application Session Role -> Item -> Storyboard Name を➕➖の➖を押して削除
を行います.▽参考文献
【Swift4】アプリの初回起動画面を storyboard ではなく xib にするアプリ初回起動
まずアプリを立ち上げた時にユーザ登録画面に行くのかログイン画面に行くのかを分岐させます.
最初に必ずAppDelegate/SceneDelegateが呼ばれるので,そこでまずRoutingViewControllerに移動します.
今回はターゲットをiOS13以上にしたためSceneDelegateに書いていきます.SceneDelegate.swiftimport UIKit class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). guard let _ = (scene as? UIWindowScene) else { return } // RoutingViewController呼び出し if let windowScene = scene as? UIWindowScene { let window = UIWindow(windowScene: windowScene) window.rootViewController = UINavigationController(rootViewController: RoutingViewController.init()) self.window = window window.makeKeyAndVisible() } } 以下略(変更なし)ここでUINavigationControllerを設定することで今後画面遷移が楽チンにできるようになります!
ユーザ登録画面へ
そのRoutingViewControllerでユーザ登録画面かログイン画面かの分岐させます.今回はユーザ登録画面から作るのでひとまずユーザ登録画面に遷移するように,openLaunchScreen関数の引数に
.registrationを指定しています.RoutingViewController.swiftimport Foundation import RxSwift final class RoutingViewController: UIViewController { override func viewDidLoad() { // ひとまず必ずユーザ登録画面に遷移するように self.openLaunchScreen(launchScrenType: .registration) } } extension RoutingViewController { private func openLaunchScreen(launchScrenType: LaunchScreenType) { switch launchScrenType { case .login: // ログイン画面へ移動 break case .registration: // ユーザ登録画面へ移動 RegistrationViewController.start(self) break } } }ユーザ登録画面の作成
ユーザ登録画面を作ります.
新規ファイル作成からxibファイルとViewControllerを作成します.今回はRegistrationViewController.swiftとRegistrationView.xibという名前にしました.xibとViewControllerの接続
まず最初にRegistrationViewとRegistrationVCがOutlet接続したりできるようにClassに登録します.xibを開いた時のClassのところに
RegistrationViewControllerと入力します.
次にFile's OwnerとViewを紐付けます.Outlet接続する感じでFile's OwnerからViewに青線を持ってくると結べます.写真のview-Viewのようにつながってたらできてます!
とりあえずtextboxを置いてみる
すごい適当に置いてみました.目立つのでピンク色でど真ん中に配置しています.
コードを書く
ユーザ登録ビューを書いていきます.
さきほど配置したtextboxをuserNameという名前でOutlet接続し,viewDidLoad()で赤色にしています.ビュー全体の背景は黄緑にしています.また,RoutingViewController.swiftで分岐する際
RoutingViewController.swiftcase .registration: // ユーザ登録画面へ移動 RegistrationViewController.start(self)とあったと思います,この
start関数をRegistrationViewController.swiftに書いていきます.
start関数ではnavigationControllerが持っているpushViewControllerというものを使い画面遷移をしています.
currentVCには元々のRoutingViewControllerが入っており,nextVCには遷移先のRegistrationViewControllerが入っています.RegistrationViewController.swiftimport Foundation import RxSwift final class RegistrationViewController: UIViewController { @IBOutlet weak var userName: UITextField! static func start( _ currentVC: UIViewController, animated: Bool = false ) { let nextVC = RegistrationViewController(nibName: "RegistrationView", bundle: nil) // .initは省略可能 currentVC.navigationController?.pushViewController(nextVC, animated: animated) // 上のナビゲーションバーを非表示 currentVC.navigationController?.navigationBar.isHidden = true } override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .green userName.backgroundColor = .red print("レジストレーションビューコントローラー") } }するとこんな感じになります.めちゃめちゃ気持ち悪いですがわかりやすいですね!ちゃんと赤色のtextboxになっています.
![]()
ここからはデザインをいい感じに作っていきます.
コードはGitLabにあげています.next記事
かけたらここに載せます.
- 投稿日:2021-01-27T20:30:12+09:00
初めて作るアプリのアイコンを作成する
なぜ記事にするのか
本当に無知(アプリ開発初心者)の段階で、どのような考え方、過程でアプリのアイコンを作ったか記録するため
どんなアプリを作っているのか
以下の記事で説明していますが、台湾中国語および日本語勉強アプリです。アプリのタイトルは「AtaCon」に決めました。
初めて作るアプリのタイトルを決める要件
・台湾中国語と日本語が学習できるとわかるようにしたい(国旗をいれるとか)
作る過程
YouTubeをやっており、動画編集で使うためAdobe Creative Cloudを契約しています。
そのため、Adobe illustratorでアイコン作成をしました。
完成したアイコンはこれです。
このデザインにセンスがないといことはわかりますが、どうやってセンスのいいアイコンを作れるのかわかりません、、、
とりあえず要件は満たしたのでよしとしますが、いいアイデアがあれば是非教えてください。作る過程(2021/01/28追記)
上のアイコンが少しごちゃごちゃしていて気に入らなかったのですぐに作り替えました。
テトラポッドでコンクリートを表現しました。参考URL
【Xcode】アプリアイコンの作成と設定方法
https://qiita.com/digital-creator-masa/items/57ae8e84665205369481【2021年版】もう配色デザインには迷わない!すごい無料カラーパレットツール72個まとめ
https://photoshopvip.net/72189
- 投稿日:2021-01-27T19:16:12+09:00
RxSwift6 の変更点まとめ
RxSwiftの6.0が公開されたので変更点をサンプル付きでまとめました。
GitHubのリリースノートやDEV Communityでもまとめられています。
dynamicMemberLookupを使用したバインダーの自動合成今ままでは以下のような
ExampleViewがあったときclass ExampleView: UIView { var text: String }
Binderを毎回記述することでextension Reactive where Base: ExampleView { var text: Binder<String> { Binder(base) { base, title in base.text = text } } }このように
streamをクラスにbindすることができました。let exampleView = ExampleView() Observable.of("text").bind(to: exampleView.rx.text)
RxSwift 6からは、どのクラスに対しても、Binderを自動的に合成します。そのため、上記のBinderのコードをすべて削除してコードをすっきりさせることができるようになりました。
Infallibleエラーを流さない
Observableです。Infallible<String>.create { observer in observer(.next("next")) observer(.completed) // これはコンパイルエラー // observer(.error(NSError())) return Disposables.create {} }
Observableと比べると微妙にメソッドが違います。Observable<String>.create { observer in observer.on(.next("next")) observer.on(.error(NSError())) observer.on(.completed) return Disposables.create {} }また RxCocoa の
DriverとSignalは常にMainSchedulerを使用しリソースを共有するのに対して、Infallible、基本的にObservableである点が異なります。
drive()とemit()で複数のobserverやrelayにバインドできるようになりましたlet myButton = UIButton() Driver.of(true).drive(myButton.rx.isEnabled, myButton.rx.isSelected) Signal.of(true).emit(myButton.rx.isEnabled, myButton.rx.isSelected)
decode(type:decoder:)が追加されましたCombineと同様に、Dataを出力するObservableに対して動作するデコード演算子が追加されました。
service .fetchJSONUsers() // Observable<Data> .decode(type: [Example].self, decoder: JSONDecoder()) // Observable<[Example]>
SingleがSwiftのResultを使うようになりました。subscribe の命名が変わったため警告が出るようになりました。
// RxSwift 5 // 'subscribe(onSuccess:onError:onDisposed:)' is deprecated: renamed to 'subscribe(onSuccess:onFailure:onDisposed:)' single.subscribe( onSuccess: { value in print("Got a value: \(value)") }, onError: { error in print("Something went wrong: \(error)") } ) // RxSwift 6 single.subscribe( onSuccess: { value in print("Got a value: \(value)") }, onFailure: { error in print("Something went wrong: \(error)") } )
ReplayRelayが追加されました新しく
ReplaySubjectをラップしたReplayReplayが追加されました。
BehaviorRelayやPublishRelayと同様にエラーを流しません。
withUnretainedが追加されましたいままでは
weakキーワードを使い循環参照をせずにクラスに値を渡していました。viewModel.importantInfo .subscribe(onNext: { [weak self] info in guard let self = self else { return } self.doImportantTask(with: info) }) .disposed(on: disposeBag)RxSwift 6 からは
withUnretainedを使うことで綺麗に記述することができます。viewModel.importantInfo .withUnretained(self) // (self, info) のタプルになる .subscribe(onNext: { owner, info in owner.doImportantTask(with: info) }) .disposed(by: disposeBag)
distinctUntilChange(at:)で Key Paths をつかるようになりました。Observable.of(Example(text: "1"), Example(text: "2")).distinctUntilChanged(at: \.text) struct Example { let text: String }
DisposeBagのビルダー関数でSwiftUIのようにカンマを使わずに記述することができます。var disposeBag = DisposeBag { observable1.bind(to: input1) observable2.drive(input2) observable3.subscribe(onNext: { val in print("Got \(val)") }) } disposeBag.insert { observable4.subscribe() observable5.bind(to: input5) }
ignoreElementsがObservable<Never>を返すようになりました※ 修正前
public func ignoreElements() { -> Completable { return self.flatMap { _ in return Observable<Never>.empty() } .asCompletable() }※ 修正後
public func ignoreElements() { -> Observable<Never> { self.flatMap { _ in Observable<Never>.empty() } }
UIApplicationにRxのExtensionが追加されました以下変数が追加されました
didEnterBackgroundwillEnterForegrounddidFinishLaunchingdidBecomeActivewillResignActivedidReceiveMemoryWarningwillTerminatesignificantTimeChangebackgroundRefreshStatusDidChangeprotectedDataWillBecomeUnavailableprotectedDataDidBecomeAvailableuserDidTakeScreenshot命名変更
メソッドのリネームがありました。
RxSwift 5 RxSwift 6 catchError(_:)catch(_:)catchErrorJustReturn(_:)catchAndReturn(_:)elementAt(_:)element(at:)retryWhen(_:)retry(when:)takeUntil(_:)take(until:)takeUntil(behavior:_:)take(until:behavior:)takeWhile(_:)take(while:)takeWhile(behavior:_:)take(while:behavior:)take(_:)take(for:)skipWhile(_:)skip(while:)takeUntil(_:)take(until:)observeOn(_:)observe(on:)subscribeOn(_:)subscribe(on:)前のメソッドを使ってもエラーにはならずに以下のような警告が表示されます。
'catchError' is deprecated: renamed to 'catch(_:)'
- 投稿日:2021-01-27T17:01:11+09:00
初めて作るアプリのタイトルを決める
なぜ記事にするのか
本当に無知(アプリ開発初心者)の段階でどのようにタイトルを決めたのか、記録を残しておくため。
どんなアプリを作っているか
日本語文章とその翻訳を一対にしており、?を押すことで台湾中国語が表示できるようになっています。
「Next」と「Back」で文章を変更します。
右上の「lang」を押すことで、日本語と台湾中国語を切り替えることができます。
また、文章の表示と同時に録音音声を鳴らしています。
ちなみにですが、日本語音声は僕、台湾語音声は僕の彼女が台湾人なのでお願いしています。録音音声の処理はpythonで書いています。
pythonを使って録音した音声を採番、無音部分をカットする【プログラミング超初心者】
https://qiita.com/atamakonkurii/items/af8cddaccf4565361086制約
日本人と台湾人に使ってもらいたいので、英語のタイトルがいいかなと考えました。
考える過程
以下の記事によるとアプリのタイトルは3つ考える必要がありそうです。
アプリ製作者必見!アプリタイトルを決めるのに必要な情報まとめ1.アプリ名(呼称)
2.ホーム画面の下にあるタイトル
3.ストア掲載されるタイトルメルカリを例にして説明すると
1は「メルカリ」
2は「メルカリ」
3は「フリマアプリ-メルカリ フリマでかんたんショッピング」
となります。yahoo!乗り換え案内の場合は
1は「Yahoo!乗り換え案内」
2は「Y!乗換案内」
3は「Yahoo!乗換案内 無料で路線図や乗り換えの情報を検索できるアプリ」
といった感じです。言語学習アプリということを伝えたいので、あまり捻らずに行こうかと思います。
思いましたが、以下のタイトルに決定しました。
1.「AtaCon」
2.「AtaCon」
3.「AtamaConcrete 台湾中国語、日本語勉強アプリ」読み方は「アタコン」です。
日本ではすでに使われていない日本語ですが、台湾には日本統治時代の名残りで「頭コンクリート」という言葉が残っているそうです。
意味は頭が固いとかそんな感じらしいです。
日本と台湾の言語的な文化のつながりが垣間見えるタイトルなのではないかと思いこれに決めました。
すぐ変えるかもしれません、、、ちなみに僕がやってるYouTubeのチャンネル名は「頭コンクリ」です。
狙ってやったわけじゃなく、けっこうこの言葉が好きで気に入ってるから結局アプリの名前もこれ関連になってしまいました。
プログラミングと全然関係ないですが、お時間あれば覗いてみてください。
https://www.youtube.com/channel/UC2JHTgLF0wHhkKIPS9sTl0wまとめ
結局かなりテキトーに決めてしまいましたが、記録しておきます。
- 投稿日:2021-01-27T01:23:24+09:00
ViewcontrollerからTabBarControllerへコードで移動する
ViewControllerからTabBarControllerに移動する
まず、最初に下の図のようにViewControllerからTabBarControllerに紐づいてた緑のViewControllerに遷移しても、ViewControllerへの移動なので、
下のタブが表示されません。だから、TabBarViewControllerへ移動する必要があります。
コード
ViewController.swiftimport UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() } @IBAction func FromViewControllertoTabBarController(_ sender: Any) { let storybord=UIStoryboard(name: "Main", bundle: nil) let TabBarController=storybord.instantiateViewController(withIdentifier: "TabBarController") as! UITabBarController //[0]が緑のViewControllerで[1]にすると赤のViewControllerに遷移する let ViewController=TabBarController.viewControllers?[0] as! FirstViewController //TabControllerに遷移した時に最初にどの画面を表示するかを選択する TabBarController.selectedViewController=ViewController TabBarController.modalTransitionStyle = .crossDissolve TabBarController.modalPresentationStyle = .fullScreen self.present(TabBarController, animated: true, completion: nil) } }











