Android ListView 행의 추가 또는 제거에 애니메이션을 적용하는 방법


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

@ 알렉스 : 당신은 짓을 (아이폰 같은) 그 유튜브 비디오와 같은 애니메이션 당신이 다음 날주세요 안드로이드에 대한 데모 또는 링크가있는 경우, 나는 XML 파일에서 animateLayoutChanges을 사용하여 시도했지만, 정확히 아이폰처럼 아니라고
Jayesh

@Jayesh, 안타깝게도 더 이상 Android 개발에 참여하지 않습니다. 2012 년 무렵에 작성된이 질문에 대한 답은 테스트하지 않았습니다.
Alex 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() { ... })Handler를 사용하는 대신
올렉 Vaskevich

1
무엇 populateList()입니까?
Vasily Sochinsky

5
몇 가지 이유로 @MrAppleBR. 먼저 불필요한을 만들지 않습니다 Handler. 둘째, 애니메이션이 끝날 때 내장 콜백을 사용하여 코드를 덜 복잡하게 만듭니다. 셋째, 각 플랫폼 에서 구현 HandlerAnimation작동 방식을 모릅니다 . 애니메이션이 완료되기 전에 지연된 런너 블이 발생할 수 있습니다.
Oleg Vaskevich

7
"그러나 notifyDataSetChanged ()가 호출 될 때 애니메이션 행을 둘러싼 행은 새 위치로 이동할 때까지 위치를 이동하지 않습니다." 이 문제는 여전히 솔루션에서 지속됩니다.
Boris Rusev

5
FavouritesManager 클래스와 populateList () 메소드 란 무엇입니까 ??
Jayesh

14

1
간단한 애니메이션이 필요할 때 이것이 간단한 방법이라고 생각하지만 RecyclerView.setItemAnimator () 메서드를 사용하여 애니메이션을 사용자 정의 할 수도 있습니다.
qatz

2
마지막 단계는 내가 잃어버린 링크입니다. 안정적인 Id. 감사!
Amir Uval

이것은 API를 잘 보여주는 훌륭한 샘플 프로젝트입니다.
Mr-IDE

9

Google 솔루션을 살펴보십시오. 삭제 방법 만 있습니다.

ListViewRemovalAnimation 프로젝트 코드 및 비디오 데모

Android 4.1 이상 (API 16)이 필요합니다. 그러나 우리는 2014 년 밖에 있습니다.


2

ListViews고도로 최적화되어 있기 때문에 이것이 불가능하다고 생각합니다. 코드로 "ListView"를 만들려고 했습니까 (예 : xml에서 행을 팽창시키고 행에 추가하여 LinearLayout) 애니메이션을 적용하셨습니까?


6
애니메이션을 추가하기 위해 목록보기를 다시 구현하는 것은 의미가 없습니다.
Macarse

확실히을 사용할 수는 LinearLayout있지만 매우 큰 데이터 세트 LinearLayout의 성능은 어두워집니다. ListView뷰 재활용에 대한 많은 스마트 최적화 기능을 통해 대용량 데이터 세트를 처리 할 수 ​​있습니다 (iOS의 UITableView는 동일한 최적화 기능이 있습니다). 내 자신의보기 재활용
기를

나는 그것이 의미가 없다는 것을 알고 있습니다. 그러나 몇 줄만 작업하면 멋진 인 / 아웃 애니메이션을 사용하는 것이 좋습니다.
whlk

2

오른쪽으로 쓸어 넘기는 애니메이션을 고려 했습니까? 목록 항목 상단에 점진적으로 더 큰 흰색 막대를 그린 다음 목록에서 제거하는 것과 같은 작업을 수행 할 수 있습니다. 다른 세포는 여전히 제자리에 고정되지만 아무것도 아닌 것보다 낫습니다.



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 2016

1

Android는 오픈 소스이므로 실제로 ListView의 최적화를 다시 구현할 필요가 없습니다. ListView의 코드를 가져 와서 애니메이션을 해킹하는 방법을 찾으려고 안드로이드 버그 추적기에서 기능 요청 수도 있습니다 (구현하기로 결정한 경우 패치제공하는 것을 잊지 마십시오 ).

참고로, ListView 소스 코드는 다음과 같습니다 .


1
이것은 그러한 변경이 구현되는 방식이 아닙니다. 무엇보다 먼저 AOSP 프로젝트를 구축해야합니다. 이는 목록보기에 애니메이션을 추가하는 데 매우 어려운 방법입니다. 다양한 오픈 소스 라이브러리의 구현을 살펴보십시오.
OrhanC1

1

다음은 행을 삭제하고 재정렬 할 수 있는 소스 코드 입니다.

데모 APK 파일도 제공됩니다. 행 삭제는 상위 뷰를 스 와이프 한 후 하단 뷰를 표시하는 Google Gmail 앱의 라인을 따라 더 많이 수행됩니다. 하단보기에는 실행 취소 버튼 또는 원하는 것이 있습니다.


1

내 사이트에서 내 접근 방식을 설명했듯이 링크를 공유했습니다. 어쨌든 아이디어는 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);
        }
    });

이미지를 이해 하려면 이것을 참조하십시오

감사.


0

나는 이것과 비슷한 것을했다. 한 가지 방법은 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.