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


в 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 206

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 высоко оптимизированы я думаю, что это невозможно принять. Вы пытались создать свой "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 (и если вы решили реализовать его, не забудьте внести исправления).

кстати, исходный код элемента управления 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 до правда:

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