Day 23 : ListView Animation

Day 23 : ListView Animation Cover Image

สวัสดีครับ บทความนี้เป็นบทความที่ 23 แล้วนะครับ ที่ผมจะมาเขียน ในซีรีย์ Learn 30 Android Libraries in 30 days

สำหรับบทความทั้งหมด อ่านได้จากด้านล่างครับ

สำหรับวันนี้ขอนำเสนอเรื่อง ListViewAnimations ตัวนี้เป็น Library ที่เอาไว้เพิ่มลูกเล่น animation ให้กับ ListView เวลาที่เลือน scroll ครับ ไม่ใช่เฉพาะ ListView เท่านั้น สามารถใช้กับ GridView ก็ได้ animation ก็มีด้วยกันหลายอย่างเช่น

  • Alpha ค่อยๆ สว่าง
  • SwingRightIn - ไอเท็มจะวิ่งมาจากทางขวาของหน้าจอ
  • SwingLeftIn - ไอเท้มจะวิ่งมาจากด้านซ้ายของหน้าจอ
  • SwingBottomIn - ไอเท็มจะวิ่งขึ้นมาจากด้านล่าง
  • ScaleIn

แล้วนอกจาก Animation แล้ว ยังมี Swipe-To-Dismiss ซึ่งเป็นการลบ item เมื่อทำการ swipe คล้ายๆกับ Library Day 17 : SwipeListView

Installation

ขั้นตอนการติดตั้ง เปิดไฟล์ build.gradle ขึ้นมา แล้วเพิ่ม dependencies ลงไปดังนี้

dependencies {
    compile 'com.nhaarman.listviewanimations:library:2.6.0'
}

กด Sync Gradle เป็นอันเรียบร้อย

Usage

มาถึงขั้นตอนวิธีการใช้งานตัว ListViewAnimations กันเลยครับ จะมีคลาส Adapter มาให้เราเลือกใช้งานดังนี้ครับ

  • AlphaInAnimationAdapter
  • ScaleInAnimationAdapter
  • SwingBottomInAnimationAdapter
  • SwingLeftInAnimationAdapter
  • SwingRightInAnimationAdapte

เอฟเฟคก็จะแตกต่างกันไป ตามที่เกริ่นไว้นะครับ

ส่วนการ implement Adapter เหล่านี้ ทำยังไง?

[1] โดยปกติแล้ว เวลาเราสร้าง ListView หรือว่า GridView เราจะมี Adapter ของเราด้วยใช่มั้ยครับ เช่น ArrayAdapter หรือ CustomAdapter ก็แล้วแต่ จากนั้น เราจะใช้ Adapter ของเราเนี่ยแหละครับ เป็น argument ส่งไปให้กับ AnimationAdapter() ของ ListViewAnimations แต่ละอัน เช่น SwingBottomInAnimationAdapter

SwingBottomInAnimationAdapter swingAdapter = new SwingBottomInAnimationAdapter(myAdapter);

[2] เซต ListView ให้กับ SwingBottomInAnimationAdapter เพื่อบอกให้รู้ว่าจะทำการ animation ListView ตัวนี้นะ

ListView listView = (ListView) findViewById(R.id.list_view);
swingAdapter.setAbsListView(listView);

[3] ให้ ListView ทำการ setAdapter() โดยใช้ SwingBottomInAnimationAdapter แทน Adapter ของเราเอง

listView.setAdapter(swingAdapter);

หลักการก็มีคร่าวๆแค่นี้ครับ สำหรับ Animation อื่นๆ เช่นพวก ScaleIn, SwingRightIn ก็แค่เปลี่ยนคลาส ส่วนวิธีการและ argument ต่างๆ เหมือนกันทุกอย่างครับ มาลองสร้างโปรเจ็คดูเลยดีกว่า

Create Project

สำหรับโปรเจ็คนี้ จะใช้แค่ไฟล์ ListViewAnimationActivity.java และไฟล์เลเอาท์ชื่อ activity_listview_animation.xml 2 ไฟล์เท่านั้นครับ สำหรับไฟล์เลเอาท์ แค่มี ListView เท่านั้นครับ

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical">

    <ListView
        android:id="@+id/list_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    </ListView>

</LinearLayout>

