01 กรกฎาคม 2558

[Android Code] รู้จักกับ Snackbar ของเล่นตัวใหม่จาก Material Design



        วันนี้ก็ปลีกตัวมาแอบเขียนบทความเกี่ยวกับ Material Design กันเล็กน้อย แต่ทว่าจะลงโค๊ดกันนะครับ ไม่ได้พูดเรื่อง Design Principle

        โดย Material Design นั้นก็มาพร้อมกับ Widget ใหม่ๆอีกหลายๆตัว และหนึ่งในนั้นก็คือ Snackbar ซึ่งเจ้าของบล็อกขอหยิบมาเขียนให้ได้อ่านกันเพลินๆตามเคย

Snackbar นั้นคืออะไรหนอ?

        เฉกเช่นเดียวกับ Widget อีกตัวใน Android ที่ทางทีมพัฒนาได้ตั้งชื่อให้เกี่ยวข้องกับของกินอย่าง Toast และ Hamburger

        สำหรับนิยามของ Snackbar จะสรุปได้คร่าวๆว่า

        "Snackbar เป็นรูปแบบหนึ่งในการโต้ตอบกับผู้ใช้  ที่มีรูปแบบการแสดงผลที่รบกวนผู้ใช้ค่อนข้างน้อย (Lightweight) โดยจะแสดงอยู่บริเวณข้างล่างของหน้าจอมือถือหรือบริเวณซ้ายล่างของอุปกรณ์ที่มีหน้าจอใหญ่ๆอย่าง Tablet และอยู่เหนือเนื้อหาต่างๆบนหน้าจอ"

        ถ้าผู้ที่หลงเข้ามาอ่านยังนึกไม่ออกให้ลองดูภาพข้างล่างนี้ก็ได้



       Snackbar ถูกนำมาใช้ในแอนดรอยด์ได้ซักพักแล้ว ซึ่ง GMail ก็คือหนึ่งในนั้น โดยจะสังเกตเห็นได้ทุกครั้งเวลาที่ลบจดหมาย

Snackbar ต่างจาก Toast ยังไงกันนะ?

       นักพัฒนาแอนดรอยด์ทุกคนย่อมรู้จักกับ Toast อยู่แล้ว เพราะเป็นหนึ่งในพื้นฐานที่มักจะใช้งานกันอยู่บ่อยๆ และจะเห็นว่า Snackbar มีหน้าที่คล้ายกับ Toast นั่นก็คือ แสดงข้อมูลหรือข้อความชั่วคราวให้ผู้ใช้เห็น

        ถึงแม้ว่า Toast จะถูกใช้มานาน แต่ Toast กลับมีข้อเสียหลายๆจุดในแง่ของการใช้งานจริง ดังนี้

        • มีการทำงานที่ซ้ำซ้อนกัน เวลาแสดง Toast เป็นจำนวนเยอะๆจะทำให้มี Toast โผล่ขึ้นมาซ้อนกันเยอะมาก
        • ใช้เวลานานในการจางหายไป จึงกลายเป็นสิ่งที่น่ารำคาญไปในบางครั้ง
        •  ไม่สามารถทำอะไรกับมันได้นอกจากดูเนื้อหาที่แสดงอยู่ใน Toast

        ด้วยข้อเสียดังกล่าวจึงทำให้การใช้งาน Toast บ่อยครั้ง เป็นที่น่ารำคาญให้กับผู้ใช้ มากกว่าการสื่อสารบางอย่างให้ผู้ใช้ ดังนั้น Snackbar จึงถือกำเนิดขึ้นจากการพัฒนาจาก Toast ให้ดีขึ้น ดังนั้นจากข้อเสียของ Toast จึงถูกแทนด้วยคุณสมบัติของ Snackbar ดังนี้

        • แสดงแค่อันเดียวเท่านั้น ถ้ามี Snackbar อันใหม่ก็จะเข้ามาแทนที่ของเก่า แล้วของเก่าจะเลื่อนหายไปในทันที
        • สามารถกำหนดให้แสดงชั่วคราวหรือถาวรก็ได้
        • มีปุ่มให้หนึ่งปุ่มเพื่อสั่งงานอะไรก็ได้จาก Snackbar เช่น เวลาลบจดหมายทิ้งก็จะมี Snackbar ขึ้นแจ้งเตือนว่าลบแล้ว และจะมีปุ่ม Undo เพื่อให้สามารถยกเลิกการลบจดหมายได้


        เรียกได้ว่า Snackbar ได้กลบข้อเสียของ Toast เรียบร้อย โดยมาในรูปแบบการแสดงผลแบบใหม่ที่เข้ากับ Material Design มากขึ้น

