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. 둘째, 애니메이션이 끝날 때 내장 콜백을 사용하여 코드를 덜 복잡하게 만듭니다. 셋째, 각 플랫폼 에서 구현 Handler및 Animation작동 방식을 모릅니다 . 애니메이션이 완료되기 전에 지연된 런너 블이 발생할 수 있습니다.
— 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 : animateLayoutChanges 를 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;
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.