ส่วนไฟล์จาวา ก็มีดังนี้

package com.devahoy.learn30androidlibraries.day23;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.devahoy.learn30androidlibraries.R;

import java.util.ArrayList;

public class ListViewAnimationsActivity extends ActionBarActivity {

    private ArrayList<String> mDataset = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.day23_activity_listview_animation);

        ListView listView = (ListView) findViewById(R.id.list_view);

        for (int i = 1; i < 100; i++) {
            mDataset.add("Lorem ipsum quis leo pharetra item #" + i);
        }

        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mDataset);

        listView.setAdapter(adapter);
    }
}

จากโค๊ดด้านบน โดยปกติเราจะสร้าง ListView โดยใช้ ArrayAdapter แบบธรรมดา ได้ด้วยโค๊ดแค่นี้ใช่มั้ยครับ ลองทดสอบรันดู จะเห็นว่ามี ListView แต่ไม่มี animation อะไรเลยทั้งสิ้น

หากว่าต้องการเพิ่ม Animation ก็แค่เพิ่มนี้ลงไป

SwingBottomInAnimationAdapter swingBottomInAdapter = new SwingBottomInAnimationAdapter(adapter);
swingBottomInAdapter.setAbsListView(listView);

adapter ก็คือ ArrayAdapter ของเรา และ setAbsListView(listView) ก็คือ ListView ของเราครับ

จากนั้นสุดท้าย ก็เปลี่ยนจาก

listView.setAdapter(adapter);

เป็น

listView.setAdapter(swingBottomInAdapter);

เท่านี้ก็เรียบร้อย

package com.devahoy.learn30androidlibraries.day23;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.devahoy.learn30androidlibraries.R;
import com.nhaarman.listviewanimations.swinginadapters.prepared.SwingBottomInAnimationAdapter;

import java.util.ArrayList;

public class ListViewAnimationsActivity extends ActionBarActivity {

    private ArrayList<String> mDataset = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.day23_activity_listview_animation);

        ListView listView = (ListView) findViewById(R.id.list_view);

        for (int i = 1; i < 100; i++) {
            mDataset.add("Lorem ipsum quis leo pharetra item #" + i);
        }

        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mDataset);

        SwingBottomInAnimationAdapter swingBottomInAdapter =
                new SwingBottomInAnimationAdapter(adapter);
        swingBottomInAdapter.setAbsListView(listView);

        listView.setAdapter(swingBottomInAdapter);
    }
}

ทดลองรันดูผลลัพธ์กันเองนะครับ ผมไม่ได้บันทึกแบบเคลื่อนไหวไว้ (ทำไม่เป็น)

ส่วนหากต้องการให้มันเป็น Animation อื่นๆ ก็ทำได้ลักษณะเดียวกัน เช่น

ScaleInAnimationAdapter

ScaleInAnimationAdapter scaleInAdapter = new ScaleInAnimationAdapter(adapter);
scaleInAdapter.setAbsListView(listView);
listView.setAdapter(scaleInAdapter);

SwingLeftInAnimationAdapter

SwingLeftInAnimationAdapter swingLeftInAdatper = new SwingLeftInAnimationAdapter(adapter);
swingLeftInAdatper.setAbsListView(listView);
listView.setAdapter(swingLeftInAdatper);

Swipe to Dismiss

ListViewAnimations มันยังสามารถทำ Swipe to Dismiss ได้ด้วยเช่นกันครับ ตัวอย่างนี้ผมจะให้มันลบข้อมูลไอเท็มในลิสต์ออกไปเมื่อเราทำการ swipe ครับ การใช้งานก็ไม่ยากเลย เพียงแค่ใช้ swingLeftInAdatper ดังนี้ครับ

SwipeDismissAdapter swipeDismissAdapter = new SwipeDismissAdapter(adapter, new OnDismissCallback() {
    @Override
    public void onDismiss(AbsListView listView, int[] reverseSortedPositions) {
        for (int position : reverseSortedPositions) {
            adapter.remove(mDataset.get(position));
        }
    }
});

โดยสร้าง SwipeDismissAdapter จาก adapter ของเรา และอีก parameter คือ OnDismissCallback() และ override เมธอด onDismiss() เมื่อมีการ swipe จะให้ทำการลบข้อมูลใน adapter ออกครับ

