みずきち日記

ひらすらプログラミング

僕のリモート勤務を快適にする

covid-19 の影響で弊社も3月末頃から完全リモート勤務になりました。

最初はローデスクとソファーしか無く劣悪な開発環境の中で過ごしていましたが、 コレじゃいかんというわけで急遽周辺機材を買い揃えました。

あれから2ヶ月ほど経過し、コレ買ってよかった!と思える商品を紹介します。

仕事環境を整備する

昇降デスク

家でローデスクに対して長時間座っていると腰を痛めます。 弊社で昇降デスクを使った経験があり憧れていたので、 まずは昇降デスクから探すことにしました。

制約条件として、

  • 昇降時は電動が良い。
  • 我が家は8畳ワンルームなので、それほどデカイ机は置けない。120cm x 60cm 程度。
  • ただ将来的に引っ越すことも考えると、複数の天板サイズに対応しているタイプが望ましい。
  • 体型が小柄なので、座った時の座面の高さを考えると、65cm くらいまで下げられる机が良い。

ここまで来ると、そこそこ絞られてきます。 天板が交換可能な電動昇降デスクでヒットしたのが、flexispot というメーカーです。(界隈では有名なの?) 天板付きのタイプや、天板別売りのタイプ、さらには交換用の天板まで売ってました。

天板付きのオールインワンタイプの製品は高さが最小で700mmだったので、 最小600mmまで下げられる以下の製品を買いました。 黒色を買いましたが、白バージョンもあるようです。

こちらは天板別売りタイプなので、どこかで天板を取り揃える必要があります。 flexispot は天板も取り揃えているので、適当なサイズのものを購入しました。 純正なので、ネジ止めの穴を開ける必要もなく楽です。 茶色を買いましたが、他にも種類があるようです。

公式より、amazon のほうが安かったので、そちらで買ってます。 配送も早いし、おすすめです。

ただし昇降デスク自体とても重量があるため、組み立てにはとても苦労すると思います。 youtube などで商品紹介されてる方の動画を何個か見ていましたが、 一人で組み立てる場合は細心の注意を払ったほうが良いです。

周辺機器

さて、新しいデスクを買ったので、今度は周辺機器を揃えていきましょう。 仕事場ではデュアルディスプレイだったので、そこから整備することにしました。 僕はディスプレイの反射が嫌いなので、マットなやつが必須です。

マットな4Kディスプレイでいろいろ調べていると、以下の製品に当たりました。 4Kは5万以上する印象だったんですが、低価格だし、レビューも良さそうなのでコレにしました。

破格なんですが、2ヶ月たった今でも不具合なく使えています。 ブルーライトカットモードがあるので、ぜひ使ってください。 反射もなく目に優しいです。

ディスプレイの付属スタンドも、最低限の高さ調節や向きが変えられました。 不満は無いのですが、昇降デスクを使っている関係上ディスプレイの向きを簡単に調整したかったので、 評判が良さそうな以下のディスプレイアームを買うことにしました。

昇降時に若干揺れてしまいますが、通常使用する際には何も不満は無かったです。 ただノートPC等と一緒にデュアルディスプレイで使う場合、脚を取り付ける位置をミスると 思ったように微調整できず返って不便になるので気をつけたほうが良いです。


また、ディスプレイアームと一緒にノートPCスタンドも買いました。 これは弊社デスクでも使っている製品で、細かい高さ微調整が出来る上、 重みでずれ落ちるみたいなこともありません。結構おすすめです。


次に、机・ディスプレイ周りが揃ったので、今後は手元の環境を整備することにしました。 キーボード、パームレストあたりを探しました。

僕は会社ではHHKBを使っているので、家でも使えるように、前から欲しかったものを買ってみました。

Bluetooth の静音タイプで去年冬頃に出た新しいやつです。 会社では有線タイプ使ってますがケーブル周りがシンプルになりとても快適です。 ただ毎朝キーボードの電源入れて接続して... みたいな操作が必要なのでそこは面倒だったりします。 チャタリングは滅多に起きませんが、たまに接続が切れて不安定な時期がありました。 USB-C 接続なので、MacBook なら特に変換アダプタかませなくてもシンプルに繋げれます。

