web-dev-qa-db-ja.com

Android ListView行の追加または削除をアニメーション化する方法

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の独自の実装/フォークを書くことは私の頭をよぎりましたが、これはそれほど難しいことではないように思えます。

ありがとう!

208
Alex Pretzlav
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>
124
OAK
14
Eric

Googleのソリューションをご覧ください。以下は削除方法のみです。

ListViewRemovalAnimation プロジェクトコードおよび ビデオ デモンストレーション

Android 4.1+(API 16)が必要です。しかし、2014年は外にあります。

9
dimetil

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

2
karabara

スイープを右にアニメートすることを検討しましたか?リスト項目の上部に次第に大きくなる白いバーを描画してからリストから削除するようなことをすることができます。他のセルはまだ適切な位置に動きますが、何もないよりはましです。

2
Sam Dufel

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

ListView.smoothScrollToPosition(position);
2
Rafael

リストビューを操作することなく、別の方法でハッキングしました。残念ながら、通常の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
jkschneider

ListViewsは高度に最適化されているため、これを実現することは不可能だと思います。コードで「ListView」を作成(つまり、xmlから行を膨らませてLinearLayoutに追加する)して、アニメーション化しようとしましたか?

2
whlk

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

参考までに、ListViewのソースコードは here です。

1
Lie Ryan

私はそれを試していませんが、animateLayoutChangesがあなたが探していることをするはずです。 ImageSwitcherクラスに表示されますが、ViewSwitcherクラスにもあると思いますか?

1
Genia S.

私のサイトで自分のアプローチを説明したように、リンクを共有しました。とにかく、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);
        }
    });

画像を理解するために こちらを参照

ありがとう。

1
Ram

ソースコード を使用して、行を削除して並べ替えることができます。

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

1
AndroidDev

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

0
Dori

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

最初にリストビューのAndroid:animateLayoutChangestrueに設定します。

<ListView
        Android:id="@+id/items_list"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent"
        Android:animateLayoutChanges="true"/>

次に、handlerを使用して、アイテムを追加し、遅延してリストビューを更新します。

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;
}
0
Mina Samy