่ต่อมา ก็ setAbsListView() เหมือนๆกับ AnimationAdapter

swipeDismissAdapter.setAbsListView(listView);

สุดท้าย ก็ให้ ListView ของเรา setAdatper() ด้วยไอ้เจ้า SwipeDismissAdapter ที่สร้างมาใหม่

listView.setAdapter(swipeDismissAdapter);

ทดสอบ รัน แล้วลอง swipe ไอเท็มดูครับ จะเห็นว่าข้อมูลจะหายออกไปจากลิสท์แล้ว สุดท้าย ไฟล์ทั้งหมด มีแค่นี้แหละ

package com.devahoy.learn30androidlibraries.day23;

import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.widget.AbsListView;
import android.widget.ArrayAdapter;
import android.widget.ListView;

import com.devahoy.learn30androidlibraries.R;
import com.nhaarman.listviewanimations.itemmanipulation.OnDismissCallback;
import com.nhaarman.listviewanimations.itemmanipulation.swipedismiss.SwipeDismissAdapter;
import com.nhaarman.listviewanimations.swinginadapters.prepared.ScaleInAnimationAdapter;
import com.nhaarman.listviewanimations.swinginadapters.prepared.SwingBottomInAnimationAdapter;
import com.nhaarman.listviewanimations.swinginadapters.prepared.SwingLeftInAnimationAdapter;

import java.util.ArrayList;

public class ListViewAnimationsActivity extends ActionBarActivity {

    private ArrayList<String> mDataset = new ArrayList<String>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.day23_activity_listview_animation);

        ListView listView = (ListView) findViewById(R.id.list_view);

        for (int i = 1; i < 100; i++) {
            mDataset.add("Lorem ipsum quis leo pharetra item #" + i);
        }

        final ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,
                android.R.layout.simple_list_item_1, mDataset);

        SwingBottomInAnimationAdapter swingBottomInAdapter =
                new SwingBottomInAnimationAdapter(adapter);
        swingBottomInAdapter.setAbsListView(listView);

        ScaleInAnimationAdapter scaleInAdapter = new ScaleInAnimationAdapter(adapter);
        scaleInAdapter.setAbsListView(listView);

        SwingLeftInAnimationAdapter swingLeftInAdapter = new SwingLeftInAnimationAdapter(adapter);
        swingLeftInAdapter.setAbsListView(listView);

        SwipeDismissAdapter swipeDismissAdapter = new SwipeDismissAdapter(adapter, new OnDismissCallback() {
            @Override
            public void onDismiss(AbsListView listView, int[] reverseSortedPositions) {
                for (int position : reverseSortedPositions) {
                    adapter.remove(mDataset.get(position));
                }
            }
        });
        swipeDismissAdapter.setAbsListView(listView);

        listView.setAdapter(swipeDismissAdapter);
    }
}

สรุป

บทความนี้ทำเพียงแค่ ListView เท่านั้นครับ จริงๆแล้วถ้าเอาไปทำกับ GridView หรือว่า ListView ที่เป็นแบบ Custom จะสวยกว่านี้อีกครับ แต่เนื่องจากโฟกัสที่ตัว ListViewAnimations ฉะนั้นก็เลยทำแค่นี้ มีประโยชน์มากครับ ทำให้แอพพลิเคชันของเรามีชีวิตชีวาขึ้น เวลาเรา scroll เลื่อนลงมาอ่านข้อมูล ถ้ามันมี animation มันก็จะดูน่าสนใจขึ้น ดีกว่าแข็งๆทื่อๆ ใช่มั้ยครับ?

จริงๆแล้ว ListViewAnimations มันยังมีอะไรหลายๆอย่างอีกเยอะครับ ที่ไม่ได้พูดถึงในบทความนี้ ก็ลองไปอ่านเพิ่มเติมกันดูนะครับ

Happy Coding :D

Reference

Chai Chai Phonbopit : Software Engineer @Nextzy • ผู้ชายธรรมดาๆ ที่ชื่นชอบ Android, JavaScript (Node.js) และ Open Source มีงานอดิเรกเป็น Acoustic Guitar และ Football

บทความล่าสุด