--

最後に、ウッドパームレストも買ったので紹介します。 HHKBの横幅と同じサイズのものを会社でも使っているんですが、 ちょっと横幅に物足りなさを感じていたので440mmタイプのものを買いました。

横幅が伸びたことで、キーボードに対してハの字で手を置くことが出来るようになったので、 肩こりが若干軽減されたような気がします。

とツラツラと書いてきましたが、2ヶ月振り返ってみて環境にお金をかけて本当に良かったなと思います。 リモートで少しずつ生活環境が変わってきていますが、運動不足や食生活にも気をつけて過ごしていきたいです。 おわり

外部から任意の github actions を実行する

通常、github actions では、ブランチの actions をトリガーとするケースが多いと思います。 しかし、Slack 上で特定の actions を実行したいなど、任意のタイミングで github 外部から actions を実行するための手法を紹介します。

その場合、repository_dispatch を使います。repository_dispatch に指定した type を curl で実行する際の event_type として指定すると、合致する job が実行されます。

以下の例では、前回の記事で紹介した Android アプリのバージョンを更新する shell script を、外部からのイベントで発火し、更新したアプリバージョンの Pull Request を作成する actions を定義しています。

name: dispatch_sample

on:
  repository_dispatch:
    types: [dispatch-sample]

jobs:
  dispatch-sample-job:
    runs-on: ubuntu-latest
    name: bump up app versions
    steps:
      - uses: actions/checkout@v2
        with:
          fetch-depth: 0

      - name: setup git
        run: |
          git config --local user.name bump-up-bot
          git config --local user.email bump-up-bot@google.com

      - name: bump up app versions
        run: |
          ./bump.sh ${{ github.event.client_payload.version_name }}

      - name: Create Pull Request
        uses: peter-evans/create-pull-request@v2
        with:
          token: ${{ secrets.GITHUB_TOKEN }}
          commit-message: bump up app versions
          title: bump up app versions to ${{ github.event.client_payload.version_name }}
          branch: ${{ github.event.client_payload.branch }}

上記 actions を実行するためには、外部から curl などで post します。

$ curl -X POST https://api.github.com/repos/[your-github-id]/[your-github-repository]/dispatches 
  -H "Authorization: token [your-access-token]"
  -H "Accept: application/vnd.github.everest-preview+json"
  --data "{\"event_type\": \"dispatch-sample\", \"client_payload\": {\"branch\": \"release/hoge\", \"version_name\": \"1.0.0\"}}"

この例では、repository_dispatch として dispatch-sample が定義されている job を実行します。 また、外部から情報を渡したい場合、client_payload として json 形式でデータを与える事ができます。

上記 curl を実行すると、client_payload として指定した version_name にアプリの version 名が更新され、version_code はインクリメントした差分情報を、mater からチェックアウトした release/hoge ブランチ上でコミットし、Pull Request を作成するところまで自動でやってくれます。

例えば、Slack から更新したい version name を指定し、lambda などから上記 post を実行すれば、 アプリのバージョンアップデートは slack 上で完結することが出来るので、普段のリリースフローを少し便利に済ますことが出来ます。

是非参考にしてみてください。

Android プロジェクトのアプリバージョンを自動で更新する

Android のアプリバージョンは build.gradle 内で定義されています。

android {
  ...
  defaultConfig {
    versionCode 1
    versionName 1.0.0
    ...
  }
}

この記事では、build.gradle 内のバージョンを CI などを使って自動で更新出来るようにします。

参考記事では、grale script を使った方法でやってますが、CI で実行する場合 gradle の環境構築などが走ってしまい無駄なので、 shell script を使って更新してみることにします。

参考記事: https://medium.com/@IlyaEremin/npm-version-for-gradle-android-9137a7dc273c

まずは、アプリのバージョンを定義する properties ファイルを作成します。 今回は、appversions.properties としました。

