Infinito Nirone 7

白羽の矢を刺すスタイル

Jetpack Compose TextField の横幅を n 文字分だけ確保したい

View の仕組みでは、 TextView のプロパティとして ems が定義してあり、これを利用するとTextView の横幅を ems で指定した文字数分の横幅にしてくれます。

R.attr  |  Android Developers

Jetpack Compose では Text や TextField にそのものズバリな引数や Modifier はないので、自分で計算します。

TextMeasurer で横幅を計算する

TextMeasurer はその名の通り文字を描画するのに必要な領域を計算するクラスです。テキストスタイルや親コンポーネントの縦横の大きさを制約として与えることで、テキストが領域内に収まり切るかどうかも計算可能です。

developer.android.com

今回は TextField の横幅を常に一定に保つため、あらかじめダミーの文字列を用意して TextMeasurer に食わせて横幅を計算します。これでダミーの文字列の長さの分だけ横幅を確保することになります。 次の例では数字6文字分の横幅を計算します。

// 数字6文字分を TextField の横幅にするときの、数字6文字分の横幅を計算
val measurer = rememberTextMeasurer()
val measureResult = measurer.measure(
  text = "000000",
  maxLines = 1,
)

TextField の PaddingValues を求める

TextField は内部で PaddingValues を設定しており、自動でスペースをつけています。 このスペースの大きさは TextField のスタイルによって異なります。 OutlinedTextField ならば outlinedTextFieldPadding() で、TextField の場合は label があるときは textFieldWithLabelPadding()、label がないときは textFieldWithoutLabelPadding() が標準の PaddingValues です。

TextMeasurer で計算した横幅と PaddingValues の水平方向の padding を足し合わせる

TextMeasurer で計算した横幅と PaddingValue の水平方向の padding を足し合わせると、TextField の横幅が計算できます。 TextMeasurer で計算した横幅は px なのに対し、PaddingValues が持つスペースは dp を単位にしているので、TextMeasurer で計算した横幅を dp になおす必要があります。

val measurer = rememberTextMeasurer()
val measureResult = measurer.measure(
  text = "000000",
  maxLines = 1,
)
val padding = textFieldWithoutLabelPadding()

TextField(
  modifier = Modifier.width(
    with(LocalDensity.current) {
      measureResult.size.width.toDp() + padding.calculateStartPadding(LocalLayoutDirection.current) + padding.calculateEndPadding(LocalLayoutDirection.current)
    }
  )
)

注意点

今回は数字のみで文字列の横幅を計算しましたが、全角文字を入れたりするとまた計算が変わってきそうです。 TextMeasure#measure はフォントの種類や文字の大きさなども考慮して横幅を計算できますが、今回のように与えられた文字数に必要な横幅を計算するために予め決め打ちした文字で計算すると、実際に入力した文字によってはどうしてもズレが出ます。

近況2023

この記事は「mhidakaが2つ目を建立したAdvent Calendar 2023」の10日目の記事です。近況を報告せよとのことだったので、なんとなく今年のハイライト的な記事を書いておきます。

adventar.org

今年たのしかったこと

桜のAACR

AACRとは長野県の安曇野市周辺で開催される自転車のロングライドイベントです。レースではなく、設定されたチェックポイントを各々のペースで巡るイベントです。 以前にも参加したことはありますが、コロナ禍が始まって以降は開催も久しぶりでした。

AACRは年に2度開催され、桜と銘打ったAACRは4月中旬、緑と銘打ったAACRは5月中旬に開催されます。 今回は桜のAACRということで4月の安曇野を駆け巡りましたが、当日は近年稀に見る極寒のAACRとなりました。4月も半ばだというのに朝は真冬の寒さで震えながらのスタートでした。

4月ならアルプスの山々もまだ雪をかぶっている。

Droidcon Vietnam

超絶弾丸日程のベトナム(ホーチミン)でしたが楽しめました。数ある Droidcon の中でも際立ってチケット代が安い Droidcon Vietnam ですが、参加者は APAC を中心にいろいろなところから来ていて盛り上がりを感じました。 ホーチミンは以前旅行できたことがあるのでなんとなく覚えている場所もありましたが、やはりGrabで気軽に移動できるのが強いですね。

ちなみに次の写真の真ん中らへんに写っているピンクのやつが見た目に反して異様な苦味と辛さを備えていて涙目になりました。結局今もこれが何なのかよくわかっていません。

