ProgressBar用にDrawableを作成メモ
基本的にはdraw
の中で描画をしてあげるだけで良い
動きをつける場合にはgetLevel()
で取得できる値を元に行うと簡単
getLevel()
の値の範囲は[0, 10000]
サイズの変更はonBoundsChange(Rect)
で受け取れる(draw
の前に最初に呼ばれるが必ずそうなのかは要調査)
public class MyDrawable extends Drawable { private static final int INDICATOR_COUNT = 12; private static final int MAX_LEVEL = 10000; private RectF rectF = new RectF(); private Paint p; private int centerX; private int centerY; private int width; private int height; public MyDrawable() { p = new Paint(); } @Override public void draw(@NonNull Canvas canvas) { int duration = MAX_LEVEL / 4; int currentPos = ((getLevel() % duration) / (duration / INDICATOR_COUNT)) % INDICATOR_COUNT; for (int i = 0; i < INDICATOR_COUNT; i++) { // 先頭との差によって色を変える[0xaaaaa, 0xffffff]の範囲で int diff = ((currentPos + INDICATOR_COUNT) - i) % INDICATOR_COUNT; diff = Math.max(Math.min(diff, 0x4), 0x0); p.setColor((0xff000000 | (0x00111111 * (0xf - diff)))); float r = 32 * width / 100f; canvas.drawRoundRect(rectF, r, r, p); canvas.rotate(360f / INDICATOR_COUNT, centerX, centerY); } } @Override public void setAlpha(int i) { } @Override public void setColorFilter(ColorFilter colorFilter) { } @Override protected void onBoundsChange(Rect bounds) { super.onBoundsChange(bounds); centerX = bounds.centerX(); centerY = bounds.centerY(); width = bounds.width(); height = bounds.height(); float scale = width / 100f; rectF.set(centerX + 24 * scale, centerY - 4 * scale, width - 2 * scale, centerY + 4 * scale); } @Override public int getOpacity() { return PixelFormat.TRANSLUCENT; } }
今回作ったものは以下のような表示をする(背景は別で灰色にしています)
setAlpha
やsetColorFilter
については調べられてないので調べる必要がある
また、getLevel
を使う以外にもアニメーションを行える方法があるようなので他の方法も調べたい
AndroidのRotateDrawableで回転速度を調整する
RotateDrawableとは
RotateDrawableはDrawableを回転させることができるDrawableで、以下のようなdrawableファイルを作成することで使うことが可能になります
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_action_reload" android:pivotX="50%" android:pivotY="50%" />
今回はRotateDrawableの回転速度を変更することができないか調査してみました
drawableファイル内で速度を変更させる
drawableファイル内で速度を変更するにはfromDegrees
とtoDegrees
の値を設定することで変更できます
toDegrees=0, fromDegrees=360
とtoDegrees=0, fromDegrees=3600
を比較すると後者が10倍ほど早く回転します
<?xml version="1.0" encoding="utf-8"?> <rotate xmlns:android="http://schemas.android.com/apk/res/android" android:drawable="@drawable/ic_action_reload" android:fromDegrees="0" android:pivotX="50%" android:pivotY="50%" android:toDegrees="3600" />
API21時点ではデフォルト値は以下のようになっているようです
float mFromDegrees = 0.0f; float mToDegrees = 360.0f;
実際の動作
今回はProgressBarを使って表示を行いました
<ProgressBar android:layout_width="64dp" android:layout_height="64dp" android:indeterminateDrawable="@drawable/rotate_default" />
結果は以下のようになりました
(toDegrees,fromDegrees)
の値は,
左から, (指定なし,指定なし), (0,360), (0, 3600)です
Android gradleで特定のvariantのみで処理を行う
以下のようなflavorやbuildTypeがある場合にproductReleaseでのみ処理を行いたい場合などがある
flavor
- develop
- product
buildType
- debug
- release
以下のようにbuild.gradleでflavorやbuildTypeが何なのかを見て特定のvariantを抽出する
抽出したvariantを使って行いたい処理を行うと良い
android { buildTypes { release { minifyEnabled false proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } } productFlavors{ develop{} product{} } variantFilter { variant -> def names = variant.flavors*.name if (names.contains("product") && variant.buildType.name == "release") { // do something // ex. variant.ignore = true } } }
SimpleDateFormatのLocaleとタイムゾーンのメモ
Localeを指定するとタイムゾーンが変わるかと思っていたが実際は変わらなかったのでメモ
Localeを設定した時の挙動
以下のコードを3つのLocaleで実行してみた
Date date = new Date(System.currentTimeMillis()); SimpleDateFormat sdf = new SimpleDateFormat("yyyy.MMMMM.dd GGG hh:mm aaa", locale); Log.d(TAG, "format: " + sdf.format(date));
結果は以下のような出力になる
Locale | 出力 |
---|---|
JAPAN | 2016.12.08 西暦 12:07 午前 |
CHINA | 2016.12.08 公元 12:07 上午 |
US | 2016.D.08 AD 12:07 AM |
Localeを変えてもすべて12時7分になっていた
Localeの指定では午前やAMなどの表記が異なるようだ
よく考えるとアメリカ国内でも地域によって時差が違っているのにUSのみなのはおかしい・・・
TimeZoneを設定する
実際にタイムゾーンを考慮してフォーマットするためには
DateFormat#setTimeZone(TimeZone)
を使えば良い
例:東京とニューヨークの例
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Tokyo")); Log.d(TAG, "format: " + sdf.format(date)); sdf.setTimeZone(TimeZone.getTimeZone("America/New_York")); Log.d(TAG, "format: " + sdf.format(date));
結果は以下の通り
format: 2016.12.08 西暦 00:57 午前 format: 2016.12.07 西暦 10:57 午後
adbコマンドで引数に&などの記号がある場合の対処法
adbコマンドに文字列を渡す際に、&や|が入っているとうまく文字列が渡されないという問題がある
例えば、以下のようにテキストを入力するためのコマンドのadb shell input text
に'&'や'|'が入っている文字列を渡すと途中までしか入力が行われなかったりエラーになってしまう
$ adb shell input text 'example&text'
対処方法は'&'や'|'など入力できない記号を '\' (バックスラッシュ)でエスケープしてあげることです
さきほどの例の場合は以下のようにすると無事入力ができました
$ adb shell input text 'example\&text'
EditTextへのプレーンテキストのペースト
AndroidのEditTextではペーストをすると以下のようにHTMLのタグが有効な状態で表示が行われます
今回はペースト時にプレーンテキストで貼り付けをする方法がないか調べてみました
(以下のコードはAPI24のソースコードを参照しています)
ペーストの実装を調査
まずはEditTextでペーストを押した時にどのようなコードが実行されているか調べてみたところ、
onTextContextMenuItem
の中の以下のコードのid=ID_PASTEの場合のコードが実行されているようです
switch (id) { … case ID_PASTE: paste(min, max, true /* withFormatting */); return true; case ID_PASTE_AS_PLAIN_TEXT: paste(min, max, false /* withFormatting */); return true; … }
id=ID_PASTEの場合はhtmlが有効な状態の表示になります
プレーンテキストで貼り付けを行うにはid=ID_PASTE_AS_PLAIN_TEXTになるようにコードを実行させると良さそうです
EditText内でID_PASTE_AS_PLAIN_TEXTが使われているのは
public boolean onKeyShortcut(int keyCode, KeyEvent event)
でCtrl+Shift+Vが押された時の場合のみのようです
@Override public boolean onKeyShortcut(int keyCode, KeyEvent event) { … } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) { … case KeyEvent.KEYCODE_V: if (canPaste()) { return onTextContextMenuItem(ID_PASTE_AS_PLAIN_TEXT); } … }
ただ、これは外付けキーボードなどがないと実行することはできそうにないです・・・
ちなみに ID_PASTE_AS_PLAIN_TEXTの実態はandroid.R.id.pasteAsPlainText
となっています
これはAPI23(Android M)から追加された値です。そのためAPI23とそれ以前ではonTextContextMenuItem
の実装が変わっていました
まとめ
今回調べたところEditTextでプレーンテキストを貼り付けさせる方法は提供はされているがスマホでは簡単には実行できそうにありませんでした
onTextContextMenuItem
の実装を変更すると強制的にプレーンテキストのペーストにできそうではありましたが、バージョンごとに処理を変更したり、動作確認が大変なためあまり実用的ではなさそうですね
AndroidでWeb上のSVGファイルを表示
Androidでは公式にSVGファイルの読み込みがサポートされましたが、 drawableディレクトリにあるファイルを表示する方法がメインでWeb上にあるファイルを簡単に表示する方法がわからなかったので調べてみました。
Androidで画像表示用ライブラリといえばGlideとPicassoの2つが有名ですがPicassoでは簡単に表示する方法がなさそうだったので今回はGlideを使った例を紹介します。 2016/05/31現在の最新バージョンの4.0.0-SNAPSHOTですが安定版の3.7.0を使用します。
Glide SVG表示サンプルの実行
Glideの場合は公式にSVG画像を表示するサンプルがあります。 実行すると以下の様な画面が表示されます
SVGファイルを表示
GlideでSVG画像を表示するには以下のライブラリが必要です
dependencies { compile 'com.android.support:support-v4:19.1.0' compile 'com.github.bumptech.glide:glide:3.7.0' compile 'com.caverock:androidsvg:1.2.1' }
また、サンプルにあるMainActivity以外のクラスをコピーしておきます。あとは、Activityなどで以下の様なコードを実行するとSVG画像を表示することができます
GenericRequestBuilder<Uri, InputStream, SVG, PictureDrawable> requestBuilder = Glide.with(this) .using(Glide.buildStreamModelLoader(Uri.class, this), InputStream.class) .from(Uri.class) .as(SVG.class) .transcode(new SvgDrawableTranscoder(), PictureDrawable.class) .sourceEncoder(new StreamEncoder()) .cacheDecoder(new FileToStreamDecoder<>(new SvgDecoder())) .decoder(new SvgDecoder()) .diskCacheStrategy(DiskCacheStrategy.SOURCE) .error(android.R.drawable.progress_horizontal) .placeholder(R.mipmap.ic_launcher) .animate(android.R.anim.fade_in) .listener(new SvgSoftwareLayerSetter<Uri>()); requestBuilder.load(Uri.parse("http://www.clker.com/cliparts/u/Z/2/b/a/6/android-toy-h.svg")) .into(imageView);