VERSION_NAME=1.0.0
VERSION_CODE=1

先程の build.gradle 内のバージョンを appversions.properties から参照する形に書き換えます。

android {
  ...
  defaultConfig {
    def versionPropsFile = file('appversions.properties')
    def versionProps = new Properties()
    versionProps.load(new FileInputStream(versionPropsFile))
    
    versionCode versionProps['VERSION_CODE'].toInteger()
    versionName versionProps['VERSION_NAME']
    ...
  }
}

これで、ビルド時に appversions.properties の中身を使うようになります。 あとは、shell script で properties を書き換えるようにします。

#!/bin/bash
function get_version_code() {
    command="grep -o 'VERSION_CODE=[^,]*' appversions.properties | sed -e 's/^VERSION_CODE=//'"
    eval $command
}
VERSION_NAME=$1
VERSION_CODE=$((`get_version_code`+1))
echo -e "VERSION_NAME=$1\nVERSION_CODE=$VERSION_CODE" > appversions.properties

あとは、CI 上で ./bump.sh [version-name] と実行すれば、version code が自動でインクリメントされ、version name が指定した文字列に置換されます。 例えば、github actions などでバージョンを上げるタイミングを上手くフックして上記を実行すれば、バージョンを更新する PR を自動で作成する事もできます。 これは、次回の記事で書いてみたいと思います。

Terminal 上で翻訳したい

gawk の導入。

$ curl -OL ftp://ftp.gnu.org/gnu/gawk/gawk-5.0.0.tar.gz
$ tar -zxvf gawk-5.0.0.tar.gz
$ cd gawk-5.0.0
$ ./configure
$ make clean ; make
$ ./gawk --version

gawk のパスを通す。

$ mv gawk-5.0.0 ~/gawk-5.0.0
$ export PATH=$PATH:/Users/s05463/gawk-5.0.0
$ gawk --version

translate-shell の導入。

$ git clone git clone https://github.com/soimort/translate-shell
$ cd translate-shell
$ make
$ sudo make install
$ trans -sl=en -tl=ja "Peace begins with a smile."

オプション多いので、alias を設定しておきます。

.zshrc

alias transj='trans -b -sl=ja -tl=en'
alias transe='trans -b -sl=en -tl=ja'

使う時はこんな感じ。

$ transe "hello"
> こんにちは

$ transj "こんにちは"
> Hello

参考サイト

qiita.com

qiita.com

qiita.com

StatusBar と ToolBar のあれこれ

今回の目標はコレです。 グラデーションのかかった Toolbar が StatusBar の下に潜り込んで表示されています。 そして、キーボードが表示された際の Activity のリサイズにも対応するようにします。

StatusBar と ActionBar

まずは、何も設定していない時はどうなるか見ていきます。

分かりやすいように EditText に赤い枠線を付けてます。 キーボードが EditText の上に覆いかぶさってしまっています。

これは、AndroidManifest の方で、android:windowSoftInputMode="adjustResize" を設定すると、キーボードが出現した際に Activity がリサイズされるようになります。

さらに、ActionBar を非表示にします。 Theme.AppCompat.Light.NoActionBar を Activity の Theme に指定すると非表示にできます。

次に、StatusBar の見た目をカスタマイズしていきたいと思います。 まずは、背景を透明にしていきます。

window.statusBarColor = Color.TRANSPARENT をすることで実現できます。

これで背景を透明にできました。しかし、これでは StatusBar の背景が白で、アイコンの色と被ってしまい見にくいので、LIGHT_STATUS_BAR にして、アイコンを黒にします。

window.statusBarColor = Color.TRANSPARENT
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val option = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR
    window.decorView.systemUiVisibility = option
}

 

StatusBar の下に Activity の View を食い込ませる

Activity の表示領域を StatusBar の範囲まで拡大させるためには、systemUiVisibility に対して View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE を設定します。

これは、以下のコードで実現できます。 こちらのサイトがとても参考になりました。

window.statusBarColor = Color.TRANSPARENT
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
    val option = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
    window.decorView.systemUiVisibility = option
}

 

