在 iOS 中,有一个非常简单且强大的工具来动画 UITableView 行的添加和删除,here's a clip from a youtube video 显示默认动画。请注意周围的行如何折叠到已删除的行上。此动画可帮助用户跟踪列表中的更改以及数据更改时他们在列表中查看的位置。
由于我一直在 Android 上进行开发,因此我没有发现可以为 TableView 中的各个行设置动画的等效工具。在我的适配器上调用 notifyDataSetChanged()
会导致 ListView 立即使用新信息更新其内容。我想在数据更改时显示一个新行推入或滑出的简单动画,但我找不到任何记录在案的方法来做到这一点。看起来 LayoutAnimationController 可能是让它工作的关键,但是当我在 ListView 上设置一个 LayoutAnimationController(类似于 ApiDemo's LayoutAnimation2)并在列表显示后从我的适配器中删除元素时,元素会立即消失而不是变得生动起来。
我还尝试了以下方法来在删除单个项目时对其进行动画处理:
@Override
protected void onListItemClick(ListView l, View v, final int position, long id) {
Animation animation = new ScaleAnimation(1, 1, 1, 0);
animation.setDuration(100);
getListView().getChildAt(position).startAnimation(animation);
l.postDelayed(new Runnable() {
public void run() {
mStringList.remove(position);
mAdapter.notifyDataSetChanged();
}
}, 100);
}
但是,动画行周围的行不会移动位置,直到调用 notifyDataSetChanged()
时它们跳转到新位置。放置元素后,ListView 似乎不会更新其布局。
虽然我已经想到了编写我自己的 ListView 实现/分支,但这似乎不应该那么困难。
谢谢!
Animation anim = AnimationUtils.loadAnimation(
GoTransitApp.this, android.R.anim.slide_out_right
);
anim.setDuration(500);
listView.getChildAt(index).startAnimation(anim );
new Handler().postDelayed(new Runnable() {
public void run() {
FavouritesManager.getInstance().remove(
FavouritesManager.getInstance().getTripManagerAtIndex(index)
);
populateList();
adapter.notifyDataSetChanged();
}
}, anim.getDuration());
对于自上而下的动画使用:
<set xmlns:android="http://schemas.android.com/apk/res/android">
<translate android:fromYDelta="20%p" android:toYDelta="-20"
android:duration="@android:integer/config_mediumAnimTime"/>
<alpha android:fromAlpha="0.0" android:toAlpha="1.0"
android:duration="@android:integer/config_mediumAnimTime" />
</set>
RecyclerView
负责添加、删除和重新排序动画!
https://i.stack.imgur.com/Q7oYK.gif
此 simple AndroidStudio project 具有 RecyclerView
。看看commits:
提交经典的 Hello World Android 应用程序提交,将 RecyclerView 添加到项目(内容不是动态)提交,添加在运行时修改 RecyclerView 内容的功能(但没有动画),最后......提交向 RecyclerView 添加动画
看看谷歌的解决方案。这里只是一种删除方法。
ListViewRemovalAnimation 项目代码和 Video 演示
它需要 Android 4.1+ (API 16)。但我们外面有 2014 年。
由于 ListViews
是高度优化的,我认为这是不可能的。您是否尝试过通过代码创建您的“ListView”(即通过从 xml 扩充您的行并将它们附加到 LinearLayout
)并为它们设置动画?
LinearLayout
,但是对于非常大的数据集,LinearLayout
的性能会变得很糟糕。 ListView
围绕视图回收进行了许多智能优化,使其能够处理大型数据集(iOS 的 UITableView 具有相同的优化)。编写我自己的视图回收器属于重新实现 ListView 的类别:(
您是否考虑过为向右扫描设置动画?您可以执行一些操作,例如在列表项的顶部绘制一个逐渐变大的白条,然后将其从列表中删除。其他牢房仍会猛拉到位,但总比没有好。
调用 listView.scheduleLayoutAnimation();在更改列表之前
我拼凑了另一种方法来做到这一点,而不必操纵列表视图。不幸的是,常规的 Android 动画似乎可以操纵行的内容,但在实际缩小视图方面无效。所以,首先考虑这个处理程序:
private Handler handler = new Handler() {
@Override
public void handleMessage(Message message) {
Bundle bundle = message.getData();
View view = listView.getChildAt(bundle.getInt("viewPosition") -
listView.getFirstVisiblePosition());
int heightToSet;
if(!bundle.containsKey("viewHeight")) {
Rect rect = new Rect();
view.getDrawingRect(rect);
heightToSet = rect.height() - 1;
} else {
heightToSet = bundle.getInt("viewHeight");
}
setViewHeight(view, heightToSet);
if(heightToSet == 1)
return;
Message nextMessage = obtainMessage();
bundle.putInt("viewHeight", (heightToSet - 5 > 0) ? heightToSet - 5 : 1);
nextMessage.setData(bundle);
sendMessage(nextMessage);
}
将此集合添加到您的列表适配器:
private Collection<Integer> disabledViews = new ArrayList<Integer>();
并添加
public boolean isEnabled(int position) {
return !disabledViews.contains(position);
}
接下来,无论您想隐藏一行,添加以下内容:
Message message = handler.obtainMessage();
Bundle bundle = new Bundle();
bundle.putInt("viewPosition", listView.getPositionForView(view));
message.setData(bundle);
handler.sendMessage(message);
disabledViews.add(listView.getPositionForView(view));
而已!您可以通过更改一次缩小高度的像素数来更改动画的速度。不是很复杂,但它有效!
将新行插入 ListView 后,我只需将 ListView 滚动到新位置。
ListView.smoothScrollToPosition(position);
我还没有尝试过,但看起来 animateLayoutChanges 应该可以满足您的需求。我在 ImageSwitcher 类中看到它,我假设它也在 ViewSwitcher 类中?
由于 Android 是开源的,因此您实际上不需要重新实现 ListView 的优化。您可以获取 ListView 的代码并尝试找到一种破解动画的方法,您还可以在 android 错误跟踪器中open a feature request(如果您决定实施它,请不要忘记 contribute a patch)。
仅供参考,ListView 源代码是 here。
这是 source code,可让您删除行并重新排序。
还提供了一个演示 APK 文件。删除行更多地遵循 Google 的 Gmail 应用程序,该应用程序在滑动顶部视图后显示底部视图。底部视图可以有一个撤消按钮或任何你想要的。
正如我在我的网站上解释过我的方法一样,我分享了链接。无论如何,这个想法是通过 getdrawingcache 创建位图。有两个位图并为较低的位图设置动画以创建移动效果
请看以下代码:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View rowView, int positon, long id)
{
listView.setDrawingCacheEnabled(true);
//listView.buildDrawingCache(true);
bitmap = listView.getDrawingCache();
myBitmap1 = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), rowView.getBottom());
myBitmap2 = Bitmap.createBitmap(bitmap, 0, rowView.getBottom(), bitmap.getWidth(), bitmap.getHeight() - myBitmap1.getHeight());
listView.setDrawingCacheEnabled(false);
imgView1.setBackgroundDrawable(new BitmapDrawable(getResources(), myBitmap1));
imgView2.setBackgroundDrawable(new BitmapDrawable(getResources(), myBitmap2));
imgView1.setVisibility(View.VISIBLE);
imgView2.setVisibility(View.VISIBLE);
RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
lp.setMargins(0, rowView.getBottom(), 0, 0);
imgView2.setLayoutParams(lp);
TranslateAnimation transanim = new TranslateAnimation(0, 0, 0, -rowView.getHeight());
transanim.setDuration(400);
transanim.setAnimationListener(new Animation.AnimationListener()
{
public void onAnimationStart(Animation animation)
{
}
public void onAnimationRepeat(Animation animation)
{
}
public void onAnimationEnd(Animation animation)
{
imgView1.setVisibility(View.GONE);
imgView2.setVisibility(View.GONE);
}
});
array.remove(positon);
adapter.notifyDataSetChanged();
imgView2.startAnimation(transanim);
}
});
用于理解图像see this
谢谢。
我做过类似的事情。一种方法是在为 listView 发出 requestLayout()
时在行 onMeasure
内随着时间的推移在动画时间内插入视图的高度。是的,直接在 listView 代码中执行可能会更好,但这是一个快速的解决方案(看起来不错!)
只是分享另一种方法:
首先将列表视图的 android:animateLayoutChanges 设置为 true:
<ListView
android:id="@+id/items_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"/>
然后我使用处理程序添加项目并延迟更新列表视图:
Handler mHandler = new Handler();
//delay in milliseconds
private int mInitialDelay = 1000;
private final int DELAY_OFFSET = 1000;
public void addItem(final Integer item) {
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
new Thread(new Runnable() {
@Override
public void run() {
mDataSet.add(item);
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
}
}).start();
}
}, mInitialDelay);
mInitialDelay += DELAY_OFFSET;
}
anim.setAnimationListener(new AnimationListener() { ... })
而不是使用 HandlerpopulateList()
是做什么用的?Handler
。其次,它在动画结束时已经使用了内置回调,从而降低了代码的复杂性。第三,您不知道Handler
和Animation
的实现将如何在每个平台上工作;您的延迟运行可能发生在动画完成之前。