2022年8月4日木曜日

Android DialogFragmentをフルスクリーン化する実装方法を解説

どうも。どっことです。今回はDialogFragmentをフルスクリーン化する実装方法を解説します。

DiagloFragmentをフルスクリーンで表示する

DialogFragmentはダイアログを表示するためのクラスです。シンプルなダイアログを表示するために使うのはもちろんですが、自分で色々カスタマイズできる拡張性の高いクラスでもあります。今回は、そんなDialogFragmentをカスタマイズするために画面いっぱいに表示する実装(フルスクリーン化)を解説します。

実装方法

今回はまとめてスニペットを載せたいと思います。ポイントはonStart()です。
class CustomDialogFragment : DialogFragment() { 
  
  override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    return Dialog(requireActivity()).also { dialog ->
      // 表示したいViewをここで生成します。LayoutInflaterなどを使ってもOK
      val view = View(requireContext()) 
      dialog.setContentView(view)
    }
  }

  override fun onStart() {
    super.onStart()
    // onStart() で以下の処理をします。
    dialog?.window?.also {
       // ①背景色を背景透過にするよう設定(完全にフルスクリーンにするなら必要)
       it.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
       // ②画面サイズに合わせて領域を広げる
       it.setLayout(
          ViewGroup.LayoutParams.MATCH_PARENT,
          ViewGroup.LayoutParams.MATCH_PARENT
       )
    }
  }
}

onStart①背景色を透過にする②表示領域を画面いっぱいに広げるように設定します。これにより表示するダイアログをフルスクリーン化することができます。

まとめ

今回はDialogFragmentのフルスクリーン化について解説しました。DialogFragmentは拡張性が高い反面、使いこなすのが非常に難しいクラスです。ただ正しく理解さえできれば一つ一つの処理は難しいものでは無いので、どんなカスタマイズでもできるようにマスターしていきたいですね。


Android ProgressBarで進捗を表示する

横に伸びるProgressBarを表示する。

レイアウトファイル

    <ProgressBar
        android:id="@+id/progress_bar"
        style="?android:attr/progressBarStyleHorizontal"
        android:max="100"
        android:min="0"
        android:layout_width="240dp"
        android:layout_height="30dp"/>

コードで進捗を更新する。

val progressBar = it.findViewById<ProgressBar>(R.id.progress_bar)
progressBar.progress = 0 // アニメーション無し
progressBar.setProgress(progressBar.progress + 50, true) // アニメーション有り

// 滑らかなアニメーション
val animation = ObjectAnimator.ofInt(progressBar, "progress", progressBar.progress + 50)
animation.setDuration(1000); // 1000ms = 1sec の時間でアニメーションさせる
animation.setInterpolator(new DecelerateInterpolator());
animation.start();

2022年8月3日水曜日

Android ディレクトリを作成する

どうも。どっことです。今回はアプリ固有のファイル領域にディレクトリを生成する実装方法を解説します。

さっそくですが、実装サンプルです。階層構造のあるディレクトリを生成するケースとして、階層ごとに生成するケースとまとめて生成するケースを紹介します。

ディレクトリ階層ごとにディレクトリを生成する

階層ごとに生成するケースを紹介します。最初にディレクトリを生成したあと、そのディレクトリを親ディレクトリとして指定する形で子ディレクトリを生成します。

val parent1 = File(requireContext().filesDir, "parent1")
// ディレクトリ(parent1)を作成する
parent1.mkdir()
val parent2 = File(parent1, "parent2")
// 作成したparent1ディレクトリを親にして、子ディレクトリ(parent2)を作成する
parent2.mkdir()

複数のディレクトリ階層があってもまとめて生成する

こちらはまとめて生成するケースです。ディレクトリ名の指定に親ディレクトリを含めることで、その親ディレクトリもまとめて生成してくれる。というわけです。唯一注意が必要なのは、ディレクトリを生成する関数が前のサンプルではmkdir()をつかっていましたが、今回はmkdirs()を使っている点でしょうか。

val parents = File(requireContext().filesDir, "parent1/parent2")
parents.mkdirs()