しかし、これだとキーボードが表示された時、 android:windowSoftInputMode="adjustResize" を設定しているのにも関わらず、 Activity のリサイズが効かなくなってしまいます。

そこで、Activity のルートタグに fitsSystemWindows="true" を指定することで、キーボードが出現した時に、Activity が必要に応じてリサイズされるようになります。

Toolbar を設置する

ここまで出来たら、次は Toolbar を設置していきます。

<androidx.appcompat.widget.Toolbar
    android:id="@+id/toolbar"
    android:layout_width="match_parent"
    android:layout_height="?attr/actionBarSize"
    android:background="@drawable/gradation"
    app:title="Toolbar"
    app:titleTextColor="#FFF" />

これを Activity に追加しておきます。

<?xml version="1.0" encoding="utf-8"?>
<layout>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00F"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@drawable/gradation"
            app:title="Toolbar"
            app:titleTextColor="#FFF" />

        <androidx.appcompat.widget.AppCompatEditText
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="16dp"
            android:background="@drawable/frame"
            android:gravity="top"
            android:hint="sample strings sample strings sample strings sample strings"
            android:padding="8dp"
            tools:ignore="HardcodedText" />
    </LinearLayout>
</layout>

ちなみに、背景の @drawable/gradation はこんな感じです。 gradient タグを使ってグラデーションを描きます。

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape android:shape="rectangle">
            <gradient
                android:angle="45"
                android:centerColor="#FF8C00"
                android:endColor="#FFEE00"
                android:startColor="#F60000" />
        </shape>
    </item>
</layer-list>

この状態で実行すると、Toolbar にグラデーションが描かれていると思います。 しかし、StatusBar にグラデーションがかかっていません。

 

これは、fitsSystemWindows="true" を設定した際に、StatusBar の高さ分だけ Padding が自動的に付与されるからです。

なので、以下の方法でステータスバーの領域までグラデーションをかけようと考えました。

  1. StatusBar の高さ分だけ Toolbar の高さを伸ばす
  2. StatusBar の高さ分だけ Toolbar に対してマイナスマージンをかける

StatusBar の高さは ViewCompat.setOnApplyWindowInsetsListener を使います。今回は汎用性をもたせて拡張関数として定義しました。

fun View.getStatusBarHeightPx(f: ((Int) -> Unit)) {
    ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
        v.setOnApplyWindowInsetsListener(null)
        f(insets.systemWindowInsetTop)
        ViewCompat.onApplyWindowInsets(v, insets)
    }
}
private fun resizeToolbar() = with(binding) {
        root.getStatusBarHeightPx { statusBarHeightPx ->
            toolbar.updatePadding(top = statusBarHeightPx)
            toolbar.layoutParams = (toolbar.layoutParams as ViewGroup.MarginLayoutParams).apply {
                height += statusBarHeightPx
                updateMargins(top = -statusBarHeightPx)
            }
        }
    }

また、android:clipToPadding="false" を Activity のレイアウトに追加するのを忘れないでください。マイナスマージンをかけているので、Toolbar を親の View からはみ出して描画されるようにします。これでうまく動くはずです。

最後に、最低限必要なソースコードを載せておきます。

class MainActivity : AppCompatActivity() {

    private val binding by lazy {
        DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
    }
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        initStatusBar()
        setContentView(R.layout.activity_main)
        resizeToolbar()
    }

    private fun initStatusBar() {
        window.statusBarColor = Color.TRANSPARENT
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            val uiOption = window.decorView.systemUiVisibility or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_LAYOUT_STABLE
            window.decorView.systemUiVisibility = uiOption
        }
    }

    private fun resizeToolbar() = with(binding) {
        root.getStatusBarHeightPx { statusBarHeightPx ->
            toolbar.updatePadding(top = statusBarHeightPx)
            toolbar.layoutParams = (toolbar.layoutParams as ViewGroup.MarginLayoutParams).apply {
                height += statusBarHeightPx
                updateMargins(top = -statusBarHeightPx)
            }
        }
    }
}

