Как анимировать добавление или удаление строк Android ListView

в iOS есть очень простое и мощное средство для анимации добавления и удаления строк UITableView,вот клип из видео youtube отображение анимации по умолчанию. Обратите внимание, как окружающие строки сворачиваются в удаленную строку. Эта анимация помогает пользователям отслеживать, что изменилось в списке и где в списке они смотрели, когда данные изменены.

Так как я разрабатывал на Android, я не нашел эквивалентного средства для анимации отдельных строк TableView. Зову notifyDataSetChanged() на моем адаптере заставляет ListView немедленно обновлять свое содержимое новой информацией. Я хотел бы показать простую анимацию новой строки, нажимающей или выскальзывающей при изменении данных, но я не могу найти документированного способа сделать это. Похоже на LayoutAnimationController может содержать ключ к тому, чтобы это работало, но когда я устанавливаю LayoutAnimationController в моем ListView (аналогично ApiDemo это!--5-->) и удалите элементы из моего адаптера после отображения списка, элементы немедленно исчезнут вместо того, чтобы анимироваться.

Я также пробовал следующие вещи, чтобы оживить отдельный элемент при его удалении:

@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 пришло мне в голову, что это похоже на то, что не должно быть так сложно.

спасибо!

14 ответов


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>


взгляните на решение Google. Вот только метод удаления.

ListViewRemovalAnimation кода видео демонстрация

ему нужен Android 4.1+ (API 16). Но у нас есть 2014 снаружи.


С ListViews хорошо оптимизированы, я думаю, это не возможно, чтобы accieve. Вы пытались создать свой "ListView" с помощью кода (т. е. путем раздувания строк из xml и добавления их в LinearLayout) и анимировать их?


вы рассматривали возможность анимации развертки вправо? Вы можете сделать что-то вроде рисования постепенно увеличивающейся белой полосы в верхней части элемента списка, а затем удалить ее из списка. Остальные клетки все равно встанут на свои места, но это лучше, чем ничего.


звоните элемент управления 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 bug tracker (и если вы решили реализовать его, не забудьте внести исправления).

FYI, исходный код ListView -здесь.


здесь исходный код чтобы удалить строки и изменить их порядок.

демо-файл APK также доступен. Удаление строк выполняется больше по линии приложения Gmail Google, которое показывает вид снизу после прокрутки сверху. Вид снизу может иметь кнопку отмены или все, что вы хотите.


Как я объяснил свой подход на моем сайте, я поделился ссылкой.В любом случае идея заключается в создании растровых изображений по 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);
        }
    });

для понимания с изображениями посмотреть этот

спасибо.


Я сделал что-то подобное. Один из подходов заключается в интерполяции по времени анимации высоты представления с течением времени внутри строк onMeasure при оформлении requestLayout() для listView. Да, это может быть лучше сделать внутри кода listView напрямую, но это было быстрое решение (это выглядело хорошо!)


просто обмен другим подходом:

Сначала установите представление списка android: animateLayoutChanges to правда:

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

тогда я использую проводник чтобы добавить элементы и обновить listview с задержкой:

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