如何animation添加或删除Android ListView行

在iOS中,有一个非常简单而强大的工具来animation添加和删除UITableView行, 这里是一个来自YouTubevideo的剪辑,显示了默认的animation。 请注意周围的行如何折叠到删除的行上。 这个animation可以帮助用户跟踪列表中更改的内容以及数据更改时他们正在查看的列表中的哪些内容。

由于我一直在Android上开发,我没有find相应的工具来animationTableView中的单个行。 在适配器上调用notifyDataSetChanged()会导致ListView立即使用新信息更新其内容。 我想展示一个简单的animation,当数据改变时,推入或滑出的新行,但我找不到任何logging的方式来做到这一点。 它看起来像LayoutAnimationController可能持有一个关键,让这个工作,但是当我在我的ListView上设置一个LayoutAnimationController(类似于ApiDemo的LayoutAnimation2 ),并在列表显示后从我的适配器中删除元素,元素立即消失,而不是animation。

我也尝试了下面这样的事情来移动一个单独的项目,

 @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()时,围绕animation行的行不会移动位置,直到它们跳到新的位置。 看来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()); 

对于从上到下的animation使用:

 <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负责添加,删除和重新sortinganimation!

RecyclerView在行动

这个简单的AndroidStudio项目具有RecyclerView 。 看看提交 :

  1. 提交经典的Hello World Android应用程序
  2. 提交,添加RecyclerView到项目(内容不dynamic)
  3. 提交,添加function来修改RecyclerView的内容在运行时(但没有animation)
  4. 最后…提交添加animation到RecyclerView

看看Google的解决scheme。 这只是一个删除方法。

ListViewRemovalAnimation项目代码和video演示

它需要Android 4.1+(API 16)。 但是我们有2014年以外。

由于ListViews高度优化,我认为这是不可能的。 你有没有试图通过代码创build你的“ListView”(即通过膨胀你的XML行和附加到LinearLayout ),并为它们设置animation?

你有没有考虑过把animation扫描到右边? 您可以执行一些操作,例如在列表项顶部绘制逐渐变大的白色条,然后将其从列表中移除。 其他细胞仍然会挺起来,但总比没有好。

调用listView.scheduleLayoutAnimation(); 在更改列表之前

我一起砍了另一种方式来做到这一点,而无需操纵列表视图。 不幸的是,常规的Androidanimation似乎操纵行的内容,但实际上缩小视图是无效的。 所以,首先考虑这个处理程序:

 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)); 

而已! 您可以通过更改一次缩小高度的像素数来更改animation的速度。 不是真正的复杂,但它的工作原理!

向ListView插入新行后,我只是将ListView滚动到新的位置。

 ListView.smoothScrollToPosition(position); 

我还没有尝试过,但它看起来像animateLayoutChanges应该做你想要的。 我在ImageSwitcher类中看到它,我认为它也在ViewSwitcher类中?

由于Android是开源的,你实际上不需要重新实现ListView的优化。 你可以抓住ListView的代码,并试图find一种方法来破解animation,你也可以在android bug跟踪器中打开一个function请求 (如果你决定实现它,不要忘了贡献一个补丁 )。

仅供参考,ListView源代码在这里 。

这里的源代码让你删除行并重新sorting。

演示APK文件也是可用的。 在Google的Gmail应用程序中,删除行更为顺利,在刷完顶视图后可以看到底部视图。 底部视图可以有一个撤消button或任何你想要的。

正如我已经解释了我的方法在我的网站我共享链接。总之这个想法是通过getdrawingcache创build位图。有两个位图和animation的较低的位图创build移动效果

请看下面的代码:

 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); } }); 

为了理解与图像看到这一点

谢谢。

我做了类似的事情。 一种方法是在animation时间内插入onMeasure行内视图的高度,同时为listView发出requestLayout() 。 是的,直接在listView代码中执行可能会更好,但这是一个快速解决scheme(看起来不错!)

只是分享另一种方法:

首先将列表视图的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; }