2023年8月8日火曜日

HTML/CSS マウスオーバーしたときの表示をカスタマイズする

マウスオーバーしたときに表示を切り替えたいときは、CSSに疑似クラスを指定する。

a:hover {
  マウスオーバー中に表示したい内容
}

この指定を複数の要素に指定することで、例えばテキストやイメージの表示切替などもできる。

a:hover {
  マウスオーバー中に表示したい内容
}
.a-covered:hover {
  マウスオーバー中に表示したい内容
}

マウスオーバー以外にも疑似クラスの指定により表示を変えられるものは以下。

  • link:御訪問リンク
  • visited:訪問済みリンク
  • hover : マウスオーバー
  • active : リンククリック中

参考

2023年8月7日月曜日

Android Parcelableを実装する方法を解説

どうも。どっことです。今回はParcelableの実装方法について解説します。

Parcelableを実装する

ActivityFragmentなどの画面間におけるデータ受け渡しはアプリ全体の動きを考える上でなくてはならない処理ですが、自前で用意したデータクラスはそのままだとBundleに乗せることができません。

それではどうするかというと、そのデータクラスにParcelableSerializableを実装します。取り出すときにキャストが必要にはなるが、これでBundleに乗せることができるようになり画面間のデータ受け渡しができるようになります。

今回はその呪文の如きParcelableのインターフェース群の実装について、説明します。

実装

必要な実装ですが、データクラスに以下のクラス・メソッドを実装します。

  • Parcelableを実装する
  • describeContentsを実装する
  • 引数がParcelのコンストラクタを実装する
  • writeToParcel()を実装する
  • CREATOR : Parcelable.Creatorを実装する

サンプルとしてItemクラスにParcelableを実装する場合は以下となります。

data class Item(
    var title: String,
    var description: String,
) : Parcelable {
    constructor(parcel: Parcel) : this(
        parcel.readString()!!,
        parcel.readString()!!
    )

    override fun writeToParcel(parcel: Parcel, flags: Int) {
        parcel.writeString(title)
        parcel.writeString(description)
    }

    override fun describeContents(): Int {
        return 0
    }

    companion object CREATOR : Parcelable.Creator<Item> {
        override fun createFromParcel(parcel: Parcel): Item {
            return Item(parcel)
        }

        override fun newArray(size: Int): Array<Item?> {
            return arrayOfNulls(size)
        }
    }
}

あとは実装したデータクラスのオブジェクトをBundle#putParcelable()Bundleに詰め

val bundle = Bundle().apply {
    putSerializable("適当なキー", item)
}

Bundle#getParcelable()Bundleから取り出すことで

val item = bundle.getParcelable("適当なキー", Item::class.java)

画面間でデータクラスをやり取りすることができます。

ここまで書いててですが…

Percelableをいい感じに実装してくれるアノテーションがあると公式サイトが謳っていました。

Parcelable 実装生成ツール

アノテーション付けるだけで上記の面倒臭い実装をしなくてよくなるなんて、なんて素晴らしいんだ!!ありがとうGoogle様!!!

まとめ

今回はParcelableの実装方法について解説しました。ボイラープレートなParcelableの実装ですが、すでに自動生成してくれるツールがあるので、そちらを使う方が無難でしょう。今回の紹介した内容がほぼ無用なものになってしまいますが、必要なものが簡単に実装できることの方が重要だと思うので、まあ仕方ないでしょう笑

2023年8月6日日曜日

VBA 今日の日付を取得する

単純な日付だけであれば Dateをって取得する。

Dim date As Date: date = Date()

時刻まで必要であれば Now を使って取得する。

Dim now As Date: now = Now()

参考

2023年8月5日土曜日

VBA 変数宣言時に初期値を設定する

Dimによる変数宣言と、値の設定は一行で書ける。

Dim numberValue As Integer: numberValue = 30000
Dim text As String: text = "sample text"

2023年8月4日金曜日

SQL 複数のキーを主キーに設定するPRIMARY KEY節を紹介

どうも。どっことです。今回は複数のキーをPRIMARY KEYに設定するSQLを紹介します。

複数のキーをPRIMARY KEYに設定する

まず、前提として主キーが1つだけの場合です。

テーブルを生成する際、1つのキーだけを主キーに設定する場合は以下のようになります。

create table user(id int primary key,  name text);

しかし複数のキーを主キーに設定する場合、上記と同じような形にするとエラーが発生します。

複数のキーを設定する場合は、最後の方にPRIMARY KEY節を追加します。例えばid,subIdを主キーに設定する場合は以下となります。

create table user(id int, subId int, value text, ..., PRIMARY KEY(id, subId));

今回は簡単ですが以上です。

2023年8月3日木曜日

iOS TextFieldのキーボードを閉じる実装方法を解説

どうも。どっことです。今回はiOSでのキーボードを閉じる実装について解説します。

解説

