[Dev] Custom WebView บน Android

เนื่องจากว่า ใน App Ethan’s Web Reader ที่ใช้สำหรับอ่านบทความจากเว็บนี้แหล่ะ มีส่วนที่แสดงด้วย WebView อยู่ด้วย ซึ่งผมต้องการทราบ Position ที่ WebView นั้นแสดงอยู่ แบบ Real time แต่ก็พบว่า ไม่มี Listener ตัวไหน ที่จะให้ตรวจสอบแบบ Real time ได้เลย

Android Developer logo

สำหรับบทความตอนนี้ ผมจะทำการ Custom WebView โดยจะทำการเพิ่มความสามารถ OnScrollChangedListener เพื่อไว้ตรวจสอบ Position ที่ WebView แสดงอยู่แบบ Real time ให้ดูนะครับ

ก็ในเมื่อ WebView ไม่มีให้ใช้ ก็ทำให้มันมีขึ้นมา โดยการ Custom มันขึ้นมาซะเลย

ในบทความนี้ จะใช้ Eclipse เป็นหลัก และใช้ความสามารถของ Eclipse ในการช่วยสร้างส่วนต่าง ๆ นะครับ สำหรับใครที่ใช้ Android Studio ก็ลองปรับ ๆ ดูนะ

 

List of contents

 

WebView Class

ก่อนลงมือ Custom WebView นั้น ก็ต้องดูความเป็นไปได้ก่อนว่าจะสามารถอ่านค่า Position แบบ Real time ได้หรือไม่ ซึ่งก็ได้พบว่า Class WebView นั้น มี Class View เป็นบรรพบุรุษ ดังรูป

WebView Class Hierarchy
WebView Class Hierarchy

ซึ่งใน Class View ก็มี Method getScrollX() และ getScrollY() ให้ใช้ ซึ่งจะ Return ค่าเป็น X และ Y Position ได้

แต่ว่า… แล้วจะรู้ได้ยังไงว่ามีการเปลี่ยนตำแหน่ง เพื่อที่จะได้เรียกใช้ 2 Method ดังกล่าวได้ จะเขียนคำสั่งตรวจสอบตลอดเวลาก็ไม่น่าจะถูกต้องเท่าไหร่นัก หรือจะใช้ OnTouchListener เพื่อดัก Event ที่เกิดจากการ Touch แล้วค่อยใช้ Method getScrollX() และ getScrollY() เท่าที่ลองดูก็พบว่า หากทำการ Swipe หรือเหวี่ยงเร็ว ๆ นิ้วมือเรายกออกจากจอแล้ว OnTouchListener ก็ไม่เกิดแล้ว แต่ WebView ยังไหลต่อไปได้อยู่ ก็เลยไม่ค่อยตรงประเด็นเท่าไหร่นัก

พอส่อง Reference ของ Class View ต่อไปเรื่อย ๆ ก็พบว่า Class View มี Method onScrollChanged() ให้ใช้ และ Return ค่า X และ Y Position ให้ได้เลย

แต่… ใช้ Method นี้เลยไม่ได้~!! เพราะว่ามันเป็น Protected Method

เพราะฉะนั้น Class ที่ Inherit มาจาก Class View ทั้งหลาย สามารถเข้าถึง Method นี้ได้แล้ว

 

Design Custom WebView Class

เมื่อพบแล้วว่า มี Method onScrollChanged() ของ Class View ให้ใช้ ซึ่งเป็นบรรพบุรุษของ Class WebView เพราะฉะนั้น เราจะทำการสร้าง Custom WebView Class ขึ้นมาใช้

โดยคราวนี้ ผมใช้หลักการตามแนวคิด TDD มโนขึ้นมาเองว่า จะใช้งานได้แบบนี้

เมื่อมโนขึ้นมาแล้ว ก็ถึงเวลาทำการทำให้มันมีขึ้นมาจริง ๆ ซึ่งจาก Code ที่มโนขึ้นมา สรุปได้ว่า จะต้องเพิ่มความสามารถให้กับ Class WebView ดังนี้

  1. เพิ่ม Interface OnScrollChangedListener เข้าไป เพื่อใช้ Implement Callback Method เมื่อเกิดการ Scroll
  2. สร้าง Callback Method ชื่อ onScrollChanged()1 ให้กับ Interface OnScrollChangedListener
  3. สร้าง Method setOnScrollChangedListener() เพื่อใช้สำหรับกำหนด Listener ที่สร้างมาจาก Interface OnScrollChangedListener
  4. ที่ Method onScrollChanged() ของ Class WebView ส่งค่าออกไปทาง Callback Method ของ Interface ต่อไป

