Androidリストビュー行の追加または削除をアニメーション化する方法


212

iOSには、UITableView行の追加と削除をアニメーション化するための非常に簡単で強力な機能があります。これは、デフォルトのアニメーションを示すYouTubeビデオのクリップです。周囲の行が削除された行にどのように折りたたまれているかに注意してください。このアニメーションは、ユーザーがリストで何が変更されたか、データが変更されたときにリストのどこを見ているかを追跡するのに役立ちます。

私はAndroidで開発してきたので、TableViewの個々の行をアニメーション化する同等の機能を見つけられませんでしたnotifyDataSetChanged()アダプタを呼び出すと、ListViewはそのコンテンツを新しい情報ですぐに更新します。データが変更されたときに新しい行が押し込まれるか、またはスライドする簡単なアニメーションを表示したいのですが、これを行うための文書化された方法が見つかりません。LayoutAnimationControllerがこれを機能させるためのキーを保持しているように見えますが、ListViewにLayoutAnimationControllerを設定し(ApiDemoの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の独自の実装/フォークを作成することは私の心を超えましたが、これはそれほど難しいことではないようです。

ありがとう!


誰かがこれに対する答えを見つけましたか?pls shareee
AndroidGecko

@Alex:そのyoutubeビデオ(iphoneなど)のようなアニメーションを実行しましたか、androidのデモまたはリンクがある場合は教えてください、xmlファイルでanimateLayoutChangesを使用してみましたが、それはiphoneとはまったく
異なります

@Jayesh、残念ながら私はもはやAndroid開発に取り組んでいません。私は2012年の周りの後に書かれたこの質問への回答のいずれかをテストしていません
アレックスPretzlav

回答:


124
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>

70
anim.setAnimationListener(new AnimationListener() { ... })ハンドラーを使用するよりも使用することをお
勧めします

1
何のpopulateList()ため?
Vasily Sochinsky 2013年

5
@MrAppleBRにはいくつかの理由があります。まず、不要なを作成する必要はありませんHandler。次に、アニメーションの終了時に組み込みのコールバックを既に使用しているため、コードの複雑さが軽減されます。第三に、あなたはどのように実装を知らないHandlerAnimation、各プラットフォーム上で動作します。アニメーションが終了する前に遅延ランナブルが発生する可能性があります。
Oleg Vaskevich 2013年

7
「ただし、アニメーション化された行を囲む行は、notifyDataSetChanged()が呼び出されたときに新しい位置にジャンプするまで、位置を移動しません。」この問題は依然としてソリューションで解決しません。
Boris Rusev 2014

5
FavouritesManagerクラスとPopulateList()メソッドとは何ですか?
Jayesh 2014年

14

1
シンプルなアニメーションが必要な場合はこれがシンプルな方法だと思いますが、RecyclerView.setItemAnimator()メソッドを使用してアニメーションをカスタマイズすることもできます。
qatz 2016年

2
最後のステップは、私が持っていたミッシングリンクです。安定したIDです。ありがとう!
Amir Uval

これは、APIを十分に実証する優れたサンプルプロジェクトです。
Mr-IDE


2

ListViews高度に最適化されているので、これを達成することは不可能だと思います。コードで(つまり、xmlから行をインフレートしてに追加することによって) "ListView"を作成してLinearLayoutアニメーション化しようとしましたか?


6
アニメーションを追加するためだけにリストビューを再実装することは意味がありません。
Macarse

私は確かに単にを使用することもできますがLinearLayout、非常に大きなデータセットではLinearLayoutパフォーマンスがひどくなります。 ListView大規模なデータセットを処理できるようにするビューのリサイクルに関する多くのスマートな最適化があります(iOSのUITableViewにも同じ最適化があります)。私自身のビューリサイクラーを書くことは、リストビュー:(再実装に該当
アレックスPretzlav

私はそれが意味をなさないことを知っています-しかし、あなたがいくつかの行だけで作業する場合、素敵なイン/アウトアニメーションを持つ利点は、試してみる価値があります。
2010年

2

スイープを右にアニメートすることを検討しましたか?リストアイテムの上部に次第に大きな白いバーを描画し、それをリストから削除するようなこともできます。他のセルはまだ所定の位置にジャークしますが、何もないよりはましです。


2

listView.scheduleLayoutAnimation();を呼び出します。リストを変更する前


2

リストビューを操作せずに別の方法でハッキングしました。残念ながら、通常の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));

それでおしまい!一度に高さを縮小するピクセル数を変更することで、アニメーションの速度を変更できます。実際には洗練されていませんが、動作します!


2

ListViewに新しい行を挿入した後、ListViewを新しい位置にスクロールするだけです。

ListView.smoothScrollToPosition(position);

1

まだ試していませんが、animateLayoutChangesで目的の処理を実行できるようです。ImageSwitcherクラスに表示されますが、ViewSwitcherクラスにもあると思いますか?


ちょっとありがとう、私はそれを調べます。残念ながら、animateLayoutChangesはAPIレベル11(別名Honeycomb)の時点で新しくなっているようです。別名:(これはすべての電話では使用できません):(
Alex Pretzlav

1

Androidはオープンソースであるため、実際にListViewの最適化を再実装する必要はありません。ListViewのコードを取得し、アニメーションをハッキングする方法を見つけようとすることができます。また、Androidバグトラッカーで機能リクエスト開くこともできます(実装することにした場合は、パッチの提供を忘れないでください)。

ちなみに、ListViewのソースコードはこちらです。


1
これは、そのような変更を実装する方法ではありません。何よりもまず、AOSPプロジェクトを作成する必要があります。これは、リストビューにアニメーションを追加するための非常に手間のかかるアプローチです。さまざまなオープンソースライブラリの実装をご覧ください。
OrhanC1 2014年

1

次に、行を削除してそれらを並べ替えるソースコードを示します。

デモAPKファイルも利用できます。行の削除は、GoogleのGmailアプリの線に沿って行われ、上面ビューをスワイプすると底面ビューが表示されます。下のビューには、[元に戻す]ボタンなど、必要なものを含めることができます。


1

私のサイトで私のアプローチを説明したように、リンクを共有しました。常に、アイデアはgetdrawingcacheによってビットマップを作成します.2つのビットマップを持ち、下のビットマップをアニメーション化して移動効果を作成します

次のコードをご覧ください。

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

画像で理解するにはこちらをご覧ください

ありがとう。


0

私はこれと同じようなことをしました。1つのアプローチは、listViewのonMeasure発行中requestLayout()に、行内のアニメーションの時間の経過に伴うビューの高さの時間を補間することです。はい、それはlistViewコード内で直接行う方が良いかもしれませんが、それは迅速な解決策でした(見栄えが良かったです!)


0

別のアプローチを共有するだけです:

まず、リストビューのandroid:animateLayoutChangestrueに設定ます

<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;
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.