บทความวันนี้เจ้าของบล็อกขอพูดถึงเรื่องของ Listener ที่คุ้นเคยกันเสียหน่อย ซึ่งเรื่องที่จะพูดถึงนี้เป็นเรื่องที่ชาวบ้านเค้าไม่ค่อยพูดถึงกันอีกตามเคย (ฮาๆ)

สำหรับ OnClick OnLongClick และ OnTouch ซึ่งผู้ที่หลงเข้ามาอ่านทุกคนคงเคยใช้กันแล้วล่ะ บ้างก็เคยใช้แค่ OnClick อย่างเดียว หรือเคยใช้ OnTouch เป็นบางครั้ง แต่เจ้าสามสิ่งนี้เป็น Listener ที่น่าจะคุ้นเคยกันดีแหละเนอะ

แต่ทว่าทั้งสาม Listener นี้มีบางอย่างที่สัมพันธ์กันอยู่ด้วยนะเออ เคยสังเกตกันหรือไม่ว่าทำไม onLongClick กับ onTouch ต้องมี Return เป็น Boolean กันด้วย?

public boolean onLongClick(View v)
public boolean onTouch(View v)


ในขณะที่ onClick กลับไม่มีซะงั้นอ่ะ?

public void onClick(View v)


แต่ก่อนจะเล่าต่อก็ต้องถามย้อนกลับก่อน แล้วรู้หรือป่าวว่าไอที่ Return เป็น Boolean เนี่ย มันคือตัวแปรสำหรับอะไร? ถ้าลองดู Reference ของ onLongClick ก็จะเป็นแบบนี้

true if the callback consumed the long click, false otherwise.
ค่าจะเป็น True เมื่อใช้งาน onLongClick และเป็น False เมื่อไม่ใช้งาน

อ้าว หมายความว่ายังไงล่ะ? ก่อนอื่นให้ลองดูโค๊ดตัวนี้ก่อน

RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout); layout.setOnClickListener(new OnClickListener() { public void onClick(View v) { Log.i("Check", "On Click"); } }); layout.setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View v) { Log.i("Check", "On Long Click"); return false; } });


จะเห็นว่าเจ้าของบล็อกเรียกใช้งาน Listener พร้อมๆกันสองตัว คือ onClick กับ onLongClick โดยที่ทั้งสองตัวนี้เจ้าของบล็อกได้กำหนดไว้ว่าเมื่อตัวใดทำงานก็จะแสดงข้อความออก LogCat ซึ่งจะเห็นว่า onLongClick ได้ Return ค่าเป็น False

พอเจ้าของบล็อกลองทดสอบกดที่ Layout ตัวดังกล่าวค้างไว้ดู แล้วเช็คที่ LogCat ก็จะพบว่ามี LogCat ขึ้นมาซ้อนกันทั้ง onClick และ onLongClick

ทีนี้เปลี่ยนใหม่ คำสั่งเดิมแต่เปลี่ยนให้ Return ค่าเป็น True ดูบ้าง

RelativeLayout layout = (RelativeLayout)findViewById(R.id.layout); layout.setOnClickListener(new OnClickListener() { public void onClick(View v) { Log.i("Check", "On Click"); } }); layout.setOnLongClickListener(new OnLongClickListener() { public boolean onLongClick(View v) { Log.i("Check", "On Long Click"); return true; } });


แล้วลองทดสอบดูใหม่อีกครั้ง โดยกดที่ Layout ตัวดังกล่าวค้างไว้เหมือนเดิม ก็จะเห็นว่ามีแค่ Log ที่มาจาก onLongClick เท่านั้น

จะเห็นว่าการกำหนดค่าที่จะ Return ใน onLongClick นั้นมีผลกับ onClick ด้วย โดยที่เมื่อเป็น True จะทำให้ onClick ทำงานไม่ซ้อนกันนั่นเอง

ดังนั้นจะเห็นว่าที่ต้องมีการกำหนดค่าตัวนี้ก็มีไว้ป้องกันมันทำงานซ้อนกันในเวลาที่ไม่ต้องการนั่นเอง โดยจะมีลำดับความสำคัญเรียงกันตามนี้

onTouch > onLongClick > onClick
ถ้าจะให้อธิบายด้วยภาพก็คงประมาณนี้ละมั้ง

ถึงตอนนี้ผู้ที่หลงเข้ามาอ่านอาจจะเกิดคำถามว่า ทำไมต้อง Return อะไรแบบนี้ด้วยล่ะ? ไม่ให้อันที่อยู่สูงสุดทำงานไปเลยล่ะ?

ให้นึกภาพว่าต้องการทำแอปพลิเคชันตัวหนึ่งที่มี Button ธรรมดาๆ สามารถกดได้และมี Gesture อย่างเช่นลากนิ้วไปทางซ้ายเพื่อทำอะไรบางอย่างล่ะ?

ที่แน่นอนเลยก็คือเมื่อแตะลงบนปุ่มดังกล่าวนี้สิ่งที่เกิดขึ้นก็คือ onTouch ในทันที ถ้า onTouch ทำการ Return ค่ามาเป็น True ตลอด แล้วจะให้ onClick ทำงานได้อย่างไรล่ะ? ดังนั้นจึง Return เป็น False เมื่อการแตะบนปุ่มนั้นไม่ใช่การลากนิ้วไปทางซ้าย จึงทำให้ onClick สามารถทำงานได้ตามปกติ และ Return ค่าเป็น True เมื่อ Gesture ทำงาน เพื่อที่ว่า onClick จะได้ไม่ทำงานนั่นเอง

เมื่อถึงจุดนี้แล้วก็ดูให้ดีๆว่าควรจะ Return ค่าเป็นอะไร โดยสำหรับ onLongClick คงไม่ต้องคิดไรมากจะให้ Return เป็น True ตลอดก็ยังได้ แต่ทว่าสำหรับ onTouch จะถือว่าเป็นเรื่องจำเป็น ซึ่งก็ขึ้นอยู่กับโค๊ดนั่นแหละว่าจะให้ onTouch ไปทำงานร่วมกับ onLongClick หรือ onClick อย่างไรให้ไม่ซ้ำซ้อนกัน