最近ハマった事象の備忘録(SwitchCompat)
- はじめに
- ハマリポイント
- 導入
- カスタマイズ記事
- ListViewで罫線が消えることがある
- 初期化時/再表示時に勝手に ON/OFF が動いてしまう
- SwitchCompat を連打すると残像が残る
- Nexus 7でつまみ部分が表示されなかった(以前の体験)
はじめに
新年あけましておめでとうございます
去年は、年末に歯痛になったり*1、スマホ専用手袋*2の片方紛失したり
とかあんまりいい感じじゃありませんでしたが
今年はいいこと有るといいなーと思いつつ、今年も頑張りたいと思います
ハマリポイント
SwitchCompatに関して、色々とハマリポイントが有るのでメモしておく
単純に使うだけなら問題ないのですが
- ListView
- RecyclerView
等で ViewHolder 等でSwitchCompatを 使いまわすと挙動がおかしくなります
導入
appcompatに同梱されている
- build.gradle
dependencies {
compile 'com.android.support:appcompat-v7:24.1.+'
}
カスタマイズ記事
ListViewで罫線が消えることがある
Lolipopの一部の端末で発生
対処法
- style.xml
<style name="Color1SwitchStyle"> <item name="colorControlActivated">@color/my_awesome_color</item> </style>
- layout.xml
<RelativeLayout xmlns:app="http://schemas.android.com/apk/res-auto" ...> <android.support.v7.widget.SwitchCompat android:layout_width="wrap_content" android:layout_height="wrap_content" app:theme="@style/Color1SwitchStyle"/>
プログラムで書くなら
ContextThemeWrapper ctw = ContextThemeWrapper(this, R.style.Color1SwitchStyle); SwitchCompat sw = new SwitchCompat(ctw)
初期化時/再表示時に勝手に ON/OFF が動いてしまう
- 初期表示時
- notifyDataSetChangedで再表示時
のときの現象。(Array)Adapter::sort 処理とかも絡めるとさらにカオスw
対処法
stackoverflow だと下記なコードがでてきますが、前者より後者のほうがベターかと
- 微妙なコード (一度削除して追加し直し)
ViewGroup viewGroup = (ViewGroup) view; // the recycled view viewGroup.removeView(switch); switch.setChecked(states[index]); viewGroup.addView(switch);
- betterなコード(OnTouchListenerで弾く方法)
private Boolean isTouched = false; @Override public void onBindViewHolder(ViewHolder holder, int position) { switchButton.setOnTouchListener(new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { isTouched = true; return false; } }); switchButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { @Override public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { if (isTouched) { isTouched = false; if (isChecked) { } else { } } } }); }
setOnCheckedChangeListenerをOnTouchされない限り動かさないようにするコードです
RecycleViewだと特に onBindViewHolder でClickListner等をつけることを強いられるのでこの方法がベーターかと
SwitchCompat を連打すると残像が残る
SwitchCompatにデフォルトに設定されているアニメーションが動いて残像に見えてしまう現象
style.xml指定で殺せればいいんですけどね。。
対処法
- SwitchCompat.java
@Override public void setChecked(boolean checked) { super.setChecked(checked); // Calling the super method may result in setChecked() getting called // recursively with a different value, so load the REAL value... checked = isChecked(); if (getWindowToken() != null && ViewCompat.isLaidOut(this)) { animateThumbToCheckedState(checked); //■デフォルトのアニメーション } else { //★ // Immediately move the thumb to the new position. cancelPositionAnimator(); setThumbPosition(checked ? 1 : 0); } }
と実装されていて、WindowToken が nullのときにアニメーションを無効にできるようなので
- SwitchCompatを継承したクラスを作成
- getWindowToken() の戻り値に強制的に null を返すように改変
したものをlayout.xmlに設定すれば一応対処はできる。
ただこれだと完全にアニメーションが消えてしまうんですよね・・
Nexus 7でつまみ部分が表示されなかった(以前の体験)
一応下記のissueで対応はされているらしい
ただ、現在 Nexus 7サイズ のタブレットって実は殆どリリースされていなかったりするので
最新版がちゃんと動くか確認しづらいかもな。。と