fun View.getStatusBarHeightPx(f: ((Int) -> Unit)) {
    ViewCompat.setOnApplyWindowInsetsListener(this) { v, insets ->
        v.setOnApplyWindowInsetsListener(null)
        f(insets.systemWindowInsetTop)
        ViewCompat.onApplyWindowInsets(v, insets)
    }
}
<?xml version="1.0" encoding="utf-8"?>
<layout>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#00F"
        android:clipToPadding="false"
        android:fitsSystemWindows="true"
        android:orientation="vertical"
        tools:context=".MainActivity">

        <androidx.appcompat.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="@drawable/gradation"
            app:title="Toolbar"
            app:titleTextColor="#FFF" />

        <androidx.appcompat.widget.AppCompatEditText
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="16dp"
            android:background="@drawable/frame"
            android:gravity="top"
            android:hint="sample strings sample strings sample strings sample strings"
            android:padding="8dp"
            tools:ignore="HardcodedText" />
    </LinearLayout>
</layout>

何か、気づいたことや、懸念点あればコメント頂ければと思います。 参考になれば幸いです。

おしまい

Avtivity への遷移に SafeArgs を使ってみる

Android Jetpack のひとつに Navigation があります.

この機能を使えば複雑な Fragment 同士の画面遷移をGUI(xml)上で定義し,画面遷移をより簡潔に記述することが出来ます.

Fragment 間の画面遷移において,値渡しをする際は SafeArgs が便利です.

これは Navigation Graph の xml 内で対象 Fragment が必要とする引数を定義し,ビルド時に専用のクラスを生成し,それを使うことでより型安全に画面遷移を可能にする機能です.

今回は, 例のような Fragment --> Fragment だけでなく, Activity を立ち上げる際にも SafeArgs を使ってより型安全に画面遷移できる方法を考えてみます.

例として, 以下のような Activity があるとします.

class ResultActivity : AppCompatActivity() {

  companion object {
    private const val EXTRA_GITHUB_ID = "EXTRA_GITHUB_ID"

    fun createIntent(
      context: Context,
      githubId: String
    ): Intent {
      val intent = Intent(context, ResultActivity::class.java)
      intent.putExtra(EXTRA_GITHUB_ID, githubId)
      return intent
    }
    ...
}

よくある Activity を立ち上げるために必要な Intent を作成する方法として, 対象 Activity クラス内に static な createIntent メソッドを定義し, そこで Context やその他引数を受け取って, Intent に詰め込んで返す方法が一般的だと思います.

そして,呼び出し元では受け取った Intent を startActivity に渡します.

startActivity(ResultActivity.createIntent(this, "mzkii"))

この実装の問題点として

  • key:value 形式なので putExtra の key を一々自前で用意しないといけない

  • getExtra する際に渡す Key を間違えると予期しない値を受け取ってしまう可能性がある

などが挙げられると思います.

今回はこの部分を SafeArgs に置き換えて実装していきます.

まずはじめに navigation.xml を作っておきます.

<fragment> タグではなくて<activity> タグで括ります.

<navigation
    ...
    >
  <activity android:name="com.mzkii.dev.navigationactivities.ResultActivity">
    <argument
        android:name="userIds"
        app:argType="integer[]"
        />
    <argument
        android:name="userName"
        app:argType="string"
        />
  </activity>
  ...
</navigation>

この状態でビルドすると ResultActivityArgs が生成されます.

data class ResultActivityArgs(val userIds: IntArray, val userName: String) : NavArgs {
    fun toBundle(): Bundle {
        val result = Bundle()
        result.putIntArray("userIds", this.userIds)
        result.putString("userName", this.userName)
        return result
    }