北海道旅行

人生3度目の北海道旅行です。今回はどうしても運転してみたい車がレンタカーにあるということでそれを乗りつついままで行ったことのない地域に行くという旅行でした。 シルバーウィークにかぶせてDroidKaigi 2023が終わった翌日に北海道に行くという少々おかしな日程を組んでいましたが、北海道についてからも少々おかしな行程で旅行をしました。

初日は新千歳に着陸後すぐ車を確保し、そのまま苫小牧や新冠を経由(わざわざ遠回り)して帯広に行く行程。

1日目

2日目は帯広から周辺をうろつきつつ池田町のワイン城を見てから摩周湖や屈斜路湖に行き、北見に至る行程。

2日目

3日目は北見から一旦網走に出て、そこから上川に寄り道をしつつ札幌に至る行程。

3日目

最終日は札幌から洞爺湖、室蘭に抜けて新千歳に戻る行程。

最終日

節子、それ旅行やない!ただのドライブや!!

全部で1300kmほど移動していたらしいですが、元々長距離の運転に苦を感じない(+いい車が借りれたので楽だった)ので、また行きたいという気持ちです。 帯広のハゲ天で食べた天丼と朝イチから並んでいるパン屋さん(ますやパン)、北見のバルで食べたサガリ肉のステーキと余市ワイン、ちょうどいい時期にやっていたさっぽろオータムフェストと、食べ物も一通り楽しみました。

ちなみに借りた車はこちら。スバルのアウトバックです。

心残りがあるとすれば、北海道をウロウロしている間いろいろないい景色を見てきましたが、写真以外はほぼ脳内にしか記録がないこと。次は車載動画もやってみたいところです。

ジャパンカップサイクルロードレース撮影

自転車競技のシーズン終盤に行われる、日本では珍しい国際的な自転車レースです。欧州で活躍するプロがやってきて眼の前を駆け抜けるのでファンの人気も高い。 毎年ひとりで足を運んでカメラ小僧になっていますが、今年は e10dokup さんを誘って行きました。

当初はレースが始まる頃には雨が上がっている予報でしたが、実際にはレースが終わるまで見事に雨。機材を濡らさない強い気持ちはありましたが自分自身は守れませんでした。 でもいい写真が取れたのでOKです。

ジュリアン・アラフィリップ選手。アラフィリップ応援団がいるほど日本のファンもたくさん。

長年日本の自転車競技を引っ張り続ける新城幸也選手。

今年買ってよかったもの

デロンギの自動でコーヒーいれるやつ

最高

Pixel Fold

待望のやつ

上川大雪の日本酒

うまい

ツルヤのPB商品

安定

WorkManager Migration to 2.9.0

AndroidX WorkManager の 2.9.0 がリリースされました。以前のバージョンからこのバージョンに上げるにはマイグレーションが必要です。

https://developer.android.com/jetpack/androidx/releases/work?hl=en#2.9.0

Configuration.Provider の実装

2.8.x 以前は次のような定義でした。

interface Provider {
  fun getWorkManagerConfiguration(): Configuration
}

この定義が 2.9.0 では次のように変わりました。

interface Provider {
  val workManagerConfiguration: Configuration
}

このインタフェースは Application クラスで実装せよとあるので、2.8.x 以前であれば次のような実装になるはずです。

class MyApp : Application(), Configuration.Provider {
  override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder()
    .setMinimumLoggingLevel(Log.VERBOSE)
    // ... do your configuration customization
    .build()
}

2.9.0 へのアップデートでは、次のように書き換わります。

class MyApp : Application(), Configuration.Provider {
  override val workManagerConfiguration: Configuration = Configuration.Builder()
    .setMinimumLoggingLevel(Log.VERBOSE)
    // ... do your configuration customization
    .build()
}

HiltWorkerFactory と組み合わせる

次の記事で紹介した方法で、WorkManager と Hilt を組み合わせることができます。

blog.keithyokoma.dev

Hilt は各種 Worker に依存を注入するために独自の WorkerFactory を使います。そのため、Application クラスで次のように WokerFactory を注入して Configuration に渡しているはずです(2.8.x 以前)。

class MyApp : Application(), Configuration.Provider {
  @Inject
  lateinit var workerFactory: HiltWorkerFactory

  override fun getWorkManagerConfiguration(): Configuration = Configuration.Builder()
    .setWorkerFactory(workerFactory)
    // ... do your configuration customization
    .build()
}