Snackbar กับ Android Design Support Library       

        ในวันที่ Android 5.0 Lollipop เปิดตัวอย่างสมบูรณ์ สิ่งที่นักพัฒนาค้นพบก็คือ

        มันยังไม่มี Snackbar ให้เรียกใช้!!

        ดังนั้นต้องหันไปพึ่ง 3rd-Party Library ของ Nispok หรือ MrEngineer13 กันแทน


        จนล่าสุดทางทีมพัฒนาก็ได้ออก Library ชุดใหม่ที่ชื่อว่า Android Design Support Library เพื่อตอบสนองความต้องการของนักพัฒนาที่อยากจะทำ Material Design ในแอป และใน Library ชุดนี้ก็จะมี Snackbar มาให้ด้วยนั่นเอง


        ดังนั้น Snackbar ในบทความนี้เจ้าของบล็อกจะอิงจากของ Android Design Support Library ทั้งหมดนะครับ (3rd-Party Library บางเจ้าก็ประกาศ Deplecated ตัวเองทันที)

        ก่อนจะเริ่มใช้งาน Android Design Support Library ก็อย่าลืมเพิ่ม Dependency เวอร์ชันล่าสุดลงในโปรเจคด้วยนะ

compile 'com.android.support:design:23.1.1'

ใช้งานยากมั้ยนะ?

        Toast ใช้งานเช่นใด Snackbar ก็เช่นนั้นครับ เพราะตัว Library ออกแบบมาเพื่อให้ใช้คำสั่งคล้ายๆกับ Toast เพื่อให้นักพัฒนาสามารถ Migrate จาก Toast ไปเป็น Snackbar ได้ง่ายๆ จึงเหลือแค่ไม่กี่อย่างที่แตกต่างจาก Toast

        คำสั่ง Toast ที่คุ้นเคยกันดี

Toast.makeText(this, "This is Toast", Toast.LENGTH_SHORT).show();

        ก็ได้มาเปลี่ยนเป็น Snackbar ที่ไม่ค่อยจะต่างกันเลย

Snackbar.make(getView, "This is Snackbar", Snackbar.LENGTH_SHORT).show();

        จุดที่แตกต่างก็จะมีแค่คำสั่ง makeText ของ Toast ที่ต้องการ Context ในการทำงาน (ซึ่งส่วนใหญ่ก็จะโยน this เข้าไปนั่นเอง) แต่คำสั่ง make ของ Snackbar กลับจะต้องโยน View ไปให้แทน

มาดูการใช้งาน Snackbar ดีกว่า

        การสั่งงาน Snackbar จะต้องใช้คำสั่ง make เสมอ โดยไม่จำเป็นต้อง New Object เพราะ Snackbar เป็น Static Class แบบเดียวกับ Toast (จะสร้าง Instance มาเก็บ Return จากคำสั่ง make ก็ได้ แต่ทว่าคำสั่งที่ใช้งานส่วนใหญ่จะทำเป็น Method Chaining อยู่แล้ว จึงไม่จำเป็นต้องสร้าง Instance มาเก็บเลย)      
        โดยคำสั่ง make จะมี Parameter ดังนี้