    companion object {
        @JvmStatic
        fun fromBundle(bundle: Bundle): ResultActivityArgs {
            bundle.setClassLoader(ResultActivityArgs::class.java.classLoader)
            val __userIds : IntArray?
            if (bundle.containsKey("userIds")) {
                __userIds = bundle.getIntArray("userIds")
                if (__userIds == null) {
                    throw IllegalArgumentException("Argument \"userIds\" is marked as non-null but was passed a null value.")
                }
            } else {
                throw IllegalArgumentException("Required argument \"userIds\" is missing and does not have an android:defaultValue")
            }
            val __userName : String?
            if (bundle.containsKey("userName")) {
                __userName = bundle.getString("userName")
                if (__userName == null) {
                    throw IllegalArgumentException("Argument \"userName\" is marked as non-null but was passed a null value.")
                }
            } else {
                throw IllegalArgumentException("Required argument \"userName\" is missing and does not have an android:defaultValue")
            }
            return ResultActivityArgs(__userIds, __userName)
        }
    }
}

さらに, 専用の拡張関数も用意しておきます.

inline fun <reified T> Activity.startActivity(bundleArgs: Bundle) {
  val intent = Intent(this, T::class.java).apply {
    putExtras(bundleArgs)
  }
  startActivity(intent)
}
fun Activity.requireBundle() = intent.extras ?: throw IllegalArgumentException("Bundle() must not be null.")

これで準備は完了です.

Activity を立ち上げるときはこんな感じになります.

startActivity<ResultActivity>(
  ResultActivityArgs(
    userIds = intArrayOf(22, 23, 24),
    userName = "mzkii"
  ).toBundle()
)

ResultActivityArgs#toBundle() を使うと Bundle に引数の値を詰めて返してくれます.

そして, 受け取る側は以下のようになります.

onCreate 以降で使いたいので遅延初期化します.

class SafeargsActivity : AppCompatActivity() {

  private val args by lazy {
    ResultActivityArgs.fromBundle(requireBundle())
  }
  
  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    val userIds = args.userIds
    val userName = args.userName
  }

こうすることで, IDE で補完の恩恵を受けつつ, createIntent の定義がなくなり, かつ間違った key を指定する事もなくなりました.

その一方で,

  • 必要な引数達を navigation.xml に集約して書くことになるので activity のコーディング時に必要な引数がぱっと見て分かりづらくなる
  • 拡張関数 startActivity の引数が Bundle なので ResultActivityArgs 使わなくても結局起動できてしまう
  • コードの自動生成が少なからず走るので, 画面数が増えた時にビルド時間が伸びそう

みたいなデメリットもあるな〜と感じました.

SafeArgs は結構便利なライブラリなので, Navigation 入れる前段階として徐々に導入していくと良いと思います.

iTerm2 で Full-Width Bottom of Screen

iTerm2 でウィンドウ上にターミナルを上に重ねて表示できることを今日知りました(驚愕).

基本的に以下のサイトの手順で設定できました.

https://oversleptabit.com/archives/1380

手順としては,

1. Window の表示設定をする

右下の Style を Full-Width Bottom of Screen, Screen を Screen with Cursor, Space を All Spaces に設定してます.画面上に重ねて表示するので,お好みで Transparency も適度に設定しておけばいいでしょう.

2. Terminal を表示するためのホットキーを設定する

ProfilesKeys を開き, Hotkey Window 欄にある A hotkey opens... にチェックを入れて Configure Hotkey Window をクリックします.

Hotkey の欄をクリックして Recoding... 状態になるので好きなホットキーを設定します.僕は command + 1 にしました.

Floating window にチェックを入れないと, Dock の高さ分だけ Terminal が浮いちゃうので付けてます.Pin hotkey window にチェックを入れると,キーボードのフォーカスが iTerm ではなくなっても表示され続けます.先に設定した Hotkey を押すと消えます.

3. 起動時の Window 設定

最後はお好みです.ここまでの設定だと, Desktop 上の画面下半分に Terminal が表示され続けます.デスクトップ上に居続けられると邪魔だったので, General の左上にある StartupOnly Restore Hotkey Window に設定して,ホットキーを押したときだけ Terminal が出てきてくれるようにしました.

ハマったポイントは以上です.

これで Android Studio 上の Terminal は使わなくて良くなったかな?

おすすめの設定があれば是非コメントなどで教えてください😉

おわり