由於 ListView 捲動時會把畫面上的 item 重用以顯示不同資料
這樣會導致我們可能會刪除到非正確的 item
或是出現顯示上的問題(該 item 顯示的資料已經不同但是動畫卻還在它上面跑)
要解決這個問題就要使用 View 類別在 API 16 加入的新 method
public void setHasTransientState (boolean hasTransientState)
當設為 true 的時候,就告訴系統這個 View 應該盡可能的被保留,直到setHasTransientState(false)被呼叫
要注意這是可以重複設置的,也就是說每一個setHasTransientState(true)都要搭配一個setHasTransientState(false)才能回復
//Listview 的 OnItemClickListener 的內容 //本範例點了 item 後會淡出並刪除該 item public void onItemClick(AdapterView parent, final View view, int position, long id) { final String item = (String) parent.getItemAtPosition(position); ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.ALPHA, 0); anim.setDuration(500); view.setHasTransientState(true); //設為 true 宣告 item 要被追蹤 anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { myListview.remove(item); adapter.notifyDataSetChanged(); //重新整理 listview view.setAlpha(1); view.setHasTransientState(false); //完成後設定回 false } }); anim.start(); }另一種方法是用 ViewPropertyAnimator 來解決
public void onItemClick(AdapterView parent, final View view, int position, long id) { final String item = (String) parent.getItemAtPosition(position); view.animate() .setDuration(500) .alpha(0) .withEndAction(new Runnable() { @Override public void run() { myListview.remove(item); adapter.notifyDataSetChanged(); view.setAlpha(1); } } ); }但以上兩種方式最大的問題就是 API 16 以後才能使用(用到了 withEndAction 跟 setHasTransientState)
(該死的 Android Fragmentation...)
讓我們看看另一個例子
在 DevBytes: Animating ListView Deletion: Now on Gingerbread! 裡
他用了一個繼承自 ArrayAdapter 的自訂 adapter
override 掉 public boolean hasStableIds() 讓它總是回傳 true ,用來取代 setHasTransientState(true)
//用來取代 setHasTransientState(true) @Override public boolean hasStableIds() { return true; //總是回傳 true,用來取代 setHasTransientState(true) }
而 withEndAction 的部分則用 setAnimationListener 取代
//API 11 之前的方法 TranslateAnimation translator = new TranslateAnimation(startX, endX, startY, endY); translator.setDuration(150); view.startAnimation(translator); view.getAnimation().setAnimationListener(new AnimationListenerAdapter() { @Override public void onAnimationEnd(Animation animation) { new Runnable() { @Override public void run() { //...(略) } } } });
這樣可以讓 Gingerbread(API 10) 或更早的 Android 版本相容
如果是 4.0 (API 14)之後的版本
還是用 view.animate() 跟 ObjectAnimator 來做
//API 小於 16 但大於等於 14 可以這樣做 view.animate().setDuration(150); ObjectAnimator anim = ObjectAnimator.ofFloat(view, View.TRANSLATION_X, startX, endX); anim.setDuration(150); anim.start(); setAnimatorEndAction(anim, new Runnable() { @Override public void run() { //...(略) } });
相關資料:
YouTube - DevBytes: ListView Deletion
YouTube - DevBytes: ListView Animations
YouTube - DevBytes: Animating ListView Deletion
YouTube - DevBytes: Animating ListView Deletion: Now on Gingerbread!
沒有留言:
張貼留言