public static Snackbar make (View view, String message, int duration)
public static Snackbar make (View view, int resId, int duration)

        • View view สำหรับกำหนด View ใดๆก็ตามที่แสดงอยู่บนหน้าจอนั้นๆ เพราะคำสั่ง make จะเอา View ตัวนั้นมาหา Parent View อีกที เพื่อแสดง Snackbar บน Layout ของหน้าจอ


        ดังนั้นตรงนี้อย่าเข้าใจผิดเด็ดขาดว่า Snackbar จะสั่งให้มันแสดงบน View ตัวไหนก็ได้ เพราะมันใช้แค่ค้นหา Parent View เท่านั้น แล้วค่อยไปแสดง Snackbar ที่ระดับ Parent View อีกที

        • String message หรือ int resId คือข้อความที่ต้องการให้แสดงบน Snackbar สามารถกำหนดได้ทั้ง String และ String Resource โดยจะมีข้อจำกัดว่า ข้อความที่แสดงนั้นจะแสดงไม่เกินสองบรรทัด เพราะว่า Snackbar เป็นการโต้ตอบกับผู้ใช้โดยไม่ทำให้รบกวนการใช้งานมากนัก


        ในขณะที่ Toast มีเท่าไรก็แสดงหมด จึงทำให้ข้อความจาก Toast นั้นรบกวนผู้ใช้มากเกินไป ซึ่งขัดกับหน้าที่ของ Toast


        • int duration คือระยะเวลาที่ต้องการให้แสดง Snackbar ก่อนที่จะเลื่อนหายไป โดยกำหนดได้ 3 แบบเท่านั้น คือ LENGTH_SHORT, LENGTH_LONG และ LENGTH_INDEFINITE โดยที่ Short และ Long จะเป็นแบบเดียวกับ Toast เป๊ะๆ แต่ Indefinite จะเป็นการแสดง Snackbar แบบถาวร จนกว่าจะมีอันอื่นแสดงแทนที่หรือใช้คำสั่ง dismiss

Snackbar.LENGTH_SHORT
Snackbar.LENGTH_LONG
Snackbar.LENGTH_INDEFINITE

คำสั่ง show นั้นสำคัญ

        คำสั่ง show ก็คือคำสั่งแสดง Snackbar นั่นเอง ซึ่งต้องเรียกคำสั่งนี้ทุกครั้ง Snackbar ที่กำหนดไว้ถึงจะแสดงให้เห็น

Snackbar.make(SomeView, "Sleeping For Less", Snackbar.LENGTH_SHORT).show();

        และถ้าอยากจะให้มันหายไปกลางคัน สามารถสั่งงานโค๊ดได้โดยใช้คำสั่ง dismiss

Snackbar snackbar = Snackbar.make(rootView, "Yay! It's finished!", Snackbar.LENGTH_SHORT);
snackbar.show();
...
...     
snackbar.dismiss();

        แต่นั่นก็หมายความว่าต้องมี Instance มาเก็บ Snackbar ไว้ก่อนนั่นเอง ถึงจะเรียกใช้งาน Dismiss ในช่วงเวลาที่ต้องการได้

กำหนด Action ให้กับ Snackbar 

        จากที่พูดในตอนแรกว่า Snackbar จะสามารถกดเพื่อทำคำสั่งบางอย่างได้ ซึ่งแตกต่างจาก Toast ที่กดอะไรไม่ได้ โดยที่ Snackbar จะสามารถกำหนดปุ่มที่ให้กดได้อยู่ริมขวามือ แต่ว่าปุ่มที่กดได้จะเป็นแค่ตัวหนังสือเท่านั้น ไม่ได้เป็นภาพปุ่มแต่อย่างใด ยกตัวอย่างภาพข้างล่างปุ่มกดจะเป็นคำว่า UNDO สีเหลือง


        สำหรับ Action บน Snackbar จะมีได้แค่ Action เดียวเท่านั้น ด้วยหน้าที่ของ Snackbar เองจึงไม่เหมาะกับการที่จะมีหลายๆปุ่มอยู่บนนี้ และ Action นั้นๆต้องสัมพันธ์กับข้อความที่แสดงบน Snackbar ด้วย เช่น Snackbar แสดงข้อความให้ผู้ใช้ทราบว่าไฟล์ถูกลบไปแล้ว แต่มี Action เป็น Undo เพื่อให้ผู้ใช้ยกเลิกการลบไฟล์นั้นๆได้ เป็นต้น

        การกำหนด Action จะใช้คำสั่ง

public Snackbar setAction (int resId, View.OnClickListener listener)

public Snackbar setAction (CharSequence text, View.OnClickListener listener)

        CharSequence text กับ int resId คือข้อความ Action ที่จะให้ผู้ใช้เห็น โดยจะกลายเป็นตัวอักษรพิมพ์ใหญ่ให้โดยอัตโนมัติ จะกำหนดเป็น Char Sequence หรือ String Resource ก็ได้

        วิธีใช้คำสั่ง

