วิธีการเพิ่มหรือลบแถวรายการ Android สำหรับดูภาพเคลื่อนไหว


212

ใน iOS มีสิ่งอำนวยความสะดวกที่ง่ายและมีประสิทธิภาพในการเคลื่อนไหวเพิ่มและลบแถว UITableView นี่คือคลิปจากวิดีโอ youtube ที่แสดงภาพเคลื่อนไหวเริ่มต้น สังเกตว่าแถวที่ล้อมรอบยุบลงในแถวที่ถูกลบอย่างไร แอนิเมชันนี้ช่วยให้ผู้ใช้ติดตามสิ่งที่เปลี่ยนแปลงในรายการและตำแหน่งที่อยู่ในรายการที่พวกเขาดูเมื่อข้อมูลมีการเปลี่ยนแปลง

ตั้งแต่ผมได้รับการพัฒนาบน Android ฉันได้พบว่าไม่มีสิ่งอำนวยความสะดวกเทียบเท่ากับการเคลื่อนไหวแต่ละแถวในtableView การเรียกใช้ตัวปรับnotifyDataSetChanged()ต่อของฉันทำให้ ListView อัปเดตเนื้อหาด้วยข้อมูลใหม่ทันที ฉันต้องการแสดงภาพเคลื่อนไหวอย่างง่ายของแถวใหม่ที่ผลักเข้าหรือเลื่อนออกเมื่อข้อมูลมีการเปลี่ยนแปลง แต่ฉันไม่สามารถหาวิธีการทำเอกสารได้ ดูเหมือนว่าLayoutAnimationControllerอาจเก็บกุญแจไว้เพื่อให้มันใช้งานได้ แต่เมื่อฉันตั้งค่า LayoutAnimationController ใน ListView ของฉัน (คล้ายกับLayoutAnimation ApiDemo ของ 2 ) และลบองค์ประกอบออกจากอะแดปเตอร์ของฉันหลังจากที่รายการแสดงองค์ประกอบหายไปทันที .

ฉันได้ลองทำสิ่งต่อไปนี้เพื่อสร้างรายการแต่ละรายการเมื่อมันถูกลบ:

@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 ของฉันได้ข้ามความคิดของฉันดูเหมือนว่าสิ่งที่ไม่ควรยาก

ขอบคุณ!


มีคนหาคำตอบให้กับเรื่องนี้? กรุณา shareee
AndroidGecko

@Alex: คุณทำแอนิเมชั่นแบบนั้นเช่นวิดีโอ youtube (เช่น iphone) ถ้าคุณมีตัวอย่างหรือลิงค์สำหรับ android โปรดให้ฉันฉันลองใช้ animateLayoutChanges ในไฟล์ xml แต่มันไม่เหมือนกับ iphone
Jayesh

@ Jayesh โชคไม่ดีที่ฉันไม่ได้ทำงานกับการพัฒนา Android ฉันไม่ได้ทดสอบใด ๆ ของคำตอบสำหรับคำถามนี้ที่ถูกเขียนขึ้นหลังจากรอบปี 2012
อเล็กซ์ 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
Oleg Vaskevich

1
สิ่งที่เป็นpopulateList()อยู่หรือ?
Vasily Sochinsky

5
@MrAppleBR ด้วยเหตุผลหลายประการ Handlerครั้งแรกที่คุณไม่ได้สร้างที่ไม่จำเป็น ประการที่สองมันทำให้รหัสมีความซับซ้อนน้อยลงโดยใช้การโทรกลับในตัวเมื่อเคลื่อนไหวเสร็จสิ้นแล้ว ประการที่สามคุณไม่รู้วิธีการใช้งานHandlerและAnimationจะทำงานบนแต่ละแพลตฟอร์มอย่างไร อาจเป็นไปได้ที่ runnable ที่ล่าช้าของคุณเกิดขึ้นก่อนที่ภาพเคลื่อนไหวจะเสร็จสิ้น
Oleg Vaskevich

7
"อย่างไรก็ตามแถวที่ล้อมรอบแถวภาพเคลื่อนไหวจะไม่ย้ายตำแหน่งจนกว่าจะข้ามไปยังตำแหน่งใหม่เมื่อเรียกว่า ปัญหานี้ยังคงมีอยู่ในการแก้ปัญหาของคุณ
Boris Rusev

5
คลาส FavouritesManager และวิธี populateList () คืออะไร?
Jayesh

14

1
ฉันคิดว่านี่เป็นวิธีที่ง่ายเมื่อคุณต้องการแอนิเมชั่นที่เรียบง่าย แต่คุณยังสามารถกำหนดแอนิเมชั่นเองได้โดยใช้เมธอด RecyclerView.setItemAnimator ()
qatz

2
ขั้นตอนสุดท้ายคือลิงค์ที่ขาดหายไป รหัสเสถียรของ ขอบคุณ!
Amir Uval