1ขอใช้ชื่อเดียวกับ Method onScrollChanged() ของ Class View ละกันนะครับ คิดชื่ออื่นที่เหมาะสมกว่านี้ไม่ได้แล้ว

 

Create Custom WebView Class

เมื่อ Design Custom WebView Class ไว้แล้ว ก็ถึงเวลาเริ่มลงมือทำกันแล้วนะครับ โดยเริ่มจาก สร้าง Class ใหม่ขึ้นมาก่อนเลย ดังนี้

คลิกขวาที่ Folder src ของ Project เรา เลือกเมนู New > Class ตามรูป

เพิ่ม Class ใหม่ ใน Folder src
เพิ่ม Class ใหม่ ใน Folder src

จะพบกับ New Java Class Dialog ให้กำหนดค่าดังนี้

  1. ชื่อ Package ที่ต้องการ
  2. ชื่อ Class ที่ต้องการ
  3. กำหนด Superclass ที่ต้องการ สามารถใช้ปุ่ม Browse… ช่วยค้นหาได้
  4. กำหนดให้สร้าง Constructor ตาม Superclass และสืบทอด Abstract methods

จากรูปด้านล่าง ผมใช้ชื่อ Class ว่า WebView2 ซึ่งผมอยากใช้ชื่อ Class ว่า WebView เหมือนเดิม แต่พบว่า Code ที่ถูก Generate ออกมาจะมีปัญหา จึงตั้งชื่อว่า WebView2 ไปก่อน ค่อยไปแก้ที่หลัง

New Java Class Dialog
New Java Class Dialog

ก็จะได้ Class ที่สืบทอดจาก android.webkit.WebView แล้ว ดังนี้

ทำการแก้ไข Code นิดหน่อย โดย ลบ Code ตรง import android.webkit.WebView; ออก และเปลี่ยนตรง extends WebView เป็น extends android.webkit.WebView เพื่อที่จะได้เปลี่ยนชื่อ Class ของเราเป็น WebView ได้ โดยการคลิกเลือกที่ไฟล์ WebView2.java (1) แล้วกดปุ่ม F2 จะมี Rename Compilation Unit Dialog ขึ้นมา แก้ชื่อไฟล์เป็น WebView (2) แล้วกดปุ่ม Finish (3)

Rename Class
Rename Class file

เมื่อ Rename ไฟล์เรียบร้อย ชื่อ Class และ Constructor ใน Source code ก็จะถูกแก้เป็น WebView แล้ว

 

Using Custom WebView Class

หลังจากนั้น ก็ไปแก้ที่ Activity Class ที่จะใช้งาน Custom WebView โดยการเปลี่ยน import จาก

เป็น

และอย่าลืมไปแก้ไข Layout ด้วย จาก

เป็น

 

Implement Custom WebView Class

ถึงเวลาเพิ่มฟีเจอร์ให้กับ WebView กันแล้ว ซึ่งจากที่เรามโนไว้ในหัวข้อ Design Custom WebView Class นั้น เมื่อลองเอา Cursor ไปชี้ที่ Method setOnScrollChangedListener() ที่มัน Error อยู่ จะมีตัวเลือก ให้เลือก Create method ตามรูป

ตัวเลือก Create method ช่วยสร้าง Code ให้
ตัวเลือก Create method ช่วยสร้าง Code ให้

ที่ WebView ของเรา มี Method setOnScrollChangedListener() ถูกสร้างขึ้นมาโดยอัตโนมัติ แถมด้วย Parameter ชนิด Interface ชื่อ OnScrollChangedListener ด้วย ตามที่ได้ออกแบบไว้

และมีการ import <package name>.OnScrollChangedListener; ไว้ให้ด้วย บรรทัดนี้ ลบออกไปก่อน

และเนื่องจากว่า เรายังไม่ได้สร้าง Interface ก็จะมี Error อยู่ เมื่อเอา Cursor ไปชี้ ก็จะมีตัวเลือก ให้เลือก Create interface ตามรูป

ตัวเลือก Create interface ช่วยสร้าง Code ให้
ตัวเลือก Create interface ช่วยสร้าง Code ให้

จะพบกับ New Java Interface Dialog ตามรูป ให้กำหนดเป็น Enclosing type เพื่อให้ Interface OnScrollChangedListener เป็น inner ภายใน Class WebView ของเรา

New Java Interface Dialog
New Java Interface Dialog

ก็จะได้ Inner Interface เปล่า ๆ ภายใน Class WebView แล้ว

