由於 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!
沒有留言:
張貼留言