しおメモ

雑多な技術系ブログです。ニッチな内容が多いです。

iOSのキーボードの高さと連動したビューを作る

絶対忘れる自信があるので書いておきます。

なんとなく、この辺りのインターフェースもまた変わりそうな予感がするので、暫定Swift 5iOS 13版です。

NotificationCenter(raw)

NotificationCenterはライフサイクルに合わせてobserverを破棄してくれるので、addObserverの最初の引数で適切なオブジェクトを指定してあげれば、明示的にremoveObserverを呼ぶ必要はないです。

NotificationCenter.default.addObserver(
    self,
    selector: #selector(keyboardWillChangeFrame(_:)),
    name: UIResponder.keyboardWillChangeFrameNotification,
    object: nil
)

Text Fieldをキーボードに追従させて動かす例。
相変わらずI/Fがイケてないので、いったん値を探してNSValueにキャストする必要があります。

@objc private func keyboardWillChangeFrame(_ notification: Notification) {
    guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return }

    let keyboardHeight = UIScreen.main.bounds.height - keyboardFrame.cgRectValue.minY
    textField.transform = CGAffineTransform(translationX: 0, y: min(0, -keyboardHeight + view.safeAreaInsets.bottom))
}

実際に使う場合はSafe Areaの分を考慮する必要があるので、上のコードのような調整をする必要があります。

CGAffineTransformや、layoutIfNeeded()を使えばいい感じのアニメーションになりますが、値は細かくは飛んでこないので、その他の方法を使う場合は、keyboardAnimationDurationUserInfoKeyなども活用します。

f:id:scior:20200215180258g:plain

RxSwift

NotificationCenterにRxが生えてるのでそれを利用します。

 let keyboardHeight: Observable<CGFloat> = NotificationCenter.default.rx.notification(UIResponder.keyboardWillChangeFrameNotification)
    .compactMap { notification -> CGFloat? in
        guard let keyboardFrame = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue else { return nil }

        return UIScreen.main.bounds.height - keyboardFrame.cgRectValue.minY
    }

gemパッケージのCI/CDをGitHub Actionsに移行した

GitHub Actionsを使ってみたかったので、gemパッケージのrake specrubygems.orgへのpushを自動化してみました。

GitHub Actionsの準備

Travis CIなど他のCIと同じく、yamlファイルで設定を記述して、ワークフローを構築します。 yamlファイルはリポジトリ内の.github/workflowsにまとめて置きます。

yamlファイルはActionsのタブから、ブラウザのエディタでも記述することができます。

f:id:scior:20200203005607p:plain

使い方自体の詳細は、下記公式ドキュメントや他の記事を参考にしてみてください。

https://help.github.com/en/actions/automating-your-workflow-with-github-actions

PRに対してRSpecテストを実行する

こちらはRubyのテンプレートがあるので、それを少し修正すれば問題ないです。
Actionsタブにもサジェストされます。

name: RSpec

on: pull_request

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby 2.6
      uses: actions/setup-ruby@v1
      with:
        ruby-version: 2.6.x
    - name: Build and test with Rake
      run: |
        gem install bundler
        bundle install --jobs 4 --retry 3
        bundle exec rake spec

on:の部分がトリガーになるので、ここを目的のpull_requestに変えておきます。

masterへのpushでgemをアップロードする

こちらもテンプレートがありますが、多少手を加えました。

name: Ruby Gem

on:
  push:
    branches:
      - master

jobs:
  build:
    name: Build + Publish
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2
    - name: Set up Ruby 2.6
      uses: actions/setup-ruby@v1
      with:
        version: 2.6.x

    - name: Build and test with Rake
      run: |
        gem install bundler
        bundle install --jobs 4 --retry 3
        bundle exec rake

    - name: Publish to RubyGems
      run: |
        mkdir -p $HOME/.gem
        touch $HOME/.gem/credentials
        chmod 0600 $HOME/.gem/credentials
        printf -- "---\n:rubygems_api_key: ${GEM_HOST_API_KEY}\n" > $HOME/.gem/credentials
        gem build *.gemspec
        gem push *.gem
      env:
        GEM_HOST_API_KEY: ${{secrets.RUBYGEMS_AUTH_TOKEN}}

masterプッシュへのトリガーだけで良いので、on:の部分は上記のようにします。

GitHub Packageは今回は対象外なので、そちらは削除しています。
(GPRを設定したい場合こちら: https://help.github.com/en/github/managing-packages-with-github-packages/configuring-rubygems-for-use-with-github-packages)

gemをpushする前に、テストを走らせたいので、先程のrake specの部分を直前に差し込みます。 Secretsの値は後からセットします。

GitHubのレポジトリの設定

Secretsに.gems/credentialsの中のトークンを値としたキーを作っておきます。

f:id:scior:20200203005712p:plain

PRのマージの条件にCIパスを設定したい場合、Settings > Branchesから以下のようにします。 (この辺りの機能はころころ変わるので、画像と異なる場合があります)

f:id:scior:20200203005638p:plain

動くとこのようになります。

f:id:scior:20200203010056p:plain

XcodeのSnippetsなどのカスタマイズ情報をgitで管理する

Xcodeのキーバインドや、コードスニペットなどのカスタマイズした情報(UserData)をgit管理する方法を記載します。

個人サーバーやGitHub等を使ってリモートで管理しておくと、Xcodeのバージョンアップの際や複数の環境で設定を揃える際に非常に楽になります。

既存の設定からgitリポジトリを作る

特に変なことをしていなければ、~/Library/Developer/Xcode/UserDataにカスタマイズした設定が全て入っています。

丁寧にやる場合、シンボリックリンクなどを使って別の場所でリポジトリを作るというやり方もありますが、ここでは横着をして上記のパスでリポジトリを作ります。

cd ~/Library/Developer/Xcode/UserData
git init
git remote add origin <repo>

UserDataの中身はこのような感じになっています。

f:id:scior:20200125230755p:plain

.xcstate.xcuserstateなどのIDEの状態を保持するファイルはいらないので、.gitignoreに含めておきます。

自分の場合、以下ののディレクトリのみを管理しています。

  • CodeSnippets
  • FontAndColorThemes
  • KeyBindings

.gitignoreの例です。

*.plist
*.xcstate
*.xcuserstate

IB Support/
IDEEditorInteractivityHistory/
Portal/

ファイルの微調整

コードスニペットはXcodeから生成した場合、ファイル名が{UUID}.codesnippetとなってしまい、数が増えてくると管理しづらくなるので、適宜リネームすることをおすすめします。

f:id:scior:20200125230916p:plain

テーマについては.xccolorthemeファイルの中身がXMLになっているので、複数人で利用したり、細かく気にする人は調整すると良いです。

良い感じになったら、リモートに上げます。

設定をローカルに反映させる

まっさらな環境であれば、リモートから引っ張ってくれば大丈夫です。

cd ~/Library/Developer/Xcode/UserData
git init
git remote add origin <repo>
git pull origin master

既に別の環境が出来上がっている場合は、それぞれから必要なファイルをピックアップする必要があります。