ウィジェットで独自フォントを頑張って使う方法

ネットの情報をかき集めてAndroidプログラミングしています、ぐるぽです。

ウィジェットで常駐する時計アプリを制作していました。
そこで、通常のフォントではなく独自のフォントを使おうとしていたのですが、ウィジェットを調べていくと普通の方法では使えない事が判明…
(ウィジェットのアイテムのフォント指定部分には最初から用意されている3つのフォントしか選べない)

どうにかフォント利用できないかと調べていたら、

1.フォントをCanvasに描画
2.画像として保存
3・ウィジェットで画像表示

という方法を見つけました。

私の制作したアプリでは、設定画面(PreferenceActivity)でサイズと色を変更>設定画面終了時に画像生成 としました。

キモである設定画面のコード(必要な部分以外はカットしています)

/**
 * 設定画面
 * @author ぐるぽ
 */
public class SettingMenuActivity extends PreferenceActivity {

	@Override
	protected void onDestroy() {
		super.onDestroy();

		// 指定された設定で画像を生成してローカルフォルダに保存
		for (int i = 0; i < TokikakeClockWidgetProvider.IMG_NAMES.length; i++) {
			Bitmap bmp = createCharacterBitmap(
					TokikakeClockWidgetProvider.IMG_NAMES[i], size);
			saveBitmapToPng(String.valueOf(i), bmp);
		}
	}

	/**
	 * 指定された文字・フォントサイズで画像を生成する
	 * @param chara 文字
	 * @param size フォントサイズ
	 * @return Bitmap形式の画像
	 */
	private Bitmap createCharacterBitmap(char chara, int size) {
		// フォントを指定
		Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
		paint.setTypeface(Typeface.createFromAsset(getAssets(), "timeleap100.ttf"));
		paint.setTextSize(size);

		// フォントサイズに合った大きさの画像を生成する
		FontMetrics fm = paint.getFontMetrics();
		int height = (int) (fm.bottom - fm.top);

		float[] widths = new float[1];
		paint.getTextWidths(String.valueOf(chara), widths);
		int width = (int) widths[0];

		Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_4444);
		Canvas canvas = new Canvas(bmp);
		canvas.drawColor(Color.argb(0, 0, 0, 0));

		canvas.drawText(String.valueOf(chara), 0.0f, -fm.ascent, paint);

		return bmp;
	}

	/**
	 * BitmapをローカルフォルダにPNG形式で保存する
	 * @param fileName ファイル名
	 * @param bmp Bitmap形式の画像
	 */
	private void saveBitmapToPng(String fileName, Bitmap bmp) {
		try {
			OutputStream out = openFileOutput(fileName + ".png",MODE_PRIVATE);
			bmp.compress(CompressFormat.PNG, 100, out);
			out.flush();
			out.close();
			Log.i("list", fileName + ".png" + " create success!");
		} catch (IOException e) {
			e.printStackTrace();
			Log.i("list", fileName + ".png" + " can't create");
		}
	}
}

・PreferenceActivityのonDestroy()
設定画面を閉じた時に画像を生成したいので、PreferenceActivityのonDestroy()内で画像生成処理を呼び出します。

・createCharacterBitmap()
ここで独自フォントの画像をBitmap形式で生成しています。
(フォントを関数内で指定していますが、引数に与える形の方がいいですね…)
独自フォントはAssetsフォルダに置いています。

・saveBitmapToPng()
生成した画像をpng形式でアプリのローカルフォルダに保存します。
ローカルフォルダの読み込み・保存は簡単なので便利^^

ローカルフォルダ読込:InputStream is = context.openFileInput(“ファイル名”);
ローカルフォルダ保存:OutputStream out = context.openFileOutput(“ファイル名”,モード);

以上です。
Assetsフォルダとローカルフォルダを利用すれば、結構なんでもいけそうですね。

dpiとdip

Android端末の様々な大きさの画面に対応する為に、アプリの設定ではpxではなくdipという単位を使います。

dip。
Density Independent Pixel。
この値を使うと、端末のdpiによってサイズが切り替わります。
dpiによってサイズが変わることで、ボタンやテキストなどの画面上でのサイズを統一することができます。
(pxで直接指定してしまうと、dpiの低い端末では大きく、高い端末では小さくなってしまいます。)

端末のdpiの分類
・xhdpi(320dpi) ※2.3から
・hdpi(240dpi)
・mdpi(160dpi)
・ldpi(120dpi)

mdpi(160dpi)の時、1dip = 1pxとなります。

画像を扱う場合は、drawableフォルダに各dpiに合わせた画像を置いておけば、dpiによって読み込む画像が変わります。
(drawable-mdpiフォルダにいれておけば、mdpiの端末で読み込まれる)

dpiごとに画像を用意しなかった場合は、他dpiに用意した画像を拡大・縮小して表示する形になります。
(drawable-mdpiフォルダに画像を置いた状態で、hdpi端末から動かすと画像が拡大されて表示される)

dpiごとの倍率
・xhdpi:2 ※2.3から
・hdpi:1.5
・mdpi:1
・ldpi:0.75

拡大・縮小で画像が汚くなってしまうのを防ぐ場合には、dpiごとの倍率をかけたサイズの画像を用意しましょう。

以上。

IS01の右メニューの幅

IS01ではアプリ起動時、横向きだと画面右側にメニューが表示されています。(縦向きだと下に表示)
このメニューの幅は106ピクセルなので、アプリの表示領域はFWVGA(854*480)のサイズとなります。

エミュで実行していると気づかないのでご注意ください。
右側のメニューを消す方法もあるようですが、IS01独自のものなので消さずに対応する方が良いでしょう。

タイトルバーとメニューバーを非表示にする方法

デフォルトではAndroidアプリ実行時、タイトルバー・メニューバーが表示されています。
ゲームを制作する場合、どちらのバーも非表示にして画面全体、フルスクリーンモードで実行したいところ。

今回はタイトルバー・メニューバーを非表示にする方法を紹介します。

方法は簡単で、ActivityのonCreate()内に以下のコードを記述するだけ。

Window window = getWindow();

// メニューバーを非表示にする
window.addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);

// タイトルバーを非表示にする
window.requestFeature(Window.FEATURE_NO_TITLE);

※setContentView()を呼び出す前に設定すること;

Androidの描画クラス

Androidの描画クラスは3つあります。

・View
基本の描画クラスです。
ボタンやテキストフィールド、チェックボックスなどの部品を配置して作るツールの描画に適しています。

・SurfaceView
2Dのゲームやリアルタイムに描画をする必要があるアプリの描画に適しています。

・GLSurfaceView
3Dのゲームやリアルタイムに描画をする必要があるアプリの描画に適しています。