View rootView = findViewById(R.id.root_view);
Snackbar.make(rootView, "Yay! It's finished!", Snackbar.LENGTH_SHORT).setAction("ok", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Do something when user action was click
    }
});

        สำหรับ root_view ก็คือ Parent View ของ Layout (ไปใส่ชื่อ ID ไว้ว่า root_view)

        ว่าแต่ เห็นหรือป่าวเอ่ย ว่าลืมคำสั่งอะไรไป?
        .
        .
        .
        .
        ลืมคำสั่ง show นั่นเอง เพราะงั้น Snackbar ก็จะไม่แสดง

        ดังนั้นคำสั่งที่ถูกต้องก็คือต้องมีคำสั่ง make มีคำสั่ง setAction และจบท้ายด้วย show ทุกๆครั้ง

View rootView = findViewById(R.id.root_view);
Snackbar.make(rootView, "Yay! It's finished!", Snackbar.LENGTH_SHORT).setAction("ok", new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // Do something when user action was click
    }
}).show();
        จะเห็นว่า ok ถูกทำให้เป็นตัวพิมพ์ใหญ่ และจะมีสีเป็นสีเขียวให้โดยอัตโนมัติ ในขณะที่ข้อความบน Snackbar เป็นสีขาว

        ถ้าอยากเปลี่ยนสีตัวหนังสือของ Action ก็จะมีคำสั่ง setActionTextColor ให้กำหนดค่าสี

public Snackbar setActionTextColor (ColorStateList colors)
public Snackbar setActionTextColor (int color)

        เวลากำหนดต้องใส่เป็น Color Integer นะครับ ไม่ใช่ Color Resource และถ้าอยากจะให้ปุ่มกดแล้วเปลี่ยนสีได้เวลากด ก็ให้ใช้ ColorStateList แทนได้

        ถ้ากำหนดสีง่ายๆก็จะมีคำสั่งแบบนี้ (อย่าลืมคำสั่ง show นะ)

View rootView = findViewById(R.id.root_view);
        Snackbar.make(rootView, "Yay! It's finished!", Snackbar.LENGTH_SHORT)
        .setAction("OK", new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                // Do something when user action was click
            }
        })
        .setActionTextColor(Color.RED)
        .show();

        ก็จะได้ Action ตัวเป็นหนังสือสีแดง
        ถ้าต้องการดึง Color Resource ก็ให้ใช้แบบนี้แทน

setActionTextColor(getResources().getColor(R.color.red))

คำสั่งอื่นๆของ Snackbar

        และนอกจากนี้ก็ยังมีคำสั่งกำหนดค่าเล็กๆน้อยๆ ซึ่งไม่ค่อยได้ใช้ซักเท่าไร

public Snackbar setDuration (int duration)
public Snackbar setText (int resId)
public Snackbar setText (CharSequence message)

public int getDuration ()
public View getView ()

สรุป

        Snackbar ถือว่าเป็น Lightweight Feedback ที่น่าใช้งานมากกว่า Toast เพราะไม่รบกวนผู้ใช้จนเกินไป มี Action ได้หนึ่งอย่าง และไม่แสดงซ้ำซ้อนกัน รวมไปถึงรูปแบบการแสดงผลก็เหมาะสมกับ Material Design ดังนั้นถ้าเป็นไปได้ก็อยากให้ลองใช้กันดู แต่ทว่าจะเลือกใช้ Toast หรือ Snackbar ก็ควรดูความเหมาะสมของแอปพลิเคชันด้วยนะครับ


        สำหรับโค๊ดตัวอย่างของบทความนี้สามารถดาวน์โหลดได้ที่
        • Google Drive
        • Sleeping For Less

        และอยากรู้ว่า Android Design Support Library มีอะไรบ้างใช้งานยังไงสามารถดูได้จาก มาแล้ว Codelab สอนใช้ Android Design Support Library จากงาน I/O Rewind Bangkok




เหล่าพันธมิตรแอนดรอยด์

Devahoy Layer Net NuuNeoI The Cheese Factory Somkiat CC Mart Routine Artit-K Arnondora Kamonway Try to be android developer Oatrice Benz Nest Studios Kotchaphan@Medium Jirawatee@Medium Travispea@Medium