[ANDROID] ซ่อน/แสดง Floating Action Buttons ตอน Scroll ทำยังไงกันนะ

         Floating action buttons หรือ FAB เป็นปุ่มที่ทาง Google ปล่อยมาพร้อมกับ Material Design หากยังนึกไม่ออก ลองไปเปิด Application ของ Google อย่างเช่น Gmail หรือ Google Map เจ้า FAB ก็คือปุ่มกลมๆ ที่ลอยหน้าลอยตาไปมาในหน้าจอของเรานั่นเอง
         ส่วนวิธีการใช้งานขอแนะนำให้ไปอ่านบล๊อกของพี่เนย Codelab สอนใช้ Android Design Support Library ได้เลยครับ


แล้ววันนี้เราจะทำอะไรกัน ?

         จากที่ลองได้ใช้ FAB ก็พบว่าในบางครั้งมันเกะกะ เนื่องด้วยความที่มันลอยอยู่เหนือทุก Component  ทำให้เจ้า FAB ก็แอบไปบัง Content ของเรา


แล้วจะแก้ปัญหายังไง ?

         วิธีการแก้ปัญหาจากที่เห็นใน Application ดังๆ ก็คือ เมื่อมีการ Scroll ลงล่างก็จะซ่อน FAB และเมื่อ Scroll กลับขึ้นข้างบนก็จะแสดง FAB อีกครั้ง ดังรูป

https://guides.codepath.com/android/Floating-Action-Buttons#using-coordinatorlayout

ลงมือกันเลย

         การทำงานแบบที่กล่าวมาข้างต้น จะต้องร่วมกับ CoordinatorLayout (การใช้งานไม่ขอกล่าวถึง ให้ไปดูบทความพี่เนยที่บอกด้านบนนะครับ)
         วิธีการจริงๆ นั้นง่ายมากๆ คือ ทำการ implement CoordinatorLayout.Behavior สำหรับ FAB นั่นเอง ซึ่งโดยปกติแล้ว Default Behavior ของ FAB จะเป็นการขยับพื้นที่ เมื่อมี SnackBar แสดงผลขึ้นมาดัง VDO นี้
         สิ่งที่เราจะต้องทำ คือ สร้าง ScrollAwareFABBehavior.java  และ extends FloatingActionButton.Behavior เพื่อจัดการกับ Scroll event โดยที่เราจะให้เกิด event เมื่อมีการ Scroll แนวตั้งเท่านั้น ดูโค้ดกันเลย

ScrollAwareFABBehavior.java
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

    @Override
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child,
                                       View directTargetChild, View target, int nestedScrollAxes) {
        return nestedScrollAxes == ViewCompat.SCROLL_AXIS_VERTICAL ||
            super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
    }
}
         จากโค้ดด้านบนเป็นการกำหนดว่า เมื่อมีการ Scroll แนวตั้งเกิดขึ้น จะทำการ call onNestedScroll() ซึ่งเราก็จะทำการให้ แสดง/ซ่อน FAB ตอนนี้นั่นเอง
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

    ...

    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, FloatingActionButton child,
                               View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed);

        if (dyConsumed > 0 && child.getVisibility() == View.VISIBLE) {
            child.hide();
        }
        else if (dyConsumed < 0 && child.getVisibility() != View.VISIBLE) {
            child.show();
        }
    }
}
จากโค้ดจะเห็นว่ามีการเรียก method hide() และ show() เท่านั้น ซึ่งตรงนี้ต้องขอขอบคุณทาง Google ที่ได้ implement โค้ดในการ fade-in fade-out ของ FAB ไว้ใน support v4 library ให้เรียบร้อยแล้ว (ดู Update)
         สุดท้าย คือ ต้องทำให้ FAB และ CoordinatorLayout มีความสัมพันธ์กัน ด้วยการใส่ custom attribute  app:layout_behavior  ให้ FAB
<android.support.design.widget.FloatingActionButton    
    app:layout_behavior="com.trydroid.ScrollAwareFABBehavior" />
         จากโค้ดด้านบน เราได้ทำการใส่ Behavior เข้าไปใน XML แบบ Static เพื่อที่จะให้โค้ดทำงานได้ถูกต้อง จำเป็นจะต้องมีการ implement constructor ของ  ScrollAwareFABBehavior.java   ดังนี้
public class ScrollAwareFABBehavior extends FloatingActionButton.Behavior {

    public ScrollAwareFABBehavior(Context context, AttributeSet attrs) {
        super();
    }

    ...
}
หากไม่ได้ทำการ implement constructor จะเกิด error Could not inflate Behavior subclass
         เพียงเท่านี้เมื่อมีการ Scroll ลงล่างก็จะซ่อน FAB และเมื่อ Scroll กลับขึ้นข้างบนก็จะแสดง FAB อีกครั้ง แล้วหละครับ ง่ายนิดเดียวว่ามั้ย :)

ปล. เท่าที่ลองใช้งาน เมื่อใช้งานร่วมกับ NestedScrollView ยังมีปัญหาอยู่ สามารถใช้งานร่วมกับ ViewPager NestedScrollView RecyclerView ได้ปกติครับ

ลิงค์อ้างอิง

Codepath.com : Floating Action Buttons

Teeranai P

Developer ตัวน้อยๆ ที่หลงใหลในโลกของการพัฒนา Software. รักการเขียนโปรแกรมเป็นอันดับ 2 รองลงมาจากการนอน