นี่เป็นโครงการตัวอย่างที่ยอดเยี่ยมที่แสดงให้เห็นถึง API ได้เป็นอย่างดี
Mr-IDE


2

เนื่องจากListViewsมีการปรับให้เหมาะสมอย่างมากฉันคิดว่านี่เป็นไปไม่ได้ที่จะได้รับ คุณได้ลองสร้าง "ListView" ของคุณด้วยรหัส (เช่นขยายแถวของคุณจาก xml และต่อท้าย a LinearLayout) และทำให้เคลื่อนไหวหรือไม่


6
ไม่เหมาะสมที่จะปรับใช้ listview อีกครั้งเพื่อเพิ่มภาพเคลื่อนไหว
Macarse

ฉันสามารถใช้ a ได้อย่างแน่นอนLinearLayoutแต่ด้วยLinearLayoutประสิทธิภาพของชุดข้อมูลขนาดใหญ่จะกลายเป็นสุดซึ้ง ListViewมีการเพิ่มประสิทธิภาพสมาร์ทมากมายรอบการรีไซเคิลมุมมองที่อนุญาตให้จัดการชุดข้อมูลขนาดใหญ่ (UITableView ของ iOS มีการปรับให้เหมาะสมเหมือนกัน) เขียนมุมมองของฉันรีไซเคิลอยู่ภายใต้หมวดหมู่ของการปรับใช้ ListView :(
อเล็กซ์ Pretzlav

ฉันรู้ว่ามันไม่สมเหตุสมผล - แต่ถ้าคุณทำงานกับบางแถวเพียงไม่กี่ผลประโยชน์ของการมีภาพเคลื่อนไหวเข้า / ออกที่ดีอาจคุ้มค่ากับการลอง
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

ฉันไม่ได้ลองเลย แต่ดูเหมือนว่าภาพเคลื่อนไหวการเปลี่ยนเค้าโครงควรทำในสิ่งที่คุณกำลังมองหา ฉันเห็นมันในคลาส ImageSwitcher ฉันคิดว่ามันอยู่ในคลาส ViewSwitcher ด้วยหรือไม่


เฮ้ขอบคุณฉันจะดูเป็นอย่างนั้น น่าเสียดายที่ดูเหมือนว่าanimateLayoutChangesนั้นใหม่เป็นของ API ระดับ 11 หรือที่เรียกว่า Honeycomb หรือไม่สามารถใช้กับโทรศัพท์เครื่องใดก็ได้ :(
Alex Pretzlav

1

เนื่องจาก Android เป็นโอเพ่นซอร์สคุณไม่จำเป็นต้องปรับใช้การเพิ่มประสิทธิภาพของ ListView อีกครั้ง คุณสามารถคว้ารหัสของ ListView และพยายามหาวิธีแฮ็กในแอนิเมชั่นคุณยังสามารถเปิดคำขอคุณลักษณะในตัวติดตามบั๊กของ android (และถ้าคุณตัดสินใจที่จะใช้มันอย่าลืมมีส่วนร่วมในการแก้ไข )

FYI ซอร์สโค้ด ListView คือที่นี่


1
นี่ไม่ใช่วิธีการเปลี่ยนแปลงที่ควรนำมาใช้ ก่อนอื่นคุณควรมีอาคารโครงการ AOSP ซึ่งเป็นวิธีการที่ค่อนข้างหนักในการเพิ่มแอนิเมชั่นไปยังมุมมองรายการ โปรดดูการใช้งานในไลบรารีโอเพ่นซอร์สต่างๆ
OrhanC1

1

นี่คือซอร์สโค้ดจะให้คุณลบแถวและจัดลำดับใหม่

นอกจากนี้ยังมีไฟล์ APK ตัวอย่าง การลบแถวสามารถทำได้มากขึ้นตามแนวของแอพ Gmail ของ Google ที่แสดงมุมมองด้านล่างหลังจากปัดมุมมองด้านบน มุมมองด้านล่างสามารถมีปุ่มเลิกทำหรืออะไรก็ได้ที่คุณต้องการ


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

ฉันทำสิ่งที่คล้ายกับสิ่งนี้ วิธีหนึ่งคือการสอดแทรกช่วงเวลาของภาพเคลื่อนไหวความสูงของมุมมองเมื่อเวลาผ่านไปในแถวต่างๆonMeasureในขณะที่ออกrequestLayout()รายการ listView ใช่มันอาจจะดีกว่าที่จะทำในรหัส listView โดยตรง แต่มันเป็นวิธีแก้ปัญหาอย่างรวดเร็ว (ที่ดูดี!)


0

เพียงแบ่งปันวิธีอื่น:

ชุดแรกมุมมองรายการของหุ่นยนต์: 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;
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.