กลับไปที่ Code ส่วนที่ได้มโนไว้ เมื่อเอา Cursor ไปชี้ที่ OnScrollChangedListener ทำการ Import ให้เรียบร้อย

Import OnScrollChangedListener
Import OnScrollChangedListener

และ Method onScrollChanged() เมื่อเอา Cursor ไปชี้ จะมีตัวเลือก ให้เลือก Create ตามรูป

ตัวเลือก Create ช่วยสร้าง Code ให้
ตัวเลือก Create ช่วยสร้าง Code ให้

ก็จะได้ Class WebView ที่มีโครงสร้างเพิ่มเติมตามที่มโนไว้แล้ว ตามนี้

ถึงเวลา Coding Custom WebView กันแล้ว…

เมื่อโครงสร้างของ Class WebView เสร็จแล้ว ก็จะเป็นส่วนของการ Implement ส่วนที่ใช้เชื่อมกับ Method onScrollChanged() ของ Class WebView โดยเริ่มจากการเก็บค่า OnScrollChangedListener ที่ส่งเข้ามาจากภายนอก โดยจะต้องสร้าง Field ขึ้นมาก่อน

แล้วนำ Field ที่สร้าง ไปเก็บค่า OnScrollChangedListener จาก Method setOnScrollChangedListener() ดังนี้

และสุดท้าย ทำ Override Method onScrollChanged() ของ Class WebView ดังนี้

สังเกตุว่า Method onScrollChanged() ของ Class WebView นั้น มี Parameter 4 ตัว ดังนี้

  • l คือตำแหน่งในแนวนอน หรือแกน x นั่นเอง จึงนำไปส่งต่อให้กับ Callback Method onScrollChanged ของ Interface OnScrollChangedListener ผ่านทาง Parameter x
  • t คือตำแหน่งในแนวตั้ง หรือแกน y นั่นเอง จึงนำไปส่งต่อให้กับ Callback Method onScrollChanged ของ Interface OnScrollChangedListener ผ่านทาง Parameter y
  • oldl คือ ค่าเก่า ของคือตำแหน่งในแนวนอน หรือแกน x
  • oldt คือ ค่าเก่า ของคือตำแหน่งในแนวตั้ง หรือแกน y

ถ้าอย่างนั้น เราปรับปรุง Method onScrollChanged ของ Interface OnScrollChangedListener ให้มี Parameter เหมือนกับ onScrollChanged ของ WebView ดีกว่า เผื่อว่าอาจได้ไปใช้งาน โดยเปลี่ยนเป็นแบบนี้

และปรับปรุง Override Method onScrollChanged() ของ Class WebView ด้วย ดังนี้

ก็จะได้ Class WebView ที่ Custom เรียบร้อยแล้ว รวม ๆ Code ทั้งหมดออกมาเป็น ดังนี้

ทดลองนำไปใช้งาน โดยสร้าง Layout ดังนี้

ส่วนของ Activity Class

และอย่าลืมกำหนด Use permission ใน AndroidMenifest.xml ให้ใช้ permission android.permission.INTERNET ดังนี้

XML Code:

ทดลองรันดู แล้วทำการ Swipe แล้วดู LogCat

แสดงผล Web บน Custom WebView
แสดงผล Web บน Custom WebView
LogCat แสดงค่าตำแหน่งที่แสดง Web บน Custom WebView ออกมา
LogCat แสดงค่าตำแหน่งที่แสดง Web บน Custom WebView ออกมา

เราก็ทราบ Position ที่แสดง Web ออกมาได้แล้ว

 

ไม่ยากใช่ไม๊ครับ สำหรับการ Custom WebView

 

สรุปสุดท้าย บทความนี้ ได้ใช้วิชา OOP, การทำ TDD และแนวคิดแบบ Callback มาผสมผสานกัน หากใครที่ยังไม่แม่นเรื่องไหน ลองคลิกที่ Link ต่าง ๆ ที่ผมทำไว้ให้ดูนะครับ ทำช่องวาร์ปสำหรับแต่ละเรื่องไว้ให้แล้ว

สำหรับ Custom WebView Class ในบทความนี้ หากใครต้องการนำไปใช้งาน สามารถนำไปใช้ได้ทันทีนะครับ ผมตั้งใจจะ Open Source อยู่แล้ว แต่… ตัวที่มีฟีเจอร์เยอะกว่านี้ ยังไม่ได้แจกในตอนนี้นะครับ แล้วไว้จะแจกทีหลังให้ใช้กันนะ

Leave a Reply

Your email address will not be published. Required fields are marked *

 

This site uses Akismet to reduce spam. Learn how your comment data is processed.