WorkManager 2.9.0 へアップデートするとき、Hilt と組み合わせている場合は先程の書き換え方をそのまま適用すると workerFactory が注入される前に Configuration を作ってしまうためアプリがクラッシュします。

class MyApp : Application(), Configuration.Provider {
  @Inject
  lateinit var workerFactory: HiltWorkerFactory

  override val workManagerConfiguration: Configuration = Configuration.Builder()
    .setWorkerFactory(workerFactory)
    // ... do your configuration customization
    .build()
}

正しく動作するよう書き換えるには次のように getter で Configuration を作成します。

class MyApp : Application(), Configuration.Provider {
  @Inject
  lateinit var workerFactory: HiltWorkerFactory

  override val workManagerConfiguration: Configuration
    get() = Configuration.Builder()
      .setWorkerFactory(workerFactory)
      // ... do your configuration customization
      .build()
}

DEEDS BREWING #BeerAdventCalendar2022

この記事は Beer Advent Calendar 2022 - Adventar の 9 日目の記事です。

これがうめぇんだ!

DEEDS XPA

しっかりとした苦味がありつつ、後味スッキリですいすい飲めます。 最高です。

DEEDS DOUBLE TIME

さっきの XPA の苦味と後味にくわえ、HAZY PALE らしいフルーティーさが合わさった感じですいすい飲めます。 最高です。

DEEDS BREWING #BeerAdventCalendar2022

この記事は Beer Advent Calendar 2022 - Adventar の 9 日目の記事です。

これがうめぇんだ!

DEEDS XPA

しっかりとした苦味がありつつ、後味スッキリですいすい飲めます。 最高です。

DEEDS DOUBLE TIME

さっきの XPA の苦味と後味にくわえ、HAZY PALE らしいフルーティーさが合わさった感じですいすい飲めます。 最高です。

多くのパラメータを持つ関数・コンストラクタの呼び出しに必要な引数を名前付きで自動生成したい

やりたいこと

次のように定義されたコンストラクタを名前付き引数を使って呼び出したい。

// 定義
data class Sample(
  val hoge: String,
  val fuga: String,
  val moga: String,
  val piyo: String,
  val foo: String,
  val bar: String,
  val baz: String,
  val qux: String,
  val quux: String,
)

// 次のコードを補完機能で自動生成したい
val sample = Sample(
  hoge = "",
  fuga = "",
  moga = "",
  piyo = "",
  foo = "",
  bar = "",
  baz = "",
  qux = "",
  quux = "",
)

問題

IntelliJ の標準のコード補完機能では、コンストラクタや関数の呼び出しについて名前付き引数のコード補完ができない。ヒントは表示されるが補完まではしてくれないので、すべて手入力しないといけない。

解決方法

プラグインを使いましょう。

plugins.jetbrains.com

このプラグインを使うと、コンストラクタや関数の呼び出し箇所で Fill Function という補完メニューが出てくるようになり、すべての名前付き引数を自動で作ってくれます。

YouTrack にも Issue がたっていますが、今のところは上記の Plugin を使うのが一番はやいです。

つけ麺 えん寺 #つけ麺AdventCalendar2022

この記事は つけ麺 Advent Calendar 2022 - Adventar の4日目の記事です

つけ麺 えん寺

ベジポタつけ麺肉増し味たま付き

これがうめぇんだ!

説明

  • ベジポタつけ麺をやっているお店です。
  • 吉祥寺・中野・池袋・東高円寺に「えん寺」がある他、野方に「花みずき」と渋谷に「マンモス」という系列店があります。
  • 基本的にどのお店もベジポタつけ麺とベジポタ辛つけ麺を提供していて、お店によってはエビのだしを強くした数量限定のつけ麺を提供しているところもあります。
  • 辛つけ麺はデフォルトで十分辛い(自分基準)のですが、お好みで更に2段階辛くすることが可能なのようです。
  • 麺の種類が選べますが、おすすめは胚芽麺です。

宅麺

宅麺の冷凍つけ麺

  • 宅麺というサービスをつかうと、えん寺のつけ麺を自宅で楽しめます。
  • ベジポタつけ麺ベジポタ辛つけ麺があります。
  • 人気が高く入荷してもすぐ売り切れてしまうので、入荷通知を ON にしておくとよいです。
  • お店と同じ具の入ったスープと胚芽麺が入っています。味玉はお好みで自分で用意しましょう。