iOSではアプリからキーボードを閉じるのは非常に簡単で、UITextField#endEditing(true)を呼び出すだけでOKです。

@IBOutlet weak var textField: UITextField!

func closeKeyboard() {
    // キーボードを閉じる
    textField.endEditing(true)
}

AndroidではInputManagerにアクセスしたり必要な情報を渡したりで面倒臭いのに、iOSはとにかくシンプルで羨ましいですね。

参考

2023年8月2日水曜日

Android Koin の使い方を調べたので解説

どうも。どっことです。今回はKoinの使い方について解説します。

Koinを使ったDIの実装

Koinってなんだよ、というあなたはこちらを見てくださると大変嬉しいです。ちなみに、Daggerというライブラリを使ってDIを実現するパターンもありましたが、実装難易度の観点から今回はKoinを使う方針としました。

それでは実装方法について解説します。

ライブラリの組み込み

まずはライブラリを組み込む必要があるのでapp/build.gradle.ktdependenciesに以下を記述します。

dependencies {
    // 他にもあるけど説明のためこれだけ。
    implementation("io.insert-koin:koin-android:3.4.2")
}

Applicationクラスの実装

続いて、Applicationクラスに必要な処理を追加していきます。Applicationってどうすんだっけ、というあなたはこちらを見てくださると大変嬉しいです。

moduleインスタンスを作ってstartKoin を実行します。moduleインスタンスには DIするインターフェースとそれの実装クラスを登録します。以下はSampleRepositoryImpl(dao: Dao)をDIするサンプルです。

    private val appModule = module {
        single<SampleRepository> { SampleRepositoryImpl(get()) }
    }
    protected open val dao = module {
        single {
            Room.databaseBuilder(
                applicationContext,
                Database::class.java,
                DATABASE_NAME
            ).build().dao()
        }
    }
    override fun onCreate() {
        super.onCreate()
        startKoin {
            androidContext(this@SampleApplication)
            modules(appModule, dao)
        }
    }

メモ:single で登録しておくと、シングルトンパターンでオブジェクトを管理してくれる。

各機能にアクセスする

あとはDIしたい箇所で、by inject()を使ってインジェクトすると、簡単にアクセスすることができます。

private val repository : SampleRepository by inject()

まとめ

今回はDIをシンプルにアプリに導入できるライブラリであるKoinの使い方を解説しました。昨今のプログラムのレガシー化やCI/CDに向けたモジュールの疎結合を意識する上でDIは必要不可欠な機能の一つです。DIを実現するものは今回のKoin以外にもさまざまなものがありますので、比較・検討した上で導入しましょう。

参考

2023年8月1日火曜日

CI/CD Bitriseでaabを生成する

前回の続きです。今回はリリースファイルを作るための各種設定を備忘録として記載したいと思います。

リリースファイル(aab)を生成するための設定

とはいえ、基本は以下の手順通りに設定すればOK。日本語ページはなかなか残念なことになっているので、英語ページをベースに作業したほうが結果的にストレスが少なくて済む。

Generating and deploying Android app bundles

ただし、少しだけハマりポイントがあるので注意が必要。ハマったポイントは以下。

gradlewのパス

唯一納得いかなかったハマりポイント。gradlewのパスがデフォルトのままだとビルドが通らない。

上記ページの手順で追加した「Gradle Runner」のステップ内にあるInput variables>gradlew file pathの項目に以下を設定する。

./gradlew

最小構成のプロジェクトなら、これだけ手直しすればビルドが通ってaabができるはず。

(追記)最新の設定だと、「Gradle Runner」を追加せずともaabファイルを生成できる模様...何のために試行錯誤したのか。。。

google-services.jsonの準備

google-services.jsonはFirebaseの機能を使うためにアプリに組み込む設定ファイル。秘匿情報が含まれるため、原則Gitには登録しない。しかし、Gitに登録しないとBitriseでビルドする時にこの設定ファイルが無いせいでビルドに失敗する。

この矛盾を解消するために、Bitriseに用意されているテキスト生成のステップを利用する。ざっくり書くと、以下。

  1. ファイルの中身をまるっとコピーする。
  2. コピーしたテキストをBitriseの定数として保存。
    • 定数の名前は適当でOK。例えば直感的にGOOGLE_SERVICES_JSONとか。
  3. テキストファイル生成のステップ(Generate Text File)を追加。
    • 定数として定義したテキストを使って、google-services.jsonファイルとして生成する。

「テキストファイルを生成する」ステップが用意されているのが、直感的で非常にわかりやすい。

センシティブな情報の設定

おそらくAndroidアプリ開発者ならほとんどの人がハマるポイント。build.gradleBuildConfigFieldを定義する際、ダブルクォーテーションを定義に含めないと、生成されるBuildConfigでいい感じに定義できない問題。これがBitriseでも(というより環境変数として定義する場合でも)同様に発生する。

何も考えないならbuild.gradle内で

buildConfigField "String", "AD_UNIT_ID", "\"広告ID\""

