Material Design データのアプリ内導入について
はじめに
- 企画/デザインの方が Mockアプリサービス でデザインと挙動提示
- そのMockと同じ挙動をするようにしてよ! がよくあるんだけど、素材パーツが提供されないことがよく有り。
という事がよくあって、作業備忘録的に手順を整理して見たメモ
動作環境
導入手順
なコードを改変して使っている感じ。
- app/build.gradle
android { ... dataBinding { enabled = true } } dependencies { ... compile "com.mikepenz:iconics-core:2.8.7@aar" compile 'com.mikepenz:fontawesome-typeface:4.7.0.0@aar' }
- CustomApplication.java
protected void attachBaseContext(Context base) { if(base instanceof Activity){ super.attachBaseContext(IconicsContextWrapper.wrap(base)); } else{ super.attachBaseContext(base); } }
Qittaの記載より、こう書くほうが楽。
ただし適応できるのはActivityのみでソレ以外に適応するとNullPointerExceptionで落ちる
- CommonAdapter.java
public class CommonAdapter { @BindingAdapter(value = { "drawable_icon_font", "drawable_icon_font_color" },requireAll = false) public static void setDrawableIconFont(final View view, final String icon,Integer hint_color) { if(hint_color != null){ hint_color = android.R.color.holo_orange_light; //hintのカラー指定 } final Context context = view.getContext(); final IconicsDrawable iconicsDrawable = new IconicsDrawable(context) .icon(FontAwesome.Icon.valueOf(icon)) .color(hint_color) .sizePx((int)(view.getWidth())); setBackground(view,iconicsDrawable); } public static void setBackground(View view, Drawable drawable) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { view.setBackground(drawable); } else { view.setBackgroundDrawable(drawable); } } }
自分が使ってるのは FontAwesome で
- ただしfaw系は - を _ にする必要があり
ここらへんはまずはじめに戸惑う箇所かな・・*1
一応こういうルールっぽい
<TextView android:text="{faw-android} android" //★fontデータとして使う場合はそのまま android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="16dp" android:textColor="@color/colorAccent" android:textSize="30sp" /> <TextView android:text="android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/colorAccent" android:textSize="30sp" android:drawablePadding="4dp" app:drawable_icon_font_left="@{`faw_android`}" //名称検索する場合は - => _変換が必要 />
Qittaの例をそのままもってきた時に動かなかったケース
- textColorをdata-bindingで連動させて hint_color を変更させようとした
改変前(NG)
- layout.xml
<TextView tools:text=">" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@{ status.isToday() ? @color/colorGray : @color/colorAccent }" android:textSize="10sp" android:drawablePadding="2dp" app:drawable_icon_font_left="@{`faw_android`}" />
- BindingAdapterManager.java
public class BindingAdapterManager { @BindingAdapter("drawable_icon_font_left") public static void setDrawableIconFontLeft(final TextView tx, final String icon) { final Context context = button.getContext(); final IconicsDrawable iconicsDrawable = new IconicsDrawable(context) .icon(FontAwesome.Icon.valueOf(icon)) .color(tx.getCurrentTextColor()) .sizePx((int)(tx.getTextSize() * 1.25)); tx.setCompoundDrawables(iconicsDrawable, null, null, null); } }
改変後(OK)
- layout.xml
<TextView tools:text=">" android:layout_width="wrap_content" android:layout_height="wrap_content" android:textColor="@color/colorAccent" android:textSize="10sp" android:drawablePadding="2dp" app:drawable_icon_font_left="@{`faw_android`}" app:drawable_icon_font_color="@{ status.isToday() ? @color/colorGray : @color/colorAccent }" />
- BindingAdapterManager.java
public class BindingAdapterManager { @BindingAdapter("drawable_icon_font_left") @BindingAdapter(value = { "drawable_icon_font_left", "drawable_icon_font_left_color" },requireAll = false) public static void setDrawableIconFontLeft(TextView tx,String icon,Integer hint_color) { if(color == null){ hint_color = tx.getCurrentTextColor(); } final Context context = button.getContext(); final IconicsDrawable iconicsDrawable = new IconicsDrawable(context) .icon(FontAwesome.Icon.valueOf(icon)) .color(hint_color) .sizePx((int)(tx.getTextSize() * 1.25)); tx.setCompoundDrawables(iconicsDrawable, null, null, null); } }
因みに、
- final指定してるコードをよく見るが、まずいらない・・
- Integer hint_color を int hint_color と指定してしまうと省略するとエラーで落ちる
問題点
- fontデータ同梱なのでapkサイズが増える
- download Fontの機能みたいなのできないと厳しいよな・・(汗
使えないパターン
これ Prefrences用のxml/setting.xml とかには使えないので、
Android Studio 2.3.3
— close_yutori (@kimukou2628) 2017年6月15日
ただPreference系は、
Extract Stringのメニュー自体無かったり
アンスタ先生の補完一切効かないけど、、
(PreferenceFragmentって使う人殆ど居ないのかしら?
PreferenceScreen に android:layout="@layout/custom_preference" 指定のカスタムが一番楽 / “Android - Prefer…” https://t.co/37wnJvhbQk #Android #Preference
— close_yutori (@kimukou2628) 2017年6月15日
その場合は Material Design のサイトに行って検索、下記プラグインでresource配置
- Android Material Design Icon Generator
- Material Designのサイトから色指定して res/drawable に変換取り込みしてくれる
- 基本24dpと指定されている画像を使わないと駄目みたい
- Android Drawable Viewer
- res/drawable 配下の画像確認用
- AS3.0(AS2.4でも)では動かない
あたりで凌いでる感じですかね・・・。中々厳しい・・。
それ以外でハマるケース(運用面?)
ここらへんは運用バグとしか言えない気もする・・
- デザイナーさんからもらうデータ
- 画像に余白があるものが多い
- Material Design系のデータ
- 基本余白なし
まあ余白なしの方が調整しやすいんだけど、デザインは基本別工数、別発注扱いだしなー。
ちゃんと管理しているというなら計算してほしいよ・・・
もうやだ~><
— close_yutori (@kimukou2628) 2017年6月27日
デザインの微調整(画像差し替えによるデサイン崩れ)をプログラムで直せ
ってな~
しかもバグとかいって調整させるの良いけど
15分前とかに言うなや~
ここら辺は正直
— close_yutori (@kimukou2628) 2017年6月27日
Mock layout Webサービスの弊害かと思う。
パーツ無いとき=>Material.ioの素材で調整
(デザインモックサービスの即興配置用パーツは
ここら辺の使ってるから
デザイナーさんから画像素材来る
=>差し替えるとlayoutがくずれる
android
— close_yutori (@kimukou2628) 2017年6月27日
databindingで状態により、
アイコンを切り替える処理を書いている
貰った画像が状態ごとにサイズが違う
BindingAdapterのなかでサイズ変更して同じ大きさに見せる<イマココ
確かに出来るけど、なんか違う感満載orz
まあ手強かったのは、
— close_yutori (@kimukou2628) 2017年6月27日
画像サイズだけでなく
余白ありなし画像の混在だからだよな~
デザインは工数的に修正依頼は出せない状態
こういうのって発注段階のミスなんですかね(PG側は画像の編集自体は基本NGなのどこも変わらないし、、
で、具体的にコードで書くと下記なイメージになるわけです
@BindingAdapter("drawable_icon_font") public static void setDrawableIconFont(final View view, final String icon) { final Context context = view.getContext(); int color = R.color.colorGray; if(context instanceof DetailActivity){ color = R.color.colorAliceBlue; } //[TODO] playアイコンは画像に変更 if(icon.equals("faw_play")){ final Drawable drawable = ContextCompat.getDrawable(context,R.drawable.btn_play); final int size = DisplayUtils.pixelFormat(context,72); //final int size = (int)(view.getWidth()); //sizePx(size); same drawable.setBounds(0, 0, size, size); drawable.invalidateSelf(); view.post(new Runnable() { @Override public void run() { //画像リサ;イズ ViewGroup.LayoutParams params = view.getLayoutParams(); params.width = size; params.height = size; view.setLayoutParams(params); setBackground(view, drawable); } }); return; } final int size = DisplayUtils.pixelFormat(context,48); final IconicsDrawable iconicsDrawable = new IconicsDrawable(context) .icon(FontAwesome.Icon.valueOf(icon)) .color(ContextCompat.getColor(context,color)) .sizePx(size); view.post(new Runnable() { @Override public void run() { ViewGroup.LayoutParams params = view.getLayoutParams(); params.width = size; params.height = size; view.setLayoutParams(params); setBackground(view, iconicsDrawable); } }); }
- View自身のsetBounds
- Viewの親レイアウトのLayoutParams
でサイズ調整するという形。どっちか片方だけだと駄目。
view.post にしているのは UIThreadで実行されていないエラーがたまに出るため。
タイミング的な問題だけど、ココらへんの割り込みタイミングってG様黒魔術っぽいからなー(遠い目 *2
- DisplayUtils.java
public class DisplayUtils { public DisplayUtils() { } public static int pixelFormat(Context context, int dp) { float density = context.getResources().getDisplayMetrics().density; int px = (int)((float)dp * density + 0.5F); return px; } public static int getDisplayWidthPixels(Context context) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return metrics.widthPixels; } public static int getDisplayHeightPixels(Context context) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return metrics.heightPixels; } public static int getDisplayStatusBar(Context context) { DisplayMetrics metrics = context.getResources().getDisplayMetrics(); return (int)Math.ceil((double)(25.0F * metrics.density)); } }