it-swarm.com.ru

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

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

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

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

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

Спасибо!

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

Добавьте эту коллекцию в свой адаптер List:

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 - здесь .

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-файл. Удаление строк выполняется больше по аналогии с приложением Gmail от Google, которое показывает вид снизу после прокрутки вида сверху. Вид снизу может иметь кнопку Отменить или все, что вы хотите.

1
AndroidDev

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

0
Dori

Просто делюсь другим подходом:

Сначала установите представление списка в Android: animateLayoutChanges to 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;
}
0
Mina Samy