って形で定義すれば問題ない。

しかし、これを(センシティブな情報だから、外部に設定+それを参照するような形とするために)環境変数などに設定しそれを参照する形で

buildConfigField "String", "AD_UNIT_ID", System.getEnv(定義したキー)

って書くと残念ながらビルドに失敗する。設定値側(環境変数)にダブルクォーテーションを含めて定義するか、参照時に文字テンプレートを使うことで解消できる。

AndroidManifest.xmlも参照する必要が出てくるはずなので、文字テンプレートを使った方が無難。つまり以下。

buildConfigField "String", "AD_UNIT_ID", "${System.getEnv(定義したキー)}"

参考

2023年7月31日月曜日

CI/CD 各種サービスを比較し使うものを選定する

この前の続き。CI/CD環境の構築に向けて、良さそうなサービスを探す。

CI/CDと聞いて真っ先に思いつくのはJenkinsだが、オンデマンドに構築できるほど私のプライベート環境は充実していないので却下。外部サービスで検討する。

調査・知っている範囲で、以下のサービスをピックアップした。

  • Github Action
  • Circle CI
  • TravisCI
  • Bitrise

で、結論としてBitriseで進めることにした。

理由としては

  • Bitriseはモバイルアプリ(特にAndroid)のインテグレーション(単体テストなど)、デプロイ(apkやaabの生成、GooglePlayStoreへのアップロード)が初期状態でほぼ構築済み。ユーザーは必要なパラメーターを入力するだけでほぼ実現できる。

Bitrise以外のサービスについては

  • GitHubActionはリポジトリをpublicにしたいという要件を満たせない。署名キーや広告IDは秘匿にできるにせよ、それにより生成されたバイナリが表に丸見えになりうる。やり方次第かもだが、バイナリを生成するワークフローを表に見せたくない…。
  • CircleCIはfastlaneの導入が必要になる。iOSアプリ開発者だと、コマンド一つでipaを生成するために導入したりなど比較的馴染みのあるツールだが、AndroidでCI/CDするためだけにわざわざ導入したいと思わない。
  • 残るTravisCIがBitriseの対抗馬となったが、導入の容易さから結果としてBitriseに軍配があがることとなった。

ただし注意事項として、Bitriseは1アカウントにつき処理できるジョブやタスクの回数?リソースの使用量?に制限がある。無料アカウントでは、毎月「300クレジット」という単位でサービスを利用できるが、これを越えると次のクレジット支給まで使えなくなる様子。
正直どんなもん?というところだが、(構築後日談として)1回のワークフロー(ビルドをするためのセットアップからビルド完了までの一連の流れ)を処理するのに大体10クレジット程度を消費しているため、30日間ではおよそ30回しか利用できない、ということになる。
とはいえ「プライベートで回している開発フローで、複数のプロジェクトを加味する必要があるとはいえ1ヶ月に30回もリリースビルド→デプロイすることあるか…?」と考えると、これが制限となってしまうことは稀になりそうだ。

というわけで今回はCI/CD環境を構築するためのサービスの選定とその理由について投稿した。次回はBitriseを利用したAndroidアプリのデプロイ環境の構築について投稿予定だ。

2023年7月30日日曜日

正規表現 文字列の一部だけを加工したい

Logcatとかコンソールでログとか漁ってるときに、「必要なところを探して、必要な所だけくり抜くのマジだるい…」ってなる。

正規表現を使えば簡単なんだけど、「必要な所だけくり抜く」表現がわからなかったので放置してた。でもいい加減(ちゃんと書ければ秒で済む話を何時間もかけて作業してるの、マジ無能…と思い)なんとかしたかったので、調べて備忘録として残す。

知ってしまえば本当に簡単なんだわ。

検索での表現

(検索したいけど置換したくない文字)なにかしら置換したい文字(検索したいけど置換したくない文字)

置換の表現

$1置換後の文字$2

ポイントは

  • 「くり抜くところ」を括弧書き()にすると、置換するときに$*(数字)て書けば検索したときに括弧書きに該当するところがそのまま残る。ちなみに、カッコはグループ化する表現らしい。
  • そのまま残したいところが複数ある場合でも、$に付ける数字を増やしていけばOK。

<div>タグを<p>タグに変えたい。"/"も気にせず置換したい。

検索での表現

<(/*)div>
  • 検索対象のdivを指定する。
  • /があるかないかは、置換後のテキストにも影響するので、()で書く。
  • *は0文字以上の意味。

置換での表現

<$1p>

  • 置換したい文字としてpタグを指定する。
  • ()で書いた箇所が$1として置換後のテキストに反映される。
  • 今回は、/があった場合に限り置換後に/が入るようにする。

参考

移行予定

どうも。どっことです。 タイトルの通りですが、諸事情により GitHubPage に移行予定です。 https://mkt120.github.io/ この備忘録に記載の内容を転記しつつ、今後はこちらのページを更新していく予定です。