2022年6月18日土曜日

HTML/CSS 画面上の文字や画像を選択状態にできないようにするCSS設定を紹介

どうも。どっことです。今回はWebページ上の文字や画像を選択できないようにするCSSについて解説します。

テキストや画像が選択状態にできないようにする

テキストにクリックリスナーを設定した際、そのテキストが選択状態になってしまい、シンプルにダサいです。今回はそんな経緯から、テキストや画像が選択状態にできない設定を紹介します。

設定方法

設定はシンプルで、該当のテキスト・画像のタグに以下を設定します。

user-select: none;

例えば画像に設定する場合はimgタグなので以下となります。

img { 
    user-select: none;
}

簡単ですが、以上です。

参考

2022年6月17日金曜日

Dart コンストラクタについて整理

サンプル1 finalなメンバ変数無し

class Sample {
  Sample();
}

サンプル2 finalなメンバ変数あり

class Sample {
  final String value;
  Sample(this.value);
}
  • Sampleクラスを使う側が value の値を設定しなければならない。

サンプル3 finalなメンバ変数あり + 初期値あり

class Sample {
  final String value;
  Sample({this.value = "initial string"});
}
  
  • Sampleクラスを使う側は value の値を設定する必要はない。
  • 設定しなければ初期値の値が設定される。

サンプル4 finalなメンバ変数あり + Nullable

class Sample {
  final String? value;
  Sample({this.value});
}
  • Sampleクラスを使う側は value の値を設定する必要はない。
  • 設定しなければnullが設定される。

2022年3月22日火曜日

Flutter ダイアログを表示する実装方法を解説

何も考えないなら以下をコピペして呼び出す。 

static void showDialog(BuildContext context, String title, String content, String positiveButton, String negative,
      {VoidCallback? onPositiveButtonPressed, VoidCallback? onNegativeButtonPressed}) {
      showDialog<int>(
        context: context,
        barrierDismissible: true, // キャンセル
        builder: (BuildContext context) {
          return AlertDialog(
              title: Text(title),
              content: Text(content),
              actions: [
                TextButton(child: Text(positiveButton), onPressed: onPositiveButtonPressed),
                TextButton(child: Text(negative), onPressed: onNegativeButtonPressed)
              ]);
        });
}

2021年5月10日月曜日

Android AdMob、FirebaseとEUユーザからの同意の取得について

経緯

AdMobとFirebase あたりから読み進めたので整理。

AdMobについて

さまざまなフォーマットオプションで広告を表示することができる。
  • バナー
  • インタースティシャル
  • ネイティブ
  • リワード

広告を表示するためには、Google Mobile Ads SDK を統合するための AdMob 登録アプリが必要。要はアプリをAdMobに登録してねってことかな。

    実装の流れ

    1. Firebaseにアプリを登録
    2. AdMobアカウントを作成
      1. アプリを登録
      2. ユーザに関する指標を有効にする
      3. AdMobアプリをFirebaseにリンクする
    3. プロジェクト依存関係の更新
      1. Google Mobile Ads SDK を追加
    4. 広告の実装

    まあ、これといって難しそうなところはなさそう。

    Androidスタートガイド

    AdMobアカウントでアプリを設定する

    1. アカウントを作成
    2. アプリを登録

    アプリをFirebaseにリンクする

    強く推奨らしい。AdMobアカウントのダッシュボードページで以下を設定する。

    1. ユーザに関する指標を有効化
    2. アプリをFirebaseにリンク

    ここからは具体的な実装の話

    1. アプリIDをAndroidManifest.xmlに追加
    2. Mobile Ads SDK をbuild.gradle追加
      1. MobileAds.initialize()をコールし初期化 (★気になる一文あり)
    3. ユーザに関する指標とアナリティクスデータ
      1. Mobile Ads SDK で初期化するとロギングが開始されるので、ちゃんと初期化できているか確認してね。と読み取れる。
    4. (省略可)GoogleAnalyticsやFirebaseの機能を使用
      1. 色々機能を使って、ユーザの利用数(エンゲージメント)を増やしてね。と読み取れる。
    5. アプリに実装する広告フォーマットの選択
      1. アプリに合わせて実装する広告のフォーマットを選択する。

      (★気になる一文あり)に以下の文言が。

      広告を読み込む前になんらかの操作を行う必要がある場合は、必ず Mobile Ads SDKを初期化する前に行ってください。初期化の前に必要なアクションの例を次に示します。
      欧州経済領域(EEA)のユーザーから同意を得る

      ヨーロッパって広告を出す前にユーザから同意を得ないといけないらしい。マジか。そういえば、どこかのサイトにアクセスするたびに「Cookie使うで?ええか?」という警告が出るようになったけど、あれってこれのせいか。スタートガイドとはいえ、こういうアナウンスをしてくれるのは優しいな。

      EU ユーザーからの同意の取得

      EUユーザに対しては以下のケースで同意を得る必要がある。

      • Cookieやローカルストレージの利用
      • 広告配信を目的とした個人データ(AdIDなど)の利用

      Googleではこの義務の遂行をサポートするためのConsent SDKを提供している。(実装が楽できる!うれしい!)Googleが配信する広告は「パーソナライズされている・いない」の2種類がある。

      • デフォルトは「されている」。「されていない」に変更することも可能。
      • EUユーザに対してはどちらを利用するにしても同意が必要。

      詳細

      前提としてAdMobアカウント上で、広告技術プロバイダを選択しておく必要がある。

      • build.gradleにConsent SDKを追加する
      • Consent SDKを使うときは、必ず事前に同意ステータスを更新しておく。
        • 同意ステータスは、ユーザが同意しているかどうか。
        • 「同意ステータスを更新する」は「同意ステータスを把握する」と読み取れる。
      • SDKに同意ステータスのアップデートをリクエストするAPIがあって、アプリを起動するときにそれをコールする。
        • ユーザが同意した後に、広告技術プロバイダが変わると、同意ステータスが取得できていない状態(不明ステータス)になる。

      メディエーションを利用しない場合・する場合について

      よくわからないメディエーションなるキーワードが出てきた。このへんによると、第三者広告ネットワーク?を使って収益向上を図る仕組みらしい。今度は第三者広告ネットワークが何者か分からないけど、このへんによると「収益性が良さげな広告を選んでくれる広告マネージャー」のことを指しているように見える。

      • 収益性が良さげな広告選んでくれるならええやん!ってなりそう

      メディエーションを利用しない場合

      Consent SDKで同意を得る実装方針は2つ

      • Google提供の同意フォームを掲示する
        • このフォームには開発者が選択した広告技術プロバイダのリストが表示される
      • すべての広告技術プロバイダのリストをAdMobから動的に取得し、開発者自身がそれらをユーザに掲示するための実装を行う。
        • こだわりがある人はこちら、という印象。
      • ユーザが回答したら、その回答情報をSDKに保存するように指示できる
        • これが完了したらGoogle Mobile Ads SDKに回答(同意)を送信できるようになる。
      • パーソナライズされていない広告に限って同意した場合は、それをGoogle Mobile Ads SDKで送信する必要がある。
        • 結局どちらの広告であってもSDKに送信が必要と読み取れる。

      AdMobメディエーションを利用する場合

      すべての広告技術プロバイダのリストをAdMobから動的に取得し、開発者自身がそれらをユーザに掲示するための実装を行う必要がある。Googleではメディエーションネットワークに関する同意の取得も処理もできない。

      • ただし一部のメディエーションネットワークに対する同意の転送方法についてのドキュメントは公開されているとのこと。
      • 何にせよ、便利なSDKがないならあまりやりたくない。

      同意ステータスの更新

      アプリ起動時に毎回実施する必要があるとのこと。具体的な同意ステータスの更新処理の実装方法は以下の通り。

      同意の取得

      Google提供の同意フォームの実装方法。以下のオプションを組み合わせてユーザに掲示できる。

      • パーソナライズ広告表示に同意
      • パーソナライズされていない広告表示に同意
      • 広告表示しない有料版を利用

      同意テキストを更新する場合はconsentform.htmlの内容を変更する。

      • ConsentFormオブジェクトを使って同意フォームを表示する。
        • プライバシーポリシーが必要!!
      • 同意を取得したら、同意の保存し情報を送信する。

      同意の変更や取り消し

      過去の同意を変更したり、取り消すことができる必要がある。

      同意年齢に満たないユーザ

      すべての広告リクエストにTFUAを設定する必要がある。

      • どうやって検知するんだろう。。。

      テスト

      EU内外の両方でアプリを簡単にテストできるように、Consent SDKにはデバッグオプションが用意されている。

      Google Mobile Ads SDK に同意の転送

      パーソナライズされていない広告を同意したケースの転送実装

      所感

      • AdMobメディエーションを利用すると色々大変そう。とりあえず利用しない方針で問題なさそう。
      • プライバシーポリシーのページを用意する必要がある。
      • 同意を変更する導線が必要。

      2021年4月19日月曜日

      Android カスタムViewでもダークモード対応する

      経緯

      カスタムViewを作ったけど、ダークモードのことをまったく気にしなかったせいで、カスタムViewの背景が真っ白になってしまった。

      思い

      values-nightフォルダを用意してcolors.xmlを入れるのもいいけど、そこまでしなくても標準の設定で十分なんだよなぁ。じゃあ標準ってどうやればいいんだ?と思って開発者サイト見たら、しっかり書いてあった。

      ダークテーマ

      ハードコードした色を削除してください(白を指定した背景色など)。その代わりとして ?android:attr/colorBackground テーマ属性を使用します。

      なーんだ。これ使えば楽勝じゃん。

      残念。mergeタグにbackgroundは効かないんだな。

      mergeタグってこういう所で融通きかないよね。duplicateParentStateつけないと正しく動作しない問題は解決してくれるけど。さて、となると?android:attr/colorBackgroundをコード上で参照しないといけないけど、どう実装すればいいんだ?

      答え

      ググったらバリバリ答えが書いてあるページが出てきた。

      how to get background color from current theme programmatically

      TypedValueを使えば参照できるらしい。というわけで最終的に実装した形がこれ

      typedValue = TypedValue()
      context.theme.resolveAttribute(android.R.attr.colorBackground, typedValue, true)
      setBackgroundColor(typedValue.data)

      全然ちょろかった。

      2021年3月24日水曜日

      JavaScript HTTP通信で情報取得する実装を紹介

      どうも。どっことです。情報取得する処理を紹介します。今回はJavascriptで情報取得する実装方法です。

      実装時の紹介

      実装は以下の4点です。
      1. XMLHttpRequestオブジェクトを作る
      2. 取得URLやメソッドを設定する
      3. 取得した時の制御をコールバックとして実装する
      4. 通信開始メソッドをコールする
      上記を踏まえサンプルを載せます。
      // 1.XMLHttpRequestの生成
      var xhr = new XMLHttpRequest();
      xhr.onreadystatechange = function () {
          // 3.取得した時の制御
          if (xhr.readyState == 4) {
              // 取得成功
          }
      };
      // 2.取得URL・メソッドの設定
      xhr.open("GET", "http://www.example.org/example.txt");
      // 4.通信開始メソッドをコール
      xhr.send();
      

      この辺は、ネイティブアブリを作るのと同じ感覚ですね。

      参考

      2021年3月4日木曜日

      HTML/CSS/JavaScript モーダル(ポップアップ)表示したい

      ボタンをタップしたらポップアップを表示させたいので実装方法を調べた。

      やったこと

      モーダル表示用のdivbodyタグにいれる+不要になったら捨てる。

      <div id="modal-view" class="modal-background">
        <div class="modal"/>
      </div>
      • modal-backgroundクラスは背景として設定。
      • modalクラスをポップアップぽくCSSを設定する。
      • 背景、ポップアップは参考サイトの設定を見てなんとなく。

      不要になったら以下で捨てる。

      var view = document.getElementById('modal-view');
      document.body.removeChild(view);

      移行予定

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