พบว่า MS Edge มี Bug เกี่ยวกับการ xml + xslt + javascript แล้ว return null

internet explorer 11
internet explorer 11

พบการรายงาน Bug เรื่อง ใช้ javascript และ XSLTProcessor
ที่ MS Edge ไม่ Return value กลับมาอย่างถูกต้อง
ที่พบ คือ “Created fragment is null” จากการ run test
โพสต์ปํญหาโดย Martin Honnen เมื่อ 18 พฤศจิกายน 2558
ที่ https://connect.microsoft.com/IE/feedback/details/2030537
แล้ว MS ก็ย้าย Bug Report ไปยังกลุ่มที่ถูกต้อง
ที่ https://developer.microsoft.com/../issues/5552211/
มีตัวอย่างแฟ้มที่ https://developer.microsoft.com/../issues/9484576/
ทดสอบที่ http://encinematheque.fr/js7/_testHtml.htm
ดูผลการทดสอบใน _testHtml.htm
พบว่า

Test failed. Created fragment is: null.

แล้ว Microsoft Edge ที่ผมใช้อยู่รุ่น 38.14393.1066.0
แต่รุ่นล่าสุดคือ 40.15063 Desktop April 11,2017
ไปอ่าน ถาม-ตอบ ในเว็บของ Microsoft.com
เค้าว่าถ้า update MS Windows ก็จะ update MS Edge ให้โดยอัตโนมัติ
ก็รอลุ้นว่ารุ่นใหม่จะแก้ bug ตัวนี้หรือไม่ เพราะ browser ตัวอื่นผ่านหมด
https://en.wikipedia.org/wiki/Microsoft_Edge

firefox local
firefox local

สรุปว่าตอนนี้ เขียน Script ไว้ที่ http://www.thaiall.com/xml/list01.htm
เพื่ออ่านแฟ้ม XML ส่งเข้าปรับรูปแบบด้วย XSLT แล้วแสดงผลเป็น HTML
ได้ทดสอบกับ Firefox, IE, Opera, Chrome ก็ใช้งานได้แล้ว
ก็ใช้หลายวิธี ให้เหมาะสมกับแต่ละ Browser
เหลือแต่ MS Edge นี่หละครับ ค้างใจอยู่

 

ทดสอบ Free web hosting ที่บริการ PHP กับ MySQL มาหนึ่งโหล

อันที่จริงชีวิตคนไอทีเช่นผม ก็เริ่มต้นจากการใช้บริการ Free web hosting นี่หละ
เริ่มแรกเลยก็ geocities.com จากนั้นก็ขยับขึ้นไปบน Server
ที่บริการ Server-Side Script ไม่ใช่ Static web page อีกต่อไป
ไปใช้ บริการ Database Server บริการ PHP บ้าง ASP บ้าง
แล้วแต่อารมณ์จะพาไปหาในแต่ละช่วงชีวิต
ขอสารภาพเลยว่า ตัวหนึ่งที่เช่าใช้อยู่ทุกวันนี้ ก็เริ่มต้นจากการใช้ของเขาฟรี
แล้วติดใจ จึงยอมจ่ายตังมาจนถึงทุกวันนี้

เข้าเรื่องเลย เหตุเกิดว่าผมต้องคุยกับ น.ศ. เรื่องการเขียน Server-Side Script
พอยกกรณีศึกษา หรือ Sample code ก็ต้องหาที่ให้เค้าลอง
ต้องบริการ PHP + MySQL + Free + No Domain
จะให้ใช้ XAMPP่, Appserv, Thaiabc หรือ Localhost อยู่บ้าน นั่นต้องทำอยู่แล้ว
แต่ให้ดีต้อง Online
ครั้งจะ Upload ไป Run ที่เครื่องของผมที่เปิดรอท่า ก็ดูกะไรอยู่
จึงให้ไปสมัครใช้ฟรีกับเหล่า Free web hosting ผมตั้งเงื่อนไขให้เค้าสมัครใช้คนละ 2 ตัว

ปีนี้ 2017 หากจะให้เล่าถึง Server สมัยผม ก็คงล้มหายตายจากกันไปหมดแล้ว
ไปค้นเน็ตเจอที่ Desire Athow เขียนเมื่อ June 18, 2017
ว่ามี Free hosting สำหรับ Business ที่เป็น Best ถึง 10 sites
ผมก็ไม่รอช้า มี Reference แล้วก็หยิบมาเลย ทดสอบเรียงตัวเลย
http://www.techradar.com/…/top-free-hosting-for-businesses

ตัวแรก ueuo.com
ตัวนี้ไม่ได้อยู่ใน 10 Best นะครับ
แต่เป็นตัวที่ผมวาง Sample code เมื่อหลายปีก่อน และ Active อยู่
กลับไปทดสอบสมัคร เพราะผมใช้อยู่ก็จะแนะนำให้ น.ศ. ไปสมัครด้วย
ที่หน้าสมัครพบประกาศว่า
บริการ php 5.4 และ mysql 5.5 สำหรับ All free account
ใน ueuo.com หากจะ create an account
ต้องเข้าไปที่ freewebhostingarea.com
เข้าไปตาม Link เค้าก็ให้สมัคร
ไปจนถึงสร้าง account แบบ Free subdomain Hosting
เช่น www.thaiabc.ueuo.com แล้วกด proceed ก็จบเลยครับ
จบตรงข้อความที่ว่า
Public registration was temporarily disabled!
If you need an account, please contact us using register@freewha.com
ต่อจากนี้ก็จะทดสอบ 10 sites ตามข้อมูลที่ Desire Athow แนะนำ

ของฟรี ของดี มีในโลกไซเบอร์
ของฟรี ของดี มีในโลกไซเบอร์

1) http://www.000webhost.com/
สรุปว่าสามารถสมัครได้ มีบัญชี คือ https://thaiabc.000webhostapp.com
เริ่มจากเข้าไปแล้วพบอะไรน่าคลิ๊กไปหมด
สมัครเสร็จก็ต้องไปรอ Email confirmation required
หลัง Verify email แล้วกดปุ่ม Manage website “thaiabc”
พบบริการ 6 รายการ 1) Build website 2) Set web address 3) File manager 4) Manage database 5) Manage emails 6) Settings
เริ่มต้นก็กด Build website
พบบริการ 3 รายการ 1) Build a website easily 2) build WordPress website 3) Upload Own Website
เนื่องจากผมมีแฟ้ม .php ที่เตรียมทำงานกับ mysql จึงเลือกข้อ 3) Upload Own Website
เข้าหน้า files ที่คล้ายกับ Windows Explorer ที่แสดง Folder ด้านซ้าย มีรายการแฟ้มด้านขวา
พบห้อง /public_html เลือก Upload files แล้วก็ upload แฟ้ม .php ที่เตรียมไว้
แต่ยังทดสอบไม่ได้ เพราะต้องกำหนดเรื่อง Database ในแฟ้ม .php ก่อน
กลับไปเข้า 4) Manage database พบว่าเค้าให้ได้สูงสุด 2 Database
มี Default database engine: InnoDB on MariaDB 10.1
เข้าจัดการผ่าน database.000webhost.com และใช้ localhost เป็น hostname
แล้วสั่ง New Database
กรอก Database name, Database username, Password
หลังจัดการ Database เสร็จก็นำข้อมูลไปกรอกในแฟ้ม .php
แล้ว upload แฟ้ม .php เข้าไปใหม่
ผลการทดสอบ Sample code ผ่านด้วยดี
หลังปรับแก้การเชื่อมต่อ MySQL แบบเดิม เป็น MySQLi
เพราะ Server บริการ PHP 7.1.7 และทุกตัวที่บริการก็ให้บริการ PHP 7 ขึ้นไปกันหมด

2) http://www.freehostia.com/
หน้าตาเรียบง่ายดี มุมบนขวาเห็นคำว่า SIGN UP NOW FOR FREE ???
ในขั้นตอนต่อไป จำเป็นต้องมี Domain Name ติดตัวไปสมัครด้วย ถ้าไม่มีก็ไม่ได้ไปต่อ
สรุปว่า ต้องมี Domain name จึงจะสมัครได้

3) http://www.5gbfree.com/hosting-plans/
คลิ๊ก Signup Now จากนั้นก็กรอกข้อมูล แล้วกด Create Accout
แล้วไปทำ Verification ผ่าน link ใน email
พบรหัสผ่านใน email และข้อมูลต่าง ๆ
สำหรับ email จากที่นี่ ถ้าไม่พบใน inbox อาจไปอยู่ใน spam ได้นะครับ
วิธีเข้า cPanel เช่น http://thaiabc.5gbfree.com:xxxx/
มองหา Database พบ MySQL Databases ก็คลิ๊กเข้าไป
จากนั้นกด New Database, Add New User
จากนั้นกด Add ในหัวข้อ Add User to Database
แล้ว Manage User Privileges เลือก ALL PRIVILEGES แล้ว Make Changes
กลับออกไป cPanel เข้า File Manger
เข้า public_html แล้วคลิ๊ก Upload ส่งแฟ้ม .php ที่กำหนด DB แล้วเข้าไป
ขณะทดสอบพบปัญหาการไม่บริการ iconv ก็ตรวจสอบ แล้วปรับ code ใหม่
ผลการทดสอบ Sample code ผ่านด้วยดี

4) http://www.freehosting.com/client/cart.php
เข้าไปก็เลือกแบบ Free Hosting กด Order Now
เค้าว่าจะได้พื้นที่ 10 GB กับ 1 MySQL database แต่พบปัญหา
สรุปว่า ต้องมี Domain name จึงจะสมัครได้

5) http://www.zymic.com/
วันนี้เข้าแล้ว too long to respond ครับ
มีข้อมูลล่าสุดใน archive.org เมื่อมกราคม 2017
https://web.archive.org/web/20170111154733/http://www.zymic.com/

6) http://byet.host/free-hosting
กดปุ่ม Sign up for a plan ที่อยู่ด้านล่าง
กรอกข้อมูลแล้วกด Register แล้วไปกด activate ใน email
ไปตรวจใน Spam box ก็จะพบอีเมลจากผู้ให้บริการ
หลัง activate ระบบจะสร้าง user เพื่อเข้า control panel, mysql, ftp
ใน Control Panel คลิ๊ก MySQL Database แล้วสร้าง Database
เค้าระบุ Hostname จะใช้ localhost ไม่ได้ และมี phpmyadmin ให้ใช้
ได้ข้อมูลเข้าไปปรับแฟ้ม .php
กลับมาเลือก Online File Manager แล้วเข้า htdocs
กดปุ่ม upload, choose file แล้วคลิ๊กที่เครื่องหมายถูก เพื่อ submit
ผลการทดสอบ Sample code ผ่านด้วยดี

7) https://www.awardspace.com/free-hosting/
เข้าไปก็กรอก e-mail และ password แล้วกด Join Awardspace
แล้วไป click link to confirmation ใน email
จากนั้นเข้า Dashboard มีทุกอย่างที่ต้องการ
คลิ๊ก Database Manager
กรอก Database name และ password แล้วกด Create database
ส่วน DB user name เค้าให้เป็นชื่อเดียวกกับ Database name
แล้วให้ Host name มาด้วย ต้องใช้ของเค้า
กลับไปที่ Dashboard ครั้งนี้คลิก Domain Manager
คลิ๊ก Create a Free Subdomain พิมพ์ thaiabc หน้า atwebpages.com
แล้วกด Create พอสร้างเสร็จก็กด Open Website
http://thaiabc.atwebpages.com/
กลับไปที่ Dashboard คลิ๊ก File Manager
ก่อนหน้านี้เข้าไปแล้วว่าง ตอนนี้เข้าไปพบ Folder : thaiabc.atwebpages.com
ไป double click เพื่อเข้าไป
กด Upload เลือกแฟ้ม .php แล้วกด Upload เป็นอันเรียบร้อย
ผลการทดสอบ Sample code ผ่านด้วยดี

8) http://www.freehostingeu.com/web-hosting-page.php
ใน column Free plan กด Sign up
พบ New signups are temporarily disabled
สรุปว่าปิดบริการสำหรับผู้ใช้บริการรายใหม่ชั่วคราว

9) http://www.uhostfull.com/free-hosting.php
มีปุ่ม Sign Up! อยู่ข้างล่าง คลิ๊กเลย
มีให้กรอกเพียบ นับได้ 13 ช่อง รวม captcha
แล้วก็เข้า email จะไปทำ Activation แต่ไม่พบอีเมล
ทำ Resend Activation Email ใน http://cpanel.uhostfull.com/profile
กดแล้วก็ยังไม่ได้รับอีเมล รอแล้วก็ยังไม่เห็นมาเลย

10) http://freehostingnoads.net/webhosting.php
มีปุ่ม Signup Now อยู่ข้างล่าง คลิ๊กเลย
แล้วคลิ๊กปุ่ม If you want free limited hosting, please click here…
ตอนกรอกข้อมูลหน้าตาเหมือน http://www.uhostfull.com
และปัญหาเหมือนกันเลยด้วย
คือเข้า email จะไปทำ Activation แต่ไม่พบอีเมล
ทำ Resend Activation Email
กดแล้วก็ยังไม่ได้รับอีเมล รอแล้วก็ยังไม่เห็นมาเลย

สรุปว่าผลการทดสอบสมัครใช้ host ฟรี ตามคำแนะนำ
ของ Desire Athow ใน techradar.com เรื่อง Best free hosting
ได้มาหลังทดสอบจำนวน 4 host ตามรายละเอียดด้านบน
มองใกล้ตัวหน่อยก็เห็น Smart phone ของผมเป็น android
จึงติดตั้ง App: Palapa web server แล้ว Start service
จากนั้นก็ไปคัดลอก code จาก
http://www.thaiall.com/perlphpasp/source.pl?9116
วางไปบน App: DroidEdit Free แล้ว save as .php
เข้าห้อง /sdcard/pws/www
แล้วเรียกผ่าน chrome ว่า http://127.0.0.1:8080/hello.php
สรุปว่า Palapa web server เป็น host ตัวที่ 12 ที่ทดสอบครับ

ขอจบการเล่าเรื่อง 12 host แต่เพียงเท่านี้

#AndroidStudio ตอนที่ 11 แอพสำหรับ Tablet(Wide)/Smartphone(Narrow) มีตัวเลือกรายการด้านซ้าย รายละเอียดด้านขวา ถ้าจอกว้างพอ

#AndroidStudio ตอนที่ 11 แอพสำหรับ Tablet(Wide)/Smartphone(Narrow) มีตัวเลือกรายการด้านซ้าย รายละเอียดด้านขวา ถ้าจอกว้างพอ

<introduction>
อารัมภบท
การเขียน App สักตัว ที่ต้องการให้มี ซีกซ้าย (Left Pane) เป็นรายการตัวเลือก และซีกขวา (Right Pane) เป็นรายละเอียดหลังคลิ๊กไปที่รายการ ทาง Android เข้าใจเรา ได้เตรียม Template (อ่านได้จาก Add Code from a Template ) มาให้เราเลือก 12 แบบ พบว่า Main/Detail Flow เป็นแบบที่แบ่งจอภาพเป็น Two section สำหรับจอแบบ Wide screen แต่จะหดให้ทำงานกับ One section หากเป็น Narrow screen ซึ่งเค้ากำหนดว่า Wide screen คือ 900dp และผมใช้ Smartphone ก็จะไม่มีโอกาสได้เห็นแบบ 2 section แต่ใน code หากปรับชื่อ folder เป็น 600 dp ก็ทำให้ app รองรับการแสดงผลแบบ Main/Detail Flow บน Smartphone ได้

การเรียนรู้การทำงานของ Template นี้ ก็ต้องหา Activity เข้าไปใส่ แล้วค่อยแกะค่อยไซร้ไป ไม่งั้นจะให้พิมพ์ Hello world! กันทุก Project ก็คงจะจืดแยเลย จึงใส่ตัวเลือกเข้าไป 6 รายการ คือ API Level, Security_patch, width & height, IP Address, Date and Time และ Webview เมื่อต้องทำให้แต่ละกิจกรรมทำงานได้ พบปัญหาว่า บางกิจกรรมใช้ method ใน Dummycontent.java ไม่ได้ แก้ไขโดยไปใส่ใน Activity หลัก ซึ่งปัญหาที่พบบ่อยมี 2 สาเหตุ คือ 1) ฟังก์ชันนั้นต้องเรียกใช้ Context ของ Activity แต่ไม่มีให้ใช้ในคลาสนั้น 2) การเรียกใช้ฟังก์ชัน ไม่สามารถใช้ได้หากอยู่ใน method แบบ static จึงต้องย้ายงานไปทำใน Activity หลัก อาทิ MainActivity.java แล้วเก็บเป็นตัวแปรให้อ้างอิงได้ เมื่อ Dummy ต้องการใช้ ก็อ้างอิงเป็นวัตถุใน Dummy แล้วนึกไปใช้ได้ แต่ Project นี้มี Activity หลักอยู่ใน ItemListActivity.java

ระหว่างพัฒนา และทดสอบ ได้พบกับคำว่า Unfortunately บ่อยเลย เพราะการใช้ method ในที่ห้ามใช้ ระบบปฏิบัติการไม่อาจดำเนินการตามที่คาดไว้ แต่ Build APK ผ่าน ไม่มีปัญหานะครับ ปัญหาไปเกิดตอนประมวลผล ก็ต้องแก้ไขกันไป เพราะเงื่อนไขเยอะมาก หากันจนเจอ หรือหากันให้เจอ เมื่อต้องเจอปัญหาในแต่ละครั้ง

สรุปกระบวนการได้ 13 ขั้นตอน ประกอบด้วย 1) สร้าง Project เลือก Template แบบ Master/Detail Flow 2) ทำให้ item ใน list มีกิจกรรม 3) เพิ่มเกิจกรรมให้ตัวเลือกแต่ละตัว ใน DummyContent.java 4) การได้ ipaddress ต้องปรับ AndroidManifest.xml 5) สร้าง WebView ชื่อ aboutus.xml รับ HTML Tag 6) การเพิ่ม layout แบบ WebView แทน TextView จำนวน 1 ตัวเลือก 7) การหาขนาด Width และ Height ของจอภาพ 8) การหาค่า IP Address 9) การหาวันเวลาของเครื่อง 10) การหาเลขรุ่น API ของ Android ที่มีในโทรศัพท์แต่ละเครื่อง 11) การส่งค่าเข้าตัวแปรแบบตัวเลข และตัวอักษรใน string 12) การอ้างอิงชื่อ id, string, layout, drawable แบบอ้างอิงด้วยตัวแปร 13) การติดตั้ง Android 7.1 บน VirtualBox


ปล. แฟ้ม Project ผมบีบไว้ และแชร์ให้ Download ทั้ง .rar และ .apk ไปทดสอบกัน
ที่ http://www.thaiall.com/android (ผ่าน 4shared.com)

</introduction>
<definition>
นิยามศัพท์

  1. Template คือ แบบฟอร์มที่ยังไม่ได้ใส่เนื้อหา แต่มีเค้าโครง (Layout) หรือกิจกรรม (Activity) ที่จำเป็นมาให้แล้ว ซึ่ง Android มีให้เลือก 12 แบบ สามารถนำมาปรับแต่งเสมือนกับโครงงานที่สร้างขึ้นใหม่ แต่เทมเพลตจะช่วยล่นระยะเวลาในการพัฒนาระบบในระยะแรกให้สั้นลง แทนการเริ่มต้นจาก 0 หรือการนับ 1 ใหม่
  2. Unfortunately คือ ปัญหาที่ไม่คาดหวัง แต่มาปรากฎบนหน้าจออุปกรณ์ของเราได้ ในกรณีที่เกิดขึ้นจากการติดตั้งและใช้แอพที่ยังอยู่ในระหว่างพัฒนา ก็ลบแอพ (Uninstall) แล้วกลับไปไล่ดูเงือนไขของ command หรือ method หรือ class ที่เรียกใช้ อาจใช้บาง method ที่ใหม่เกินกว่า API ในเครื่องจะรองรับ หรือเก่าเกินไป หรือความไม่เข้ากับของการใช้คำสั่ง แต่ถ้าเป็น App ที่พัฒนา และใช้งานมาแล้วระยะหนึ่ง มีคำแนะนำให้ Clear cache and data หรือ ลบ App แล้วลงใหม่ หรือ Factory reset เป็นต้น

</definition>

กำลังเล่าเรื่อง การใช้โปรแกรม Android Studio สู่เพื่อนนักพัฒนา ผ่าน Blog

<process>
กระบวนการในการพัฒนา APP
เพื่อให้ได้แอพที่แสดงผล Main กับ Detail แยกกัน และแสดงผลต่างกันกับอุปกรณ์แบบ Wide screen และ Narrow screen
มีขั้นตอน ดังนี้

1. สร้าง Project เลือก Template แบบ Master/Detail Flow
ตั้งชื่อให้ project ว่า mainanddetail
เป็นตัวอย่างโครงงานที่น่าสนใจ สามารถนำมาปรับเป็นแอพที่ใช้งานจริงได้
หากใช้กับ Narrow screen จะมีเพียง one screen
หากใช้กับ Wide screen จะแบ่งการทำงานเป็น 2 Section
คือ ซีกซ้ายสำหรับรายการเมนู (Option List) และซีกขวาสำหรับรายละเอียดข้อมูล (Detail)
มีแฟ้มน่าสนใจ 9 แฟ้มที่จะเล่าสู่กันฟัง ดังนี้
https://inducesmile.com/android/android-fragment-masterdetail-flow-tutorial-in-android-studio/

1.1 สำรวจแฟ้ม AndroidManifest.xml
พบว่าใน <application> ได้กำหนด activity ไว้ 2 section
เพื่อเรียก .ItemListActivity และเรียก .ItemDetailActivity
โดย .ItemDetailActivity ที่มี parent คือ .ItemListActivity”
แสดงว่า 1) ItemListActivity.java คือ Activity หลัก
และทำงานคู่กับ 2) ItemDetailActivity.java อย่างที่เรียกว่าแยกกันไม่ออกทีเดียว
จะเห็นว่างานเริ่มจากการเรียก 2 Activity แต่จะแสดง Layout จากทั้ง 2 หรือไม่
ขึ้นกับว่าจอภาพที่ใช้เป็นแบบ Wide หรือ Narrow

1.2 สำรวจ Activity ที่ 1 แฟ้ม ItemListActivity.java
พบว่าใน oncreate ได้สั่ง setContentView(R.layout.activity_item_list);
ซึ่งจะไปเรียกให้ Layout แบบ CoordinatorLayout ที่มีอะไรหลายอย่างทำงานร่วมกัน
Activity นี้ควบคุมงานทางด้านซ้าย (Left Pane) คือ รายการตัวเลือก

1.3 สำรวจ Layout ที่ 1 แฟ้ม activity_item_list.xml
โครงร่างหลักสำหรับการวางวัตถุในด้านซ้าย (Left Pane)
มี Root Layout เป็น CoordinatorLayout
ที่ใช้ AppBarLayout กับ FloatingActionButton
ซึ่งพบได้ใน Template แบบ Basic Activity ที่อธิบายในตอนที่ 9 ข้อ 1
แล้วเรียก Layout อื่นให้ทำหน้าที่แสดงตัวเลือกผ่าน FrameLayout และ include
พบว่ามี Layout structure ดังนี้

<CoordinatorLayout>
 <AppBarLayout>
 <Toolbar />
 </AppBarLayout>
 <FrameLayout>
 <include layout="@layout/item_list" />
 </FrameLayout>
 <FloatingActionButton />
 </CoordinatorLayout>

1.4 สำรวจ Layout ที่ 2 แฟ้ม activity_item_detail.xml
โครงร่างหลักสำหรับการวางรายละเอียดในด้านขวา (Right Pane)
หรือเป็น Full Parent หากทำงานบน Narrow Screen
มี Root Layout เป็น CoordinatorLayout เช่นกัน
จะทำหน้าที่แสดงข้อมูลด้านขวาสำหรับจอภาพที่กว้างไม่น้อยกว่า 900 dp
แต่จะเป็น full screen แทน activity_item_list.xml หากน้อยกว่า 900 dp
– การแสดงเนื้อหามีทำงานกับ fragment แล้วนำไปรวมกันใน Layout
ซึ่งมีความสัมพันธ์ระหว่างแฟ้ม java จำนวน 3 แฟ้ม
– การแสดงข้อมูลมีกิจกรรมใน 1) ItemDetailActivity.java ทำหน้าที่รับอะไรจากใครเข้าไป
แล้วพบการเชื่อมกับ 2) ItemDetailFragment.java
ด้วยคำสั่ง arguments.putString(ItemDetailFragment.ARG_ITEM_ID, ..
และ .add(R.id.item_detail_container, fragment) ..
ซึ่ง item_detail_container อยู่ใน Layout activity_item_detail.xml
– หากเข้าไปดูใน ItemDetailFragment.java
พบว่า มีการเชื่อมกับ ARG_ITEM_ID กับ 3) DummyContent.java อีกทีหนึ่ง
มีรายละเอียดที่น่าสนใจอีกมากมายใน DummyContent.java

พบว่ามี Layout structure ดังนี้

<CoordinatorLayout>
 <AppBarLayout>
 <CollapsingToolbarLayout>
 <Toolbar />
 </CollapsingToolbarLayout>
 </AppBarLayout>
 <NestedScrollView android:id="@+id/item_detail_container" />
 <FloatingActionButton />
 </CoordinatorLayout>

1.5 สำรวจ Layout ที่ 3 แฟ้ม item_detail.xml
โครงร่างย่อยสำหรับแสดงเนื้อหาโดยตรง และรับข้อมูลแบบ TextView
ทำงานสำหรับด้านขวา (Right Pane) เท่านั้น
พบว่า TextView ถูกเชื่อมข้อมูลกับ DummyContent.java ผ่านคำสั่งใน ItemDetailFragment.java
คือ ((TextView) rootView.findViewById(R.id.item_detail)).setText(mItem.details)
เมื่อเห็นการทำงานของ Layout นี้ จึงนำไปปรับใช้เป็น WebView ในตอนท้ายของบทความนี้

พบว่ามี Layout structure ดังนี้

<TextView id="@+id/item_detail" /> (แฟ้มนี้มี Tag เดียว)

1.6 สำรวจ Layout ที่ 4 แฟ้ม item_list.xml
โครงร่างย่อยสำหรับรายการตัวเลือก ทำงานด้านซ้าย (Left Pane) เท่านั้น
พบว่า findViewById(R.id.item_list) ถูกเชื่อมเข้า View ใน ItemListActivity.java
แล้วเชื่อมโยงระหว่าง RecycleView กับ DummyContent ผ่าน .setAdapter()
หน้าที่ของ item_list คือ แสดงหน่วยข้อมูล (item) ให้เลือกแบบรายการ (List)
พบว่ามี Layout structure ดังนี้

<RecyclerView id="@+id/item_list" /> (แฟ้มนี้มี Tag เดียว)

1.7 สำรวจ Layout ที่ 5 แฟ้ม item_list.xml (w900dp)
คล้ายกับ 1.6 แต่หากจอภาพเป็นแบบ Wide Screen
รองรับการแสดง FrameLayout ที่กว้าง 900 dp ได้ ก็จะมี 2 Pane
มีการตรวจสอบ และกำหนดค่าให้กับ mTwopane = true
ซึ่งพบใน ItemListActivity.java
หากปรับขนาดจาก 900 dp เหลือ 600 dp ก็จะแสดงผลบน Smartphone ของผมได้
จึงลดขนาดด้วยการ rename folder เป็น layout-w600dp
ผ่านการ Right Click เลือก [Show in Explorer] แล้วก็ rename folder ได้เลย
http://www.appstoremarketresearch.com/articles/android-tutorial-master-detail-flow/

พบว่ามี Layout structure ดังนี้

<LinearLayout>
 <RecyclerView id="@+id/item_list" />
 <FrameLayout id="@+id/item_detail_container" />
</LinearLayout>

1.8 สำรวจ Layout ที่ 6 แฟ้ม item_list_content.xml
โครงร่างย่อยสำหรับแสดงรายการตัวเลือกแต่ละรายการ
ปกติจะมีลำดับตัวเลือก และชื่อตัวเลือก ก็จะเป็นตาม Layout นั้น
ส่วนแฟ้มที่กำหนดขนาด (Dimension) คือ dimens.xml
หากเปลี่ยน <dimen name=”text_margin”> ก็จะมีผลต่อ Layout
ที่อ้างอิงผ่าน layout_margin=”@dimen/text_margin”

พบว่ามี Layout structure ดังนี้

<LinearLayout android:orientation="horizontal">
 <TextView />
 <TextView />
</LinearLayout>

2. ทำให้ item ใน list มีกิจกรรม
พบว่าแฟ้ม DummyContent.java ควบคุมการแสดงรายการตัวเลือก
และกิจกรรมหลังเลือกตัวเลือก
หากจะปรับเปลี่ยนจำนวนตัวเลือก หรือเปลี่ยนชื่อตัวเลือก
จาก 25 รายการเป็น 10 รายการ ก็สามารถทำได้
สามารถเปลี่ยน for ใน static เป็นดังนี้

มองหา
 private static final int COUNT = 25;
 static {
 for (int i = 1; i <= COUNT; i++) {
 addItem(createDummyItem(i));
เปลี่ยนเป็น
 private static final int COUNT = 5;
 static {
 addItem(new DummyItem("1","API Level",makeDetails(1)));
 addItem(new DummyItem("2","SECURITY_PATCH",makeDetails(2)));

3. เพิ่มเกิจกรรมให้ตัวเลือกแต่ละตัว ใน DummyContent.java

มองหา
 builder.append("Details about Item: ").append(position);
 for (int i = 0; i < position; i++) { .. }
 return builder.toString();
เปลี่ยนเป็น
 builder.append("Data ID : ").append(position);
 switch(position){
 case 1:
 builder.append("\nAPI Level = ")
 builder.append(String.valueOf(Build.VERSION.SDK_INT)); // 21
 return builder.toString();

4. การได้ ipaddress ต้องปรับ AndroidManifest.xml
โดยเพิ่ม 2 tag นี้ ก่อนเปิด tag <application>

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

มีตัวอย่างคำสั่งในข้อ 8

 

5. สร้าง WebView ชื่อ aboutus.xml รับ HTML Tag
สร้าง Layout ใหม่ให้มีเพียง WebView คล้ายกับ item_detail.xml
แล้วปรับให้การคลิ๊ปปุ่มบน FloatingActionButton ไปเรียก aboutus.xml
เลือกการเปลี่ยน include ใน activity_item_list.xml
ใช้วิธีการกำหนด ViewFlipper เคยเล่าในตอนที่ 10 ข้อ 1

5.1 ปรับแฟ้ม activity_item_list.xml
เพื่อสลับกันไปมาระหว่างการกดปุ่ม FloatingActionButton
คือเลือกระหว่างแสดง item_list กับ aboutus
หาก include item_list ใน wide screen จะมา 2 section
หาก include aboutus ใน wide screen จะมาเฉพาะ WebView

มองหา
 <include layout="@layout/item_list" />
เปลี่ยนเป็น
 <ViewFlipper
 android:id="@+id/view_flipper"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <include layout="@layout/item_list" />
 <include layout="@layout/aboutus" />
 </ViewFlipper>

https://developer.android.com/reference/android/webkit/WebView.html
https://www.mkyong.com/android/android-webview-example/

5.2 ปรับแฟ้ม ItemListActivity.java
ใน fab.setOnClickListener(new View.OnClickListener() { }
ซึ่งใช้ switch สนับกันสั่ง setDisplayedChild

เพิ่มคำสั่งต่อไปนี้

ViewFlipper vf = (ViewFlipper) findViewById(R.id.view_flipper);
 switch (vf.getDisplayedChild()) {
 case 0:
 vf.setDisplayedChild(1);
 WebView webView = (WebView) findViewById(R.id.webview);
 webView.getSettings().setJavaScriptEnabled(true);
 String mData = getString(R.string.mdata);
 //webView.loadData(mData, "text/html", null);
 webView.loadDataWithBaseURL("file:///android_res/drawable/",
 "<img src='test.jpg' />", "text/html", "utf-8", null);
 break;
 case 1: vf.setDisplayedChild(0); break; }

5.3 เปลี่ยนภาพปุ่ม
เลือก ic_menu_help ที่แสดงเครื่องหมาย ? บน FloatingActionButton
ด้วย app:srcCompat=”@android:drawable/ic_menu_help”

5.4 เขียน HTML แบบใช้ entity reference
คือการใช้ &lt; แทนเครื่องหมาย <

<string name="mdata">
 &lt;html>&lt;body>
 &lt;b>Hello world!&lt;/b>&lt;br/>
 &lt;center>&lt;img src="bridge.jpg" height=200 />&lt;/center>
 &lt;table width=100% bgcolor=yellow>&lt;tr>&lt;td>&lt;center>
 A bridge is in Lampang province, Thailand.
 &lt;/td>&lt;/tr>&lt;/table>
 &lt;/body>&lt;/html>
 </string>

6. การเพิ่ม layout แบบ WebView แทน TextView จำนวน 1 ตัวเลือก
พบว่า มีการส่ง R.layout.item_detail
เข้าไปใน rootView ใน ItemDetailFragment.java
ผ่านคำสั่ง rootView = inflater.inflate(R.layout.item_detail,..
ก็เพียงแต่เปลี่ยนจาก item_detail เป็น aboutus เท่านั้น
เปลี่ยนเป็น rootView = inflater.inflate(R.layout.aboutus,..
แล้วปรับแฟ้ม aboutus.xml ให้คล้าย item_detail.xml ที่มีเพียง Tag เดียว
เพื่อเข้าไปอยู่ใน rootView แล้วแสดงผลร่วมกับ appBarLayout ดังนี้

<WebView xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/webview"
 style="?android:attr/textAppearanceLarge"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:padding="16dp"
 android:textIsSelectable="true"
 tools:context="com.thaiall.www.mainanddetail.ItemDetailFragment" />

โดย rootView ใน ItemDetailFragment.java
จะถูกนำเข้า fragment แล้วรวมกับ container ใน ItemDetailActivity.java
ผ่านคำสั่ง getSupportFragmentManager().beginTransaction()
.add(R.id.item_detail_container, fragment)

7. การหาขนาด Width และ Height ของจอภาพ
ทำใน Activity หลักที่มี Context
แล้วเรียกค่าไปใช้ใน Dummy project ได้

การเรียกใช้ใน Dummy project

import com.thaiall.www.mainanddetail.ItemListActivity;
private static ItemListActivity item = new ItemListActivity();
builder.append(item.screenWidth);

ประกาศตัวแปรไว้ใต้ Class แบบ static

public static int screenHeight = 0;
 public static int screenWidth = 0;

คำสั่งสำหรับหาค่า Width กับ Height ใช้ใน Activity หลัก

// Width=720pixel Height=1280pixel
// DisplayMetrics displayMetrics = getResources().getDisplayMetrics(); 
DisplayMetrics displayMetrics = new DisplayMetrics();
WindowManager wm = (WindowManager) getApplicationContext().getSystemService(Context.WINDOW_SERVICE); 
wm.getDefaultDisplay().getMetrics(displayMetrics);
screenHeight = displayMetrics.heightPixels;
screenWidth = displayMetrics.widthPixels;

8. การหาค่า IP Address

WifiManager wifiMan = (WifiManager) getApplicationContext().getSystemService(Context.WIFI_SERVICE);
 WifiInfo wifiInf = wifiMan.getConnectionInfo();
 int ipAddress = wifiInf.getIpAddress();
 ip = String.format("%d.%d.%d.%d", 
(ipAddress & 0xff),(ipAddress >> 8 & 0xff),
(ipAddress >> 16 & 0xff),(ipAddress >> 24 & 0xff));

9. การหาวันเวลาของเครื่อง

getDateTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(Calendar.getInstance().getTime());

10. การหาเลขรุ่น API ของ Android ที่มีในโทรศัพท์แต่ละเครื่อง

builder.append(String.valueOf(Build.VERSION.SDK_INT)); 
// I-Mobile IQ II 21
builder.append(String.valueOf(Build.VERSION.RELEASE)); 
// 5.0 (Lollipop) or 4.4.2 (Kitkat)

11. การส่งค่าเข้าตัวแปรแบบตัวเลข และตัวอักษรใน string
ตัวอย่างนี้ไม่ได้อยู่ใน project ที่ทดสอบนี้ แต่ค้นมาแล้วอยากเล่าเก็บไว้
จะรับข้อมูลจาก 3 ตัวแปร ที่ผสมระหว่างตัวเลข และตัวอักษร
จึงจะทำให้ข้อมูลสมบูรณ์ ตัวอย่างนี้ตัวแปรจะมีลำดับที่เริ่มจาก 1
ส่งเข้าไปผ่าน method getResources และ getString

<string name="x1">a= %1$d and b= %2$s and c= %3$d</string>
int a = 1024;
String b = "ASCII";
int c = 65536;
String y = getResources().getString(R.string.x1, a, b, c);

12. การอ้างอิงชื่อ id, string, layout, drawable แบบอ้างอิงด้วยตัวแปร
ตัวอย่างนี้ไม่ได้อยู่ใน project ที่ทดสอบนี้ แต่ค้นมาแล้วอยากเล่าเก็บไว้
บางครั้ง มีข้อมูลจำนวนมากใน string หรือ drawable
แล้วต้องการอ้างอิงแบบเขียน code ให้สั้น
ไม่ใช่มี 100 ภาพ ก็เขียน 100 บรรทัด ก็มีเทคนิค หรือ algorithm อยู่ครับ

int n = 1;
String tv ="R.id.x" + n;
int id = getResources().getIdentifier(tv, "id", getPackageName());
TextView v1 = (TextView) findViewById(id);
v1.setText("new value");
// R.layout.v1
// getResources().getIdentifier("v" + 1, "layout", getPackageName());
// R.string.v2
// getResources().getIdentifier("v" + 2, "string", getPackageName());
// R.drawable.v3
// getResources().getIdentifier("v" + 3, "drawable", getPackageName());

13. การติดตั้ง Android 7.1 บน VirtualBox
เริ่มต้นจากการ Download แฟ้ม .iso สำหรับติดตั้ง Android
http://www.android-x86.org/download

มีขั้นตอน ดังนี้

– Installation
– Create/Modify Partitions
แบบนี้เป็นปัญหา Other และ Other/Unknown
แบบนี้ผ่านด้วยดี Windows และ Windows 32 Bits
แบบนี้ผ่านด้วยดี Ubuntu และ Ubuntu 32 Bits
– use GPT = no
– in partition 1
– write in bootable and primary and Quit
– select SDA1 and format in ext4
– install GRUB and /system
– select [run Android-x86]
– Let’s go
– Setup as new
– Checking for update
– Get connected
– Don’t use any network for setup
– continue and Next
– name=android
– Google services > Next
– Anything else? > ALL SET
– Home screen
– chrome + accept policy
– no signin
– click O > Home screen
– click up arrow
– click Terminal emulator
– $ifconfig = ip address 192.168.1.2

</process>

<website_guide>
+ http://benzneststudios.com/../context-android-overview/
+ https://developer.android.com/../string-resource.html
+ https://stackoverflow.com/..using-getresources-in-non-activity-class
+ https://stackoverflow.com/..get-context-on-android
+ https://stackoverflow.com/..use-getsystemservice-in-a-non-activity
+ https://stackoverflow.com/..get-screen-dimensions-in-pixels
+ https://stackoverflow.com/..get-screen-width-and-height
+ https://stackoverflow.com/..getwindowmanager-by-another-java
+ https://www.youtube.com/watch?v=hjY06ZmYl8U
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here

#AndroidStudio ตอนที่ 10 สำรวจ Layout และ properties ที่น่าสนใจ 6 Layout

#AndroidStudio ตอนที่ 10 สำรวจ Layout และ properties ที่น่าสนใจ 6 Layout

<introduction>
อารัมภบท
เกิดข้อสงสัย จึงอยากชวนไปสำรวจ ว่ามี Layout อยู่เท่าไรที่เราทำเป็น Root layout เพราะ Theme: Basic Activity เตรียม CoordinatorLayout มาให้เราใช้ ส่วน Empty Activity เตรียม ConstraintLayout มาให้ เมื่อเข้า Layout Editor หรือ UI Builder เพื่อสร้าง UI แล้วเข้าส่วน Design มองใน Palatte หัวข้อ Layouts จะพบ 9 ตัวเลือก คือ ConstraintLayout, GridLayout, FrameLayout LinearLayout(horizontal), LinearLayout(vertical), RelativeLayout, TableLayout, TableRow, และ  อันที่จริงยังมี Layout มากกว่านี้ อาทิ CoordinatorLayout หรือ AppbarLayout เป็นต้น

ขณะสำรวจ และทดสอบในบทบาท ผู้ใช้โปรแกรม Android Studio ทำการสร้าง Layout ก็ย่อมมีปัญหา ไม่ได้อย่างใจหมายหลายครา ทำให้มีโอกาสสืบค้น และได้พบบทความเกี่ยวกับ Layout ที่ akexorcist.com และ devahoy.com พบว่านักเขียนเล่าอะไรหลายอย่างเกี่ยวกับ Android ทำให้เข้าใจขึ้นมาก ลองไปหาอ่านดูนะครับ

สรุปกระบวนการ ได้ 5 ขั้นตอน ประกอบด้วย 1) สร้าง Project แบบ Basic Activity ไว้เรียก Layout อื่น 2) การปรับ orientation ของ LinearLayout เป็น vertical กับ horizontal 3) การแสดงข้อมูล 3 column โดยใช้ TextView บน LinearLayout 4) การสร้าง relativelayout.xml 5) การทำภาพ overlay แบบ RelativeLayout 6) copy overlay.xml แล้ว paste constraintlayout.xml 7) การสร้าง gridlayout.xml 8) การสร้าง tablelayout.xml

ปล. แฟ้ม Project ผมบีบไว้ และแชร์ให้ Download ทั้ง .rar และ .apk ไปทดสอบกัน
ที่ http://www.thaiall.com/android (ผ่าน 4shared.com)

</introduction>

<definition>
นิยามศัพท์

  1. LinearLayout คือ เค้าโครงเพื่อจัดวางวัตถุแบบเรียงลำดับ เลือกเรียงแบบ ตามแนวตั้ง (Vertical) หรือตามแนวนอน (Horizontal) เป็น Default Layout เมื่อสร้าง Layout XML File ขึ้นใหม่
  2. RelativeLayout คือ เค้าโครงเพื่อจัดวางวัตถุที่สัมพันธ์กัน เชื่อมโยง อ้างอิง อาจอ้างอิงวัตถุอื่น หรืออ้างอิง Parent ก็ได้ การใช้ Layout Editor จะช่วยให้จัดวาง เห็นภาพใน Blueprint ทำได้สะดวกขึ้นแทนการเข้าไปกำหนดใน XML file โดยตรง
  3. ConstraintLayout คือ เค้าโครงแบบเพื่อจัดวางวัตถุแบบใหม่ คล้าย RelativeLayout มาก และ Android สนับสนุนให้ใช้ เป็นเค้าโครงที่เหมาะสำหรับนักพัฒนาที่ไม่ถนัด XML file มี Layout Editor ที่รองรับการจัดวางผ่าน Blueprint และลดจำนวนเค้าโครงที่ซับซ้อนได้
  4. GridLayout คือ เค้าโครงเพื่อจัดวางวัตถุแบบต่อเนื่อง ในช่องที่จัดเตรียมเป็นตะแกรง หรือจะหย่อนวัตถุไปตามตาที่กำหนดได้ ตัวอย่างการใช้ คือ Image Gallery หรือการแสดงรายการ App บนสมาร์ทโฟน ก็แสดงเป็น Grid
  5. TableLayout คือ เค้าโครงเพื่อจัดวางวัตถุ โดยกำหนดเป็น Row กับ Column เหมาะกับการวางข้อมูลจากระบบ Database ที่แบ่งข้อมูลเป็น Record กับ Field ไว้แล้ว แต่จะจัดวางเป็นฟอร์มสำหรับ Input ข้อมูลก็สามารถสั่งขยายช่องด้วย span ได้
  6. CoordinatorLayout คือ เค้าโครงเพื่อจัดวางวัตถุที่แตกต่างรูปแบบในหน้าเดียวกัน อาจมีทั้ง Slide, Panel, Button หรือ Stick และ Animate ก็ทำได้
  7. ViewGroup คือ เป็นกลุ่มของ View ที่ทำหน้าที่จัดวางเค้าโครง มี subclass ทั้งแบบ Direct (19 Layout) และ Indirect (63 Layout) หากต้องการหา Layout ที่ตรงกับความต้องการให้เข้ามาดูรายชื่อ subclass แล้วเข้าไปดู description และ method ได้

</definition>

กำลังเล่าเรื่อง การใช้โปรแกรม Android Studio สู่เพื่อนนักพัฒนา ผ่าน Blog

<process>
กระบวนการในการพัฒนา APP
เพื่อสำรวจการใช้งาน Layout แต่ละแบบ ว่าใช้งานแตกต่างกันอย่างไร
มีขั้นตอน ดังนี้

1. สร้าง Project แบบ Basic Activity ไว้เรียก Layout อื่น
ตั้งชื่อว่า layoutsample แล้วเตรียม menu, string, activity, layout
ในตอนนี้เราจะ include Layout แล้วเลือก include ผ่าน ViewFlipper
ตามที่เล่าใน ตอนที่ 9 ข้อ 3 ว่าเราสร้าง Menu ผ่าน ToolBar ได้
แล้วเพิ่ม include คู่กับ visible หรือ gone หลายรายการ
เพื่อคุมการ select ใน Menu ให้ได้ผลตามต้องการ
ตัวอย่างนี้ขอปรับการเลือกควบคุมสลับ visible กับ gone
เป็นการใช้ ViewFlipper คลุมใน activity_main.xml และ MainActivity.java

1.1 เริ่มจากสร้าง linearlayout.xml เปล่า ขึ้นมาก่อน
เพื่อเตรียมไว้เป็นตัวเลือกที่ 1 เพราะตัวเลือกแรก คือ content_main.xml
ที่มีมากับ Basic Activity แล้วแสดงคำว่า Hello world!

1.2 ปรับ code ใน activity_main.xml
เพื่อเพิ่ม ViewFlipper เข้าควบคุมการ include

มองหา
 <include layout="@layout/content_main" />
 เปลี่ยนเป็น
 <ViewFlipper
 android:id="@+id/view_flipper"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent">
 <include layout="@layout/content_main" />
 <include layout="@layout/linearlayout" />
 </ViewFlipper>

1.3 ปรับ code ใน MainActivity.java
เพื่อเปลี่ยนจากการใช้ if ไปใช้ switch คุมการ setDisplayedChild ที่ต้องการ

มองหา
 if (id == R.id.action_settings) {
 return true;
 }

เปลี่ยนเป็น
 import android.widget.ViewFlipper;
 ViewFlipper vf = (ViewFlipper) this.findViewById(R.id.view_flipper);
 switch (item.getItemId()) {
 case R.id.content:
 vf.setDisplayedChild(0);
 return true;
 case R.id.linearlayout:
 vf.setDisplayedChild(1);
 return true;
 }

1.4 ไปเพิ่ม <item> ใน menu_main.xml และ <string> ใน strings.xml
เพื่อให้มีตัวเลือกสำหรับการคลิ๊กใน menu
เพื่อเลือก case R.id.content และ case R.id.linearlayout
เพราะขณะนี้มี 2 layout ที่พร้อมทำงานใน menu

1.5 ระหว่างสร้าง string พบการปัดบรรทัดที่มีผลกับ layout
โดยตัวอักษรที่ปัดบรรทัด หรือ Line Break ด้วย \n
ปัญหานี้เล่าใน ตอนที่ 8.1 แต่มาพบ \n ในตอนนี้

<string name="datawith2br">a\nb\nc</string>

2. การปรับ orientation ของ LinearLayout เป็น vertical กับ horizontal
เมื่อสร้าง linearlayout.xml พบว่าค่า default ไม่ได้กำหนดว่า orientation เป็นอะไร
แต่ default เป็น horizontal แม้ไม่ได้กำหนดก็ตาม

2.1 ทดสอบเพิ่ม TextView ที่มี @string/data
ได้เพิ่มแบบไม่กำหนด id จำนวน 20 tag
ปัญหาแรก พบว่า ข้อมูลเบียนกันจนแน่นในแถวเดียว เป็นปัญหาเรื่องตำแหน่ง
หากจำนวนข้อมูลน้อยกว่า 20 tag ก็จะแสดงผลได้ปกติ แต่กรณีนี้มากไป
และไม่ได้จัดเรียงแบบ wrap ลงมาบรรทัดต่อไป
นี่เป็นค่า default ของ orientation ที่เป็นแบบ horizontal
อีกปัญหา พบว่า ทั้งใน emulator และ smart phone
บน emulator จะแสดงคำว่า data ทับ AppbarLayout
บน smartphone จะคำว่า data ถูกทับด้วย AppbarLayout

<TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:text="@string/data" />

[ปัญหา]
สรุปว่า พบปัญหาการแสดงผลในทั้ง 2 อุปกรณ์
เนื่องจากต้องการให้ตำแหน่งเริ่มต้นแสดงผลต่อจาก Appbarlayout
ไม่ใช่ทับกันไปมา ระหว่าง TextView กับ Appbarlayout แบบนั้น
[วิธีแก้ไข]
เพิ่ม android:layout_marginTop=”?attr/actionBarSize” ใน layout
ทดสอบกับทั้ง linearlayout.xml และ content_main.xml
แม้จะเปลี่ยน wrap_content เป็น match_parent แล้ว ก็ไม่มีปัญหา

2.2 ทดสอบเพิ่ม android:orientation=”vertical”
* ใน layout แบบ ConstraintLayout หรือกำหนด width=”match_parent”
ผล คือ data ทับกันในตำแหน่งเดิม แสดงว่า ไม่รองรับการกำหนดเป็น vertical
* ใน layout แบบ LinearLayout
ผล คือ เรียงต่อกันมาตามแนวนอน บรรทัดละ 1 คำอย่างถูกต้อง
แม้กำหนดเป็น wrap_content ทุกตัวก็ตาม

 

3. การแสดงข้อมูล 3 column โดยใช้ TextView บน LinearLayout
กำหนดให้ แท่งแรกกว้าง 25% (0.25) แท่งที่สอง 50% (0.5) แท่งที่สาม 25% (0.25)
แก้ไขในแฟ้ม linearlayout.xml เดิม
ไปอ่านมาจาก https://devahoy.com/posts/android-layout-linear-layout/

ปรับ properties ที่ใช้ใน TextView ดังนี้

background="#00ff00" คือ สีพื้นเขียว
padding="5dp" คือ ช่องว่างระหว่างตัวอักษรกับขอบใน
gravity="center" คือ อยู่ตรงกลางของ TextView
layout_width="wrap_content" คือ ขนาดเท่าข้อมูล
layout_height="match_parent" คือ ขนาดเต็มจอ
layout_weight="0.50" คือ กว้าง 50%
layout_marginStart="5dp" คือ เว้นว่างทางซ้าย

4. การสร้าง relativelayout.xml
เลือก Layout XML File ที่มี Root Tag = RelativeLayout
แล้วเพิ่มตัวเลือกเข้าไปใน menu จะได้เรียกมาทดสอบได้ง่าย
แก้ให้ครบทุกจุดนะครับ เพราะมีเยอะเลยที่ต้องแก้ให้สอดคล้องกัน
แม้เป็นตัวเลือกที่ 3 แต่ต้องกำหนด vf.setDisplayedChild(2);
อ่านความหมายของ Layout ที่ devahoy.com
เรียบเรียงได้ว่า LinearLayout และ RelativeLayout
ต่างเป็น View Group เหมือน Container มีไว้รวบรวม Child View หรือ Widget
มีสิ่งที่ต่างกันใน 2 Layout คือ การจัดเรียง
ถ้า LinearLayout ก็จัดเรียงแบบ horizontal หรือ vertical
ถ้า RelativeLayout ก็จัดเรียงอย่างมีความสัมพันธ์ ซึ่งกันและกัน
การจัดเรียงค่อนข้างเป็นอิสระ และเชื่อมโยงตามลำดับ ทำให้นึกถึง linked list

ปรับ properties ที่ใช้ใน TextView ดังนี้

id="@+id/tv1" คือ การตั้งชื่อให้ TextView
layout_toEndOf="@+id/tv1" คือ อยู่ต่อท้าย tv1
layout_alignParentStart="true" คือ ตำแหน่งเริ่มซ้ายของจอ
textSize="16sp" คือ ขนาดตัวอักษร 16
layout_below="@+id/tv1" คือ อยู่ข้างล่างต่อจากภาพ tv1
layout_toEndOf="@+id/tv1" คือ เริ่มต่อจากด้านขวาของ tv1
gravity="center|center_vertical" คือ อักษรอยู่กลาง
layout_alignParentEnd="true" คือ ชิดด้านซ้ายของจอภาพ
layout_alignParentBottom="true" คือ ชิดด้านล่างขอจอภาพ

5. การทำภาพ overlay แบบ RelativeLayout
สร้าง Layout ใหม่ชื่อ overlay.xml และ Root Tag = RelativeLayout
ส่งภาพเข้า drawable ผมเตรียมภาพขนาด 360*640 
เพราะโทรศัพท์ของผมขนาดเท่านี้
https://www.whatismyscreenresolution.com/

ปรับ properties ที่ใช้ใน TextView ดังนี้

android:layout_marginTop="?attr/actionBarSize" คือ ของ RelativeLayout
android:contentDescription="@string/data" คือ รายละเอียดของภาพ 
android:scaleType="fitXY" คือ กำหนดให้ภาพพอดีกับตำแหน่ง X และ Y
app:srcCompat="@drawable/lp01" คือ การใส่ภาพจาก drawable
gravity="center" คือ ข้อความอยู่ตรงกลาง
textSize="60sp" คือ ขนาดตัวอักษร
textColor="#000000" คือ สีตัวอักษร
background="#00ff00" คือสีพื้น
alpha="0.3" คือ การกำหนดระดับความโปร่งแสง
layout_alignParentStart="true" คือ ชิดด้านซ้าย

 

6. copy overlay.xml แล้ว paste constraintlayout.xml
เข้าไปอ่าน blog ของ akeorcist.com เห็นชัดเลยว่า
Android เชียร์ให้ใช้ ConstraintLayout แทน RelativeLayout
เพราะจัดการง่ายผ่าน UI Builder และมีขนาดเล็กกว่า
งานที่เคยทำใน RelativeLayout สามารถแปลงเป็น ConstraintLayout อัตโนมัติ
จึงคัดลอก overlay.xml เป็นวางแฟ้มเป็นชื่อใหม่คือ constraintlayout.xml
เข้า design แล้วคลิ๊กที่ RelativeLayout ใน Component Tree
กด Right Click จะมี Convert RelativeLayout to ConstraintLayout มาให้
แล้วมีให้เลือกทำ Flatten Layout Hierarchy
กรณีของผม ต้องปรับรายละเอียดใน ImageView และ TextView
เพราะ layout เปลี่ยน properties ก็ต้องเปลี่ยน เพี้ยนไปบ้าง

ใน ImageView ก็ต้องทำให้ขอบภาพชิดกับของ parent ดังนี้

app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"

แต่ข้อความใน TextView ถูกเปลี่ยนให้เชื่อมกับส่วนอื่น ทำให้อยู่ตรงกลางของจอ

app:layout_constraintRight_toRightOf="@+id/imageView"
app:layout_constraintLeft_toLeftOf="@+id/imageView"
app:layout_constraintTop_toBottomOf="@+id/textView"
app:layout_constraintBottom_toTopOf="@+id/button"

7. การสร้าง gridlayout.xml
พบว่า GridLayout เป็นเค้าโครงคล้ายตาราง ใส่ข้อมูลเป็นช่องตาม row หรือ column
แล้วมี GridView ที่ช่วยให้การใส่ image เป็น gallery ได้ง่าย
รองรับการใส่ข้อมูลจำนวนมาก มีความเป็นอัตโนมัติผ่านการจัด orientation
Default คือ orientation:horizontal คือ เรียงแนวนอนไปทางขวาจนจบแถว
แล้วขึ้นแถวต่อไป
ขณะทดสอบพบว่า SDK ที่ผมใช้ตัวล่างที่ติดตั้งไว้ คือ API 19
แล้วไม่รองรับ layout_weight in LinearLayout. This is supported in API 21.

ตัวอย่างการใส่ TextView เข้าไปใน Row และ Column ที่กำหนด

<TextView
 android:layout_row="0"
 android:layout_column="0"
 android:id="@+id/textView3"
 android:textSize="16sp"
 android:background="#00ff00"
 android:layout_width="80dp"
 android:layout_height="80dp"
 android:text="@string/data" />

ตัวอย่างการใส่ Button เข้าไปอัตโนมัติ ช่องไหนว่างตาม orientation ก็เข้าไปเลย

<Button
 android:id="@+id/button6"
 android:layout_width="80dp"
 android:layout_height="80dp"
 android:text="@string/data" />

8. การสร้าง tablelayout.xml
เป็นการวางเค้าโครงให้รองรับการใส่ข้อมูลเป็น row กับ column
ทำให้นึกถึงการเขียน Table ในภาษา HTML ที่มี tr กับ td
ทำ span เพื่อขยายพื้นที่ของ cell ได้
เมื่อใส่ TextView ลงไปก็เป็นเพียงข้อมูลที่นำมาต่อกันใน 1 cell
แต่ TextView ที่มี android:layout_weight=”1″ จะมีน้ำหนักเป็น cell
มักต้องใส่ในทุก TextView เพื่อประกาศการเป็น cell

ตัวอย่างการเค้าโครงการวาง Tag ของ TableLayout

<TableLayout>
  <TableRow>
     <TextView android:layout_weight="1">
     <TextView android:layout_weight="1">
  </TableRow>
</TableLayout>

</process>

<website_guide>
https://www.whatismyscreenresolution.com/
http://www.akexorcist.com/..new-android-layout.html
https://devahoy.com/..relative-layout-tutorial/
+ http://www.journaldev.com/..viewflipper-example-tutorial
+ http://www.programcreek.com/..&method=setDisplayedChild
+ https://developer.android.com/../view/ViewGroup.html
https://developer.android.com/guide/topics/ui/layout/grid.html
+ https://developer.android.com/../widget/TableLayout.html
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here

#AndroidStudio ตอนที่ 9 Layout ของการแจ้งเตือน และการสร้าง Layout at Runtime และเมนู กับการแสดงภาพต่อตาม Vertical

#AndroidStudio ตอนที่ 9 Layout ของการแจ้งเตือน
และการสร้าง Layout at Runtime และเมนู กับการแสดงภาพต่อตาม Vertical

<introduction>
อารัมภบท
ความตั้งใจครั้งแรก คือ การวาง Layout ของการแจ้งเตือน โดยแสดง ImageView และ TextView คู่กัน เรียงเป็นบรรทัดลงไปแบบ Vertical แต่พอได้ลงไปวาง Layout พบว่า โปรแกรมแนะนำว่าให้ใช้ Drawable ตามที่เคยใช้ใน ตอนที่ 8 ข้อ 8 พอใช้ตามคำแนะนำ ก็พบปัญหา ความตั้งใจจึงเบี่ยงเบนไปเรื่องการทำ Valign=Top ว่าทำอย่างไรให้ภาพอยู่ในตำแหน่ง Top แล้วก็ไปสนใจการใช้ Layout แบบ RelativeLayout จากนั้นก็กลับมาคิดเรื่อง Notification ว่าควรลื่นไหลขณะ Runtime เหมือนที่เห็นใน FB Message
ก็พบว่าการวาง Layout ใน Android ทำได้ 2 แบบ คือ Declare UI elements in XML และ Instantiate layout elements at runtime เมื่อไปค้นดูก็ไปไม่ถึงไหน ได้แค่การสั่งให้สร้าง Layout at Runtime ใหม่ขึ้นมา พร้อมสร้าง TextView และส่งค่าเข้า TextView ที่สร้างขึ้น

ความเดิมตอนที่แล้ว เคยเล่าเรื่องการใช้ Template : Basic Activity ใน ตอนที่ 8 แต่ข้ามเรื่อง Menu ของ Toolbar ใน AppBarLayout ที่มีความสัมพันธ์กับหลายแฟ้ม ครั้งนี้กลับมาสนใจ และเพิ่มไป 3 ตัวเลือก พร้อมกิจกรรมที่ได้ทดสอบมาแล้วข้างต้น ทั้งหมดยังอยู่ใน 1 Main Layout กับ 1 Main Activity เพราะ Android Studio วางโครงสร้างให้ Activity คู่กับ Layout ส่วน Content Layout ในตัวอย่างครั้งนี้ จะถูกเรียกผ่าน Main Layout
ใช้การ include เข้าไป ก็ต้องใช้ setVisibility(View.VISIBLE); ใน Activity กำหนดให้กับ include แต่ละตัว เพราะไม่มีวิธีส่งชื่อ Layout ให้ include โดยตรง

สรุปกระบวนการได้ 5 ขั้นตอน ประกอบด้วย 1) ทำความรู้จัก CoordinatorLayout ที่มีเสน่ห์ มาพร้อม Snackbar 2) การวางภาพคู่กับข้อความ 6 แบบ เลือกใช้ที่ชอบได้เลย 3) ใส่ Activity ให้กับ Menu ใน Toolbar บน AppBarLayout 4) การสร้าง layout at runtime เพื่อ say hello 5) สร้าง Layout สำหรับแสดง ImageView โดยเฉพาะ
</introduction>

กำลังเล่าเรื่อง การใช้โปรแกรม Android Studio สู่เพื่อนนักพัฒนา ผ่าน Blog

<process>
กระบวนการในการพัฒนา APP

เพื่อนำภาพและข้อความนำเสนอต่อกันเรียงลงมาเป็นแถว การจัดการเมนู การสร้าง Layout ช่วง Runtime และการนำภาพมาเรียงต่อกันตาม Vertical
มีขั้นตอน ดังนี้

1. ทำความรู้จัก CoordinatorLayout ที่มีเสน่ห์ มาพร้อม Snackbar
เริ่มต้นก็สร้าง project ใหม่ แล้วเลือก Basic Activity ตั้งชื่อ ว่า layoutofnotification
ยังมี Template อีกมาก ทาง Android แนะนำว่าสามารถ Add Code from a Template คือ เราไม่ต้องเขียน code จาก 0 เค้ามี Template มาให้เลือกตามชอบ เคยมีอยู่ 10 ตอนนี้มี 12 และอาจเพิ่มขึ้น เลือกแล้วก็จะมี file ที่จำเป็น และเรียกใช้งานได้ในระดับหนึ่ง เราเพียงแต่นำมาปรับเพิ่ม พบว่า หน้า activity_main.xml มี Hierarchy ของ Layout ดังนี้
1. CoordinatorLayout เป็น root layout
2. AppBarLayout และภายในมี ToolBar
3. ConstraintLayout ที่ถูก include แฟ้ม content_main.xml
4. FloatingActionButton ลอยอยู่ที่ตำแหน่ง bottom|end
สำหรับ CoordinatorLayout ที่ถูกเลือกใช้นี้
ทำให้เราได้เห็นการใช้ FloatingActionButton ร่วมกับ Snackbar และ AppBarLayout

 

https://gist.github.com/thaiall/7bfcfeb57ac459b0e664f19337438908

 

ใช้โปรแกรม Android Studio ไม่ทันไร ถาม Update อีก 150 MB
รอไร .. 
เครื่องผมเหลือเนื้อที่ตั้งเยอะ 

 

2. การวางภาพคู่กับข้อความ 6 แบบ เลือกใช้ที่ชอบได้เลย
เดิม activity_main.xml จะ include แฟ้ม content_main.xml
แต่ผมลบไปแล้ว ของเดิมมี ConstraintLayout เป็น Root Layout
กับ TextView ที่เขียนว่า Hello World!
แต่ผมต้องการ LinearLayout ที่ทำ ScrollView ได้
จึงสร้าง content1_main.xml
โดยมี Hierarchy ของ Layout สำหรับ 6 คู่ ดังนี้

 <LinearLayout orientation="vertical">
 <LinearLayout>
 <TextView text="@string/information">
 </LinearLayout>
 <ScrollView>
 <LinearLayout orientation="vertical">
 <LinearLayout orientation="vertical">
 <TextView drawableStart />
 <TextView drawableStart />
 <ImageView />
 <TextView />
 </LinearLayout>
 <LinearLayout orientation="horizontal">
 <ImageView />
 <TextView />
 </LinearLayout>
 <RelativeLayout>
 <ImageView />
 <TextView />
 </RelativeLayout>
 <RelativeLayout>
 <ImageView id="@+id/imageView2" />
 <TextView layout_toEndOf="@+id/imageView2" />
 </RelativeLayout>
 </LinearLayout>
 </ScrollView>
 </LinearLayout>

ถ้าดูผลลัพธ์จากกภาพ ดูโครงสร้าง และเห็น code น่าจะนำไปใช้ต่อได้

https://gist.github.com/thaiall/304e6ddd917dd0350aa57fba72955082

3. ใส่ Activity ให้กับ Menu ใน Toolbar บน AppBarLayout
มีขั้นตอนดังนี้
3.1 วางแผนไว้ในใจ ว่าคลิ๊ก 3 จุดที่มุมบนขวา แล้วมีเมนูไหลลงมา
อยากเห็นอะไร ก็ให้เปิด app, res, menu, menu_main.xml
จากนั้นก็เพิ่มตัวเลือกตาม item ที่ต้องการ แต่ title ต้องเปิดแฟ้ม strings.xml พิมพ์ไปพร้อมกัน

<item
 android:id="@+id/content1"
 android:orderInCategory="100"
 android:title="@string/content1"
 app:showAsAction="never" />

 

https://gist.github.com/thaiall/eb8137794add90145d19daa9d1c2c0d8

3.2 เปิด MainActivity.java ขึ้นมาแก้ไข
มองหา method ชื่อ onOptionsItemSelected(MenuItem item)
เดิมจะมี if (id == R.id.action_settings) ผมก็เปลี่ยนไปใช้ switch จะได้สะดวก
ตัวอย่างนี้ต้องปรับการใช้ include ใน activity_main.xml

switch (item.getItemId()) {
 case R.id.content1:
 findViewById(R.id.content1).setVisibility(View.VISIBLE);
 findViewById(R.id.content2).setVisibility(View.GONE);
 return true;
 case R.id.content2:
 findViewById(R.id.content1).setVisibility(View.GONE);
 findViewById(R.id.content2).setVisibility(View.VISIBLE);
 return true;
 case R.id.layoutRuntime:
 layoutRuntime();
 return true;
 default:
 return super.onOptionsItemSelected(item);
 }

 

3.3 แก้ไขการ include เพราะสั่งไปว่าจะ visible หรือ gone

มองหา
 <include layout="@layout/content_main"
เปลี่ยนเป็น
 <include
 android:id="@+id/content1"
 layout="@layout/content1_main"
 android:visibility="visible" />
 <include
 android:id="@+id/content2"
 layout="@layout/content2_main"
 android:visibility="gone" />

 

https://gist.github.com/thaiall/e55bca08d5927c97dd2dec5367771085

 

4. การสร้าง layout at runtime เพื่อ say hello
เนื่องจากที่ผ่าน 8 ตอนเป็นการใช้โปรแกรม Android Studio
ผ่าน Main_Activity.java เท่านั้น และ layout ก็ไม่ได้มีเพิ่มขึ้นเป็นพิเศษ
ไม่มีการควบคุม Layout ผ่าน Main java เลย
แต่ code สร้าง Layout at runtime สำหรับ
ท่านที่ต้องการ Layout แปลกใหม่ กว่าที่มีไว้ ก็สร้างช่วง Runtime ได้
ได้ตัวอย่างมาจาก
http://www.android-examples.com

private void layoutRuntime() {
 LinearLayout linearLayout = new LinearLayout(this);
 TextView ProgrammaticallyTextView = new TextView(this);
 ProgrammaticallyTextView.setText(R.string.helloworld);
 ProgrammaticallyTextView.setTextSize(16);
 ProgrammaticallyTextView.setPadding(30, 250, 30, 100);
 linearLayout.addView(ProgrammaticallyTextView);
 this.setContentView(linearLayout, new LinearLayout.LayoutParams(
 LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
 }

 

5. สร้าง Layout สำหรับแสดง ImageView โดยเฉพาะ
ใช้ภาพตัวอย่างจาก http://www.thaiall.com/actress/missgrand2017/
หากมีข่าวประกาศ หนังสือ รายงาน พรบ. หรือภาพสาวงาม จะนำมาเรียงต่อกัน
ให้เพื่อนชมผ่าน app บน Android ก็ส่งเข้าไปเลยครับ
ตอนผมทดสอบบน Smartphone มีปัญหาเรื่องจำนวนภาพเยอะ
ใช้ภาพเยอะ ๆ แล้ว error ส่งผ่าน Command line
เชื่อมผ่านเปิดแอพ WiFi ADB ซึ่งบนนั้นอาจมี Bug น่ะครับ
แต่แฟ้ม app-debug.apk นี้ส่งเข้า emulator ได้ผลปกติ
เรื่องสำคัญ คือ properties ของ ImageView เพื่อให้ลงจอภาพพอดี
โดยเฉพาะ scaleType กับ adjustViewBounds

<LinearLayout orientation="vertical">
 <ScrollView>
 <LinearLayout orientation="vertical">
 <ImageView
 android:id="@+id/imageView1"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:scaleType="fitCenter"
 android:adjustViewBounds="true"
 android:contentDescription="@string/data"
 app:srcCompat="@drawable/thai1" />
 </LinearLayout>
 </ScrollView>
 </LinearLayout>

 

https://gist.github.com/thaiall/41e86984b4cabe35392e29fc05107f60

</process>

<website_guide>
+ https://developer.android.com/training/basics/firstapp/
+ http://www.techotopia.com/..User_Interface_in_Java_Code
+ https://stackoverflow.com/..without-setcontentviewr-layout-main
+ https://stackoverflow.com/..button-click-in-android
+ https://stackoverflow.com/..when-button-is-pressed
+ https://stackoverflow.com/..layout-in-android (viewstub)
+ https://developer.android.com/../declaring-layout
+ https://www.androidhive.info/..design-snackbar-example/
+ http://www.android-examples.com/..programmatically-example/
+ https://stackoverflow.com/..layout-on-java-code (setVisibility(View.GONE); and <ViewFlipper>)
+ https://developer.android.com/training/appbar/actions.html
+ https://developer.android.com/guide/topics/ui/menus.html
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here

#windows ตอนที่ 1 ใช้ Web Platform Installer ติดตั้ง PHP + MySQL บน IIS ง่ายล่ะชีวิต

#windows ตอนที่ 1 การแสดงคำว่า Hello World ใน Windows
จากข้อมูลใน MySQL บน IIS

การติดตั้ง IIS 8.5 + Web Platform Installer 5.0 +
PHP5.6.31 + MySQL 5.1 + PHPMyAdmin 4.0.10.20

<introduction>
สวัสดีชาวโลก หรือ Hello World!” ซึ่งผมมีโจทย์ว่า “ต้องการแสดงข้อมูลที่เก็บไว้ใน Database บน Windows ผ่านบริการของ Web Server ต้องทำอย่างไร” ก็มีหลายทางเลือก และต้องใช้กันหลายโปรแกรมเข้ามาช่วยทำให้บริการเหล่านี้เป็นจริืงได้ การทดสอบของผมใช้ Remote Desktop และ VNC ในการเข้า Web Server ก็ได้ความช่วยเหลือจาก คุณเบนซ์ ช่วยดูเรื่องเครือข่าย เปิดให้ผมเข้าจากที่บ้านได้ แล้ว คุณเปรม ก็ช่วยทำให้มี IP จริง เชื่อมกับ Intranet IP ในที่ทำงาน ผ่านการ config ใน Firewall ขอขอบคุณฝ่ายไอทีทั้งสองท่าน น้าาาา

เดี๋ยวนี้ เทคโนโลยีพัฒนาไปเร็วมาก การจะติดตั้ง Web Server (Port 80) และ Database (Port 3306) ก็ไม่ยากที่จะทำแล้ว จะเข้าถึงบริการเหล่านี้ได้ง่าย เพียง click หรือ double click ไม่กี่ที สิ่งสำคัญคือ ผู้สนใจก็เพียงแต่หาอ่าน (read) สิ่งที่ Windows เค้ามีมาให้ (Services) ไม่มีในเครื่อง ก็ไปหา Download แล้วก็ไซร้ (Search) เข้าไปตามความสนใจ ลงลึกไปเรื่อย ๆ ถ้าสนใจซะอย่าง อะไรอะไร ก็ไม่ยาก เพราะอยู่ตรงหน้า หรือหา download ได้อยู่แล้ว

โปรแกรมบน Windows ที่ใช้ ประกอบด้วยดังนี้

  1. IIS 8.5 on Microsoft Windows
  2. Web Platform Installer 5.0
  3. PHP 5.6.31
  4. MySQL 5.1
  5. PHPMyAdmin 4.0.10.20 [4.7.3]
  6. Chrome Browser

</introduction>

<process>
มีขั้นตอนการติดตั้ง และเขียนโปรแกรม ดังนี้

  1. โปรแกรม Remote Desktop เป็นบริการที่มากับ Windows
    ทำให้เราเข้าไปควบคุมจากระยะไกล เป็นที่นิยมกว่าโปรแกรมอื่น (สำหรับผมนะ)
    เพราะโปรแกรมนี้เป็นของ Windows อยู่แล้ว ใช้งานง่าย ไม่ซับซ้อน

    00_remote_desktop.png
    
  2. โปรแกรม VNC เป็นบริการที่ คุณเบนซ์ แนะนำ
    ว่าใช้งานแทน Remote Desktop ทำให้เข้าเครื่องที่ทำงาน
    ขณะนั่งอยู่ที่บ้าน (Work at Home) ความสามารถคล้ายกัน แต่ตัวนี้มีรุ่นทดลอง 30 วัน

    00_vnc.png
    
  3. เราตรวจสอบข้อมูลได้ว่าในเครื่องคอมพิวเตอร์ของเรา
    ปัจจุบันใช้ OS : Windows รุ่นอะไร
    มี RAM เท่าไร ดูใน System เมื่อเข้าผ่าน Control Panel
    นับว่าสิ่งที่ผู้ใช้ Windows ทุกคนคุ้นเคย เพราะอะไรอะไร ก็ต้องเข้าแผงควบคุม

    00_win81_64.png
    
  4. การคลิ๊กที่ปุ่ม Windows หรือปุ่ม Start เดิม
    ถ้า Click ก็จะแสดง Metro UI (User Interface)
    ถ้า Right Click ก็จะแสดงรายการ ที่ต้องใช้บ่อย เริ่มจาก Program and Features

    01_start_by_click.png
    
  5. การเข้า Control Panel
    สามารถเข้าผ่าน Right click ที่ปุ่ม Windows หรือ Windows-X แล้วมองขึ้นไป
    หรือพิมพ์ Control Panel ในช่อง Run หลังกด Windows-R

    02_control_panel.png
    
  6. เครื่องมือบริหาร ก็จะมีอะไรให้บริหารมากมาย
    ผมทราบมาว่าในนี้ต้องมี IIS คือ Web Server ของ Windows
    แต่ไม่พบ ก็ไม่แปลก เพราะเค้าไม่ได้ติดตั้งมาให้แต่แรก
    จึงต้องไปหามาลงแล้ว มีแหล่งเก็บของ Windows ที่มี แต่ยังไม่ได้ลง

    03_administrative_tools.png
  7. ใน Control Panel จะมี Program and Features
    และด้านซ้ายจะพบ Turn Windows Features on or off
    ให้คลิ๊กเข้าไป เพื่อเปิด Feature IIS ให้ทำงาน

    04_program_and_features.png
  8. ไม่เห็นคำว่า IIS แต่เห็น Internet Information Services
    ก็คลิ๊ก Check เพื่อบอกว่าขอให้ติดตั้ง IIS ให้ด้วย
    ก็จะมีรายละเอียดโปรแกรมอีกมา ที่เราจะได้มากับ IIS หรือไม่ได้มาด้วย
    ถ้าไม่คลิ๊กบริการย่อย เค้าก็ติดตั้งเฉพาะ Web Server ซึ่งเป็นบริการที่ผมมองหา
    แต่บริการ FTP Server จะไม่มาด้วย อยากได้ต้องคลิ๊ก Check นะครับ
    เห็นใช่ไหมว่า FTP Server ยังไม่ถูกคลิ๊ก

    05_windows_feature_iis.png
  9. เมื่อติดตั้งโปรแกรม IIS เสร็จแล้ว
    เมื่อเข้า Administrative Tools อีกครั้ง
    จะพบกับ Internet Information Services (IIS) Manager

    06_administrative_tools_iis.png
  10. เมื่อเข้าไปคลิ๊กถึง Default Web Site
    จะพบว่าบริการถูก Start คือ พร้อมให้บริการ เป็น Web Server

    07_iis_start.png
  11. กลับไปที่ Desktop หา Web Browser
    แล้วเปิด http://localhost

    08_localhost.png
  12. ในเครื่องคอมพิวเตอร์ของเราน่าจะลง Web Browser ไว้หลายตัว
    ชื่อเรียกเครื่องก็มีหลายแบบ อาจเรียกว่า localhost
    เป็น local ip ก็ 127.0.0.1 หรือ ip จริงของเครื่องก็ได้ หรือชื่อ host ก็ได้อีก
    ลองเรียกว่า http://127.0.0.1 ก็ได้ครับ

    09_127001.png
  13. ถ้าใช้ Winddows อยู่แล้ว Microsoft มีโปรแกรม Web Platform Installer
    แต่เตรียมโปรแกรมไว้มากทีเดียว ทำให้เราสั่งติดตั้งโปรแกรมในรายการ
    แล้วใช้งานได้ทันที ไม่ต้องไปทำ configuration เอง แบบ manual
    เริ่มต้นก็ไปดาวน์โหลดมาติดตั้งในเครื่องของเราก่อน ฟรีครับ

    10_web_platform_installer.png
  14. ขณะดาวน์โหลด หรือติดตั้งก็รอแป๊ปนึง
    โปรแกรมไม่ใหญ่มาก แต่จะไปช้าอีกครั้งตอนติดตั้ง
    โปรแกรมย่อยที่เราเลือกในภายหลัง

    11_install_web_platform_5.png
  15. มองหาคำว่า Products ด้านบน
    แล้วก็เลื่อนหาโปรแกรมที่เราสนใจ กรณีนี้ ผมสนใจภาษา PHP
    ซึ่งเป็น Server Sided Script ทำงานร่วมกับ IIS
    เมื่อเจอ PHP 5.6.31 ก็คลิ๊ก Add และ Install ด้านล่าง

    12_install_php5631.png
  16. แม้จะเลือก PHP มาตัวเดียว แต่ระบบตรวจสอบว่าต้องลงโปรแกรมใดเพิ่ม
    เค้าเรียก Prerequisites เหมือนตอนเรียนหนังสือ
    จะลงวิชา Project ของปี 4 ต้องลงวิชาของปี 1 ก่อน เป็น pre กันอยู่

    13_download_php5631.png
  17. จากนั้นก็รอ มี 2 progress bar คือ Download กับ Install
    โปรแกรมไม่ใหญ่ก็รอแป๊ปเดียว ขึ้นกับความเร็วเน็ตด้วย

    14_download_and_install_php5631.png
  18. พอลงโปรแกรมเสร็จแล้ว
    ก็จะมีรายงานว่าลงโปรแกรมอะไรไปแล้วบ้าง
    อย่างที่เห็นผมเลือก PHP 5.6.31 ตัวเดียว แต่ชวนเพื่อนมาเพียบเลย

    15_iis_php_finish.png
  19. โปรแกรม IIS มี Root Directory อยู่ที่ C:\Inetpub\wwwroot
    จะเขียนอะไรลงไป ก็เปิดให้เพื่อนมา Download หรือเข้าถึงได้
    แต่ Winddows 8 อาจกำหนด Permission  ว่า User ห้ามเขียน
    แล้วเราก็เป็น User หนึ่ง (บางกรณีเราก็เป็นเพียง User ของเครื่อง)
    ต้องเข้าไปแก้ Security ให้ User เป็นแบบ Full Control

    16_folder_permission.png
  20. เปิดโปรแกรม Notepad แล้วพิมพ์ hello world
    เพราะคิดจะทำให้ใคร ๆ เข้าเครื่องของเรา และเห็นข้อมูลที่เราสร้างไว้

    17_notepad.png
  21. สร้างแฟ้มชื่อ helloworld.php
    แล้วทดสอบเปิดด้วย Web Browser ในเครื่องของเรา
    ยังไม่ต้องไปลองที่ไหนไกลนัก

    18_local_hello.png
  22. ลองเรียกใช้ function phpinfo() เพื่อแสดงข้อมูลของเครื่อง
    ที่ฟังก์ชันนี้พอจะแสดงออกมาได้ ก็เยอะครับ
    แล้ว save as เป็น “phpinfo.php”

    19_notepad_phpinfo_helloworld.png
  23. หากเรียบร้อยแล้ว ผมอยากมี Database ไว้ใช้
    ก็เข้า Microsoft Web Platform Installer ผ่าน Metro UI
    ด้วยการคลิ๊กที่ปุ่ม Windows แล้วมองหาโปรแกรมนี้

    20_metro_screen.png
  24. พบ MySQL Windows 5.1 ผมก็เลือก Add และ Install
    โปรแกรมจะถามให้เราใส่รหัสผ่านของ root
    ก็พิมพ์เข้าไปครับ เช่น “Song:letitbe” หรือ อะไรที่ชอบ

    21_mysql_51.png
  25. หลังติดตั้งเสร็จก็จะรายงานว่า were successfully installed
    MySQL จะไม่ถูกติดตั้งลอย ๆ แต่เชื่อมกับ IIS และ PHP เรียกใช้กันได้เลย
    เพราะเป็นหน้าที่ของ Installer ที่ทำหน้าที่ config ให้อัตโนมัติ

    22_mysql_finish.png
  26. MySQL จะเปิดบริการผ่าน port 3306
    ลองใช้ DOS ตรวจการเปิด port ด้วย
    DOS>netstat -na | find “:3306”

    23_netstat_3306.png
  27. การบริหาร MySQL ผมมักใช้ phpmyadmin
    ใน xampp หรือ appserv เค้าก็ลงมาให้เลย แต่มองหาใน installer ไม่พบ
    จึงต้องหาดาวน์โหลดมาลงเองผ่านเว็บไซต์ของ phpmyadmin.net
    ได้ phpmyadmin รุ่น 4.7.3 ไม่ได้อ่านรายละเอียด
    เห็นเป็นรุ่นใหม่ ผมก็ Download มาเลย

    24_download_phpmyadmin.png
  28. ทำการ unzip ลองห้อง c:\inetpub\wwwroot
    แล้วคาดว่าจะเรียกใช้งานผ่าน Web Server ได้ทันที

    25_phpmyadmin_unzip.png
  29. ลองเปิดจากในเครื่อง มีหน้าจอเปิดรอรับ User และ Password
    ตามที่เคยตั้งว่า User = root Password = Song:letitbe หรือะไรที่ชอบ
    เปิดในเครื่องตนเอง เปิดจากเครื่องอื่นเรียก http://localhost ไม่ได้นะ

    26_phpmyadmin_login.png
  30. ชมพูเต็มจอเลย เข้า google ใช้เลข 574 ไปช่วยหาสาเหตุ ก็ไม่พบ
    มีความเป็นไปได้หลายเรื่องที่เกิดปัญหา
    สิ่งที่ฉุกขึ้นมาในความคิดคือ รุ่นของ phpmyadmin ไม่ลงรอยกับที่อยู่ในเครื่อง
    ไปอ่านเงื่อนไขก็จริงครับ phpmyadmin 4.7.3 ต้องใช้กับ mysql 5.5
    แต่ของผมใช้รุ่น MySQL 5.1 เอง

    27_phpmyadmin_473_error.png
  31. ไปสำหรวจในห้อง phpmyadmin พบแฟ้มเพียบเลย
    ในอดีตต้องมาแก้ไข config เดี๋ยวนี้ไม่ต้องล่ะครับ
    การแก้ไขก็ไม่ยากเลย ไปหา phpmyadmin รุ่นเก่า แล้วลบห้องนี้ทิ้ง

    28_phpmyadmin_folder.png
  32. หลังติดตั้ง phpmyadmin 4.0.10.20 แล้ว
    ผมเรียกจากเครื่องที่บ้านผ่าน IP Address เพราะเครื่องที่ลงโปรแกรมอยู่ที่ทำงาน
    ก็ใช้งานได้ปกติ ไม่ใช่เรียกผ่าน localhost หรือ 127.0.0.1 นะครับ

    29_phpmyadmin_40.png
  33. เริ่มงานจากการสร้างตาราง (Table) ในฐานข้อมูล Test
    มี 1 Field ชื่อว่า Test เป็นแบบ Integer

    30_phpmyadmin_create_table.png
  34. ใส่ข้อมูลที่เป็นตัวเลขเข้าไป 1 ระเบียน
    มีค่าเท่ากับ 5

    31_phpmyadmin_insert_5.png
  35. หากจะให้สมบูรณ์ต้องมีอย่างน้อย 2 Fields
    ตัวอย่างนี้สร้าง ID เป็น Auto_Increment และ Test เป็น Varchar ขนาด 50 ตัวอักษร

    32_phpmyadmin_varcha_2_fields.png
  36. เขียนโปรแกรมด้วยภาษา PHP เพื่อเรียกข้อมูลจากตาราง Test มาแสดง
    โปรแกรมนี้เขียนแบบง่าย ๆ ไม่ซับซ้อน
    ผมแชร์เป็น ต.ย.23 ใน http://www.thaiall.com/php

    33_select_in_wwwroot.png
  37. ผลลัพธ์กรณีเรียกข้อมูลที่มี 1 Field แต่มี 2 Records
    ผ่าน IP Address จริงจากที่บ้าน เข้าที่ทำงาน

    34_select_in_browser.png
  38. ทำการ Insert ข้อมูลเข้าตารางที่มี 2 ระเบียน
    เป็นคำว่า สวัสดีชาวโลก กับ Hello world!

    35_phpmyadmin_insert.png
  39. ข้อมูลเก็บแบบ UTF-8 สามารถอ่านได้ปกติ
    จากใน phpmyadmin ไม่พบปัญหาภาษาไทย
    เดี๋ยวนี้ใคร ๆ ก็ใช้ UTF-8

    36_phpmyadmin_browse.png
  40. เขียนโปรแกรม และเตรียม code ให้รับกับ UTF-8
    ทั้ง charset หรือ set names หรือ encoding ของ source code

    37_select_with_utf8.png
  41. ผลลัพธ์ก็ได้เห็นคำว่า สวัสดีชาวโลก สมดังมุ่งหมาย
    นี่ก็เป็นทั้งหมดที่อยากเล่าให้ฟังครับ .. ชาวโลก

    38_helloworld_in_browser.png

</process>

#AndroidStudio ตอนที่ 8.1 สิ่งที่ทำได้ และไม่ได้ในการใช้ HTML ใน TextView

#AndroidStudio ตอนที่ 8.1 สิ่งที่ทำได้ และไม่ได้ในการใช้ HTML ใน TextView  

<introduction>
หลังทบทวนที่ได้ใช้โปรแกรม Android Studio แล้วพบ ปัญหา และทางออกในหลายวิธี แล้วแบ่งปันในกลุ่มเฟส สมาคมโปรแกรมเมอร์ไทย ก็มีเพื่อนมาร่วมแลกเปลี่ยน แชร์โฮมเพจดี ๆ มาให้อ่าน หลังเขียนเรื่องที่อยากเขียนแล้ว ก็นำเรื่องที่อ่านเพิ่มเติมมาเขียนในข้อที่ 8 มีอะไรอีกมากที่ต้องเรียนรู้ ทั้ง 1) properties อีกอื้อ 2) ต้องเปลี่ยนตนเองตามการเปลี่ยนรุ่นของเครื่องมือ 3) การเลือกใช้เครื่องมือที่เหมาะสมกับงาน

Google เจ้าของ Android Studio ได้เตรียมเครื่องมือไว้เยอะ บางเรื่องบางงานก็ใช้ได้หลายเครื่องมือ ยกตัวอย่างง่าย ๆ สำหรับงานง่าย ๆ ก็มี layout ให้เลือกตั้งเยอะ และตอบโจทย์สำหรับงานง่ายได้ทุก layout แต่ถ้าต้องออกแบบ layout เชิงลึกถึงจะเห็นว่างานแบบลึกนั้น จะต้องใช้ layout แบบใดที่มีคุณสมบัติเฉพาะ และใช้ layout แบบอื่นไม่ได้จริง ๆ

TextView ไม่รองรับ HTML แต่โดยดี จึงมีเรื่องมาเล่า ดังนี้ 1) ใส่ HTML Tag เข้า TextView ใน Layout โดยตรง 2) ใส่ HTML Tag ใน string ที่อยู่ใน strings.xml แล้วอ้างอิงจาก Textview ใน layout 3) การส่ง img ใน strings.xml ไป TextView ใน layout ที่แสดงผลเฉพาะตัวอักษรหนา ส่วนภาพไม่ออก 4) การส่ง img ใน MainActivity.java ไป TextView ผ่าน ImageGetter แบบใช้ได้ 5) การส่ง img ใน strings.xml เข้า MainActivity.java ไป TextView ผ่าน ImageGetter แบบใช้ได้ 6) การส่ง img ใน strings.xml เข้า MainActivity.java ไป TextView ผ่าน ImageGetter แบบสั่ง replace แทนกำหนด Html Tag 7) ปรับ ImageGetter กันดีกว่า 8) การใช้ drawableStart แทน drawableLeft

</introduction>

กำลังเล่าเรื่อง การใช้โปรแกรม Android Studio สู่เพื่อนนักพัฒนา ผ่าน Blog

<process>

1. ใส่ HTML Tag เข้า TextView ใน Layout โดยตรง

ต.ย.1 การใช้ HTML Tag ใน TextView แบบนี้ไม่ได้ เกิด Error : Build ไม่ผ่าน

android:text="<b>hello</b>"

ต.ย. 2 การใช้ Entity Reference ใน TextView แบบนี้ไม่ได้ เกิด Error : Build ไม่ผ่าน

android:text="&lt;b>hello&lt;/b>"

ต.ย. 3 การอ้างอิงข้อมูลมาใช้ ต้องเคยถูกประกาศไว้ใน strings.xml จึงจะถูกต้อง แบบนี้ดี

android:text="@string/data1"

2. ใส่ HTML Tag ใน string ที่อยู่ใน strings.xml แล้วอ้างอิงจาก Textview ใน layout 

การใช้ HTML เขียนใน strings.xml แล้วอ้างไปแสดงผลใน layout.xml ทันที แบบนี้ เป็นวิธีที่ถูกต้อง มีคำแนะนำไว้ใน guide ของ  android.com ว่าสามารถใช้ <b> <i> หรือ <u> ได้ เพื่อประกอบการแต่ข้อความที่แสดงใน TextView

ปัญหา คือ การใส่ img หรือภาพไปพร้อมข้อความใน TextView ต้องเพิ่ม code พิเศษ

<string name="data"><b>hello world</b></string>
android:text="@string/data"

3. การส่ง img ใน strings.xml ไป TextView ใน layout ที่แสดงผลเฉพาะตัวอักษรหนา ส่วนภาพไม่ออก

แบบนี้ไม่พบ error แต่ภาพไม่แสดง ต้องมี code มาช่วย จึงจะแสดงภาพใน TextView

<string name="data"><b>hello world</b> <img src="lp01" /></string>

4. การส่ง img ใน MainActivity.java ไป TextView ผ่าน ImageGetter แบบใช้ได้

บรรทัดที่ 46 มี HTML Tag ที่ทำให้ ตัวอักษรหนา และเรียกภาพมาแสดงได้จริง
ประกาศข้อมูลแบบ String ที่อยู่ภายใน MainActivity.java เอง
แบบที่่ 1 ที่ใช้งานได้ build ผ่าน และแสดงผลถูกต้อง

String mData = "<b>hello</b> <img src=\"lp01\" />";

แบบที่่ 2 ที่ใช้งานได้ เหมือนแบบแรก

String mData = "<b>hello</b> <img src=lp01 />";

แบบที่่ 3 ที่ใช้งานได้ เหมือนแบบแรก

String mData = "<b>hello</b> <img src='lp01' />";

แบบนี้ error ต้องแก้ไขทันที

String mData = "<b>hello</b> <img src="lp01" />";

บรรทัดที่ใช้ได้ทั้ง 3 ตัวอย่างข้างต้น
จะถูกส่งต่อไปให้ class ImageGetter ที่ประกาศใต้ class MainActivity
ก่อนจะส่งภาพให้ TextView ที่อยู่ใน Layout จะใช้ setText( .. )
ก็ต้องแปลงข้อมูลกันก่อน ด้วย Html.fromHtml( .. ) และใช้ ImageGetter ที่นี่
แต่ fromHtml มีหลายรุ่น จึงใช้ IF ตรวจสอบว่ารุ่นไหน ต้องเรียกใช้แบบใด

htmlTextView.setText(Html.fromHtml(mData, new ImageGetter(),null)); 

ตัวอย่าง Code ทั้งหมด 55 บรรทัดที่ใช้ใน MainActivity.java อยู่ข้างล่างนี้

https://gist.github.com/thaiall/bcd1c4a61fd16bf1cfb5dd32fc274d93

5. การส่ง img ใน strings.xml เข้า MainActivity.java ไป TextView ผ่าน ImageGetter แบบใช้ได้

เปลี่ยนจากการกำหนดค่าคงที่ (Constant) เป็นการอ้างอิงค่า (Reference) จาก R.string.data หากไม่แก้ไข MainActivity.java อีก มาดูกันว่าต้องกำหนดข้อมูลใน strings.xml อย่างไร เพื่อทำให้แสดงภาพใน TextView

String mData = res.getString(R.string.data);

ใช้ Entity Reference คือ &lt; ทำให้ภาพออก เห็นตัวอักษา แต่ตัวอักษาไม่หนา

<string name="data"><b>hello</b> &lt;img src="lp01" /></string>

ใช้ Entity Reference คือ &lt; แทน < ทำให้เห็นทั้งภาพ และตัวอักษรหนา

<string name="data">&lt;b>hello&lt;/b> &lt;img src="lp01" /></string>

ใช้ Entity Reference คือ &lt; แทน < แบบไม่มี Quote  หรือ “” ก็ได้

<string name="data">&lt;b>hello&lt;/b> &lt;img src=lp01 /></string>

 

6. การส่ง img ใน strings.xml เข้า MainActivity.java ไป TextView ผ่าน ImageGetter แบบสั่ง replace แทนกำหนด Html Tag

หากไม่ต้องการใช้ HTML Tag ระบุชื่อภาพ แต่ใช้การแทนที่ ก็สามารถเพิ่ม code ใน MainActivity.java ได้ โดยมีตัวอย่างข้อมูลใน strings.xml ดังนี้

 <string name="data">pic01 pic02 pic03</string>

เพิ่มคำสั่ง for สั่ง replace ข้อมูลใน mData หากพบ pic0 ก็ให้เปลี่ยนเป็น Img Tag ตามรูปแบบที่ต้องการ ถือเป็นการลดรูปของข้อมูลภาพใน strings.xml ไม่ต้องพิมพ์ยาว ๆ

String mData = res.getString(R.string.data);
for(int i=1;i<=3;i++) {
 mData = mData.replace("pic0" + i, "<img src=lp0" + i + " />");
}

หากกำหนดข้อมูลใน strings.xml ให้ตัวอักษรเข้ม และปัดบรรทัด
ยังต้องใช้ Entity Reference คือ &lt; แทนเครื่องหมาย < ดังอธิบายในข้อ 5

<string name="data"><b>hello</b><br/>pic01</string>

แม้จะใช้คำสั่ง replace แทนที่ < เป็น &lt; ก็ไม่ทำให้ผลลัพธ์เปลี่ยนแปลง
เหมือนกับไม่เกิดการแทนที่เกิดขึ้น ก็เพียงแต่เล่าว่า วิธีนี้ใช้มาแล้ว

mData = mData.replace("<", "&lt;");
mData = mData.replace("<b>", "&lt;b>");

แล้วถ้าข้อมูลพิมพ์ [ แทนเครื่องหมาย < แล้วสั่ง replace
ผลลัพธ์จะออกมาเป็นการแสดง source code คือ <b>hello</b><br/>และภาพ

<string name="data">[b>hello[/b>[br/>pic01</string>
mData = mData.replace("[", "&lt;");

7. ปรับ ImageGetter กันดีกว่า

7.1 บรรทัดที่ 34 คือ setBounds (.. )
เนื่องจากผมเขียนโปรแกรมทดสอบเกี่ยวกับภาพ เห็นว่าภาพใหญ่เกินไป
จึงปรับให้ขนาดเล็กจิ๋ว กว้าง 48 * 2 =96 pixel สูง 64 *2 =128 pixels
ถ้าต้องการใช้ความกว้างสูงของตัวภาพ แล้วทำให้ใหญ่ 2 เท่า หรือเล็กครึ่งหนึ่ง ก็ทำได้

d.setBounds(0,0,d.getIntrinsicWidth(), d.getIntrinsicHeight());

7.2 หากจะปรับขนาดภาพให้เป็นตามชื่อภาพ
เราก็มีชื่อภาพในตัวแปร source แก้โปรแกรม โดยเปลี่ยนบรรทัด 34 เป็น 4 บรรทัดข้างนี้
แล้วปรับขนาดได้ตามชอบใจ

if(source.equals("lp01"))
    d.setBounds(0,0,48 * 2, 64 * 2);
else
    d.setBounds(0,0,300, 400);

7.3 ปรับการตรวจสอบ id
ตรวจสอบค่าของ getPackageName(); พบมีค่า com.thaiall.www.myapplication
ทำให้โปรแกรมที่เขียนขึ้นสามารถบรรทัดที่ 18 – 21 เพราะมีบรรทัดที่ 17 อยู่แล้ว

String p = getPackageName();

8. การใช้ drawableStart แทน drawableLeft
ได้แชร์ blog ตอนที่ 8 ในเฟสกลุ่ม สมาคมโปรแกรมเมอร์ไทย
แล้วคุณ Somkiat Ake Khitwongwattana แนะนำให้อ่าน Advance Android TextView ที่เขียนโดย Chiu-Ki Chan พอเข้าไปก็เห็นว่ามีคุณสมบัติที่ชื่อ drawableTop, drawableBottom และอีกเยอะที่ทดสอบแล้วใช้ได้เลยใน TextView แต่ drawableLeft ที่น่าจะใช้ได้พบว่า Android Studio ที่ผมใช้เค้าให้เปลี่ยนเป็น drawableStart และ drawableEnd ซึ่งเป็นการเปลี่ยนแปลงตลอดระหว่างการเปลี่ยนรุ่นของเครื่องมือที่ใช้พัฒนา นี่เป็นตัวอย่าง code ที่ปรับมาจากคำแนะนำที่ไปอ่านมา และผมไม่ใช้ lp01 เพราะรูปใหญ่เกิน จึงเลี่ยงไปใช้ ic_insert_emoticon_black_24dp และใน Page ของ Chiu-Ki Chan ยังมี Guide ที่น่าสนใจอีกมาก

<TextView
    android:id="@+id/textView"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/app_name"
    android:drawableStart="@drawable/ic_insert_emoticon_black_24dp"
    android:drawableEnd="@drawable/ic_insert_emoticon_black_24dp"
    android:drawableTop="@drawable/ic_insert_emoticon_black_24dp"
    android:drawableBottom="@drawable/ic_insert_emoticon_black_24dp" />

</process>

สรุปว่าวิธีที่ใส่ภาพ และ html อยู่ข้อ 5 
ส่วนข้อ 6 เป็นการเล่าเพิ่มเติม เรื่อง code

<website_guide>
http://chiuki.github.io/advanced-android-textview/#/
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here

#Android Studio ตอนที่ 8 การใส่ภาพและคำสั่ง HTML ใน TextView ต่างกันทั้ง Java, Layout และ String

#Android Studio ตอนที่ 8 การใส่ภาพและคำสั่ง HTML ใน TextView
ต่างกันทั้ง Java, Layout และ String

<introduction>
อารัมภบท
การทำให้ตัวอักษรหนา หรือ Bold ใน TextView มีเงื่อนไขต่างกันทั้งใน Java, Layout และ String ในตอนนี้จะเน้นว่าทำอย่างไรให้แสดงผลได้ ไม่อธิบายส่วนของปัญหา เพราะการใส่ Html Tag ใน TextView ไม่เหมือนการเขียนเว็บเพจด้วยภาษา HTML พบว่า มีข้อจำกัดมาก ถามกันเยอะใน stackoverflow.com ไปอ่านใน guide ของ android.com พบว่า Supported HTML elements include:

  • <b> for bold text.
  • <i> for italic text.
  • <u> for underline text.

อันที่จริงยังมี Tag ที่ได้รับการสนับสนุนมากกว่านี้ ถ้าอ่านเพิ่มเติมที่ abhiandroid.com และ grokkingandroid.com หากจะให้สรุปก็คงเห็นพ้องกับ Developer หลายท่านว่าการใช้ Html บน Android Studio มี 2 คลาสที่รองรับคือ TextView กับ WebView ถ้าให้ดีควรเลือกใช้ WebView เพราะ TextView สนับสนุนการใช้ HTML น้อยกว่า โดยเฉพาะการใส่ Image ที่ต้องสร้าง Class ImageGetter มาช่วย

แต่ TextView เป็น Class ที่นิยมใช้งานกัน การพยายามใส่ Image และ HTML ลงไปก็น่าจะมาถูกทาง เพียงแต่ Android Studio มี Class อื่นที่สนับสนุนงานด้าน HTML มากกว่า หากใช้งาน HTML จริงจัง คงต้องไปใช้ WebView แต่ถ้างานเล็ก ๆ จะใช้ TextView ก็น่าจะพอรับมือไหว ตัวอย่างในตอนนี้จึงมุ่งมั่นจะใช้ TextView เพื่อแสดง image และ HTML Tag แล้วลองติดตามดูครับ งานนี้ Activity Template เริ่มต้นผมเลือกใช้ คือ Basic Activity

สรุปกระบวนการได้ .. ขั้นตอน ประกอบด้วย 1) ทำความเข้าใจ Project ที่นำมาพัฒนาต่อ 2) ทดลองใส่ Tag:img ใน strings.xml 3) สร้างคลาส ImageGetter เพื่อให้แสดงภาพ ตาม Tag:img 4) สร้าง layout ใหม่ และ string ที่มี HTML tag หลายตัว 5) ทำให้ปุ่มสั่งเปิด Layout ใหม่ได้ และ Tag:img ทำงานได้ 
</introduction>

กำลังเล่าเรื่อง การใช้โปรแกรม Android Studio สู่เพื่อนนักพัฒนา ผ่าน Blog

<process>
1. ทำความเข้าใจ Project ที่นำมาพัฒนาต่อ
สร้าง New Project แบบ Basic Activity ชื่อ imageintextview
จะมีปุ่มที่เป็น FloatingActionButton ใน activity_main.xml
ตามที่เล่าใน ตอนที่ 7 : ข้อ 6 กับข้อ 7 ต่อไปปุ่มนี้ก็จะเป็นปุ่มเปลี่ยนบทความให้กับ App
ให้มองหา app:srcCompat=”@android:drawable/ic_dialog_email”
เปลี่ยนเป็น app:srcCompat=”@android:drawable/ic_media_play”

ส่วนปุ่มนี้จะไปเปิด layout ตัวใด ให้ขึ้นมาแสดงผล
ยังไม่ได้ปรับใน MainActivity.java รอไปทีละขั้น เพราะยังไม่ถึงเวลาของขั้นนี้
แต่เห็นว่า ตอนนี้มี <include layout=”@layout/content_main” />
อยู่ใน activity_main.xml ซึ่งจะเรียก content_main.xml เมื่อเริ่มต้นอยู่แล้ว

2. ทดลองใส่ Tag:img ใน strings.xml
2.1 เริ่มต้นจากการไปหาภาพตัวอย่างมา 5 ภาพ
แล้วใส่ภาพที่หาได้ เข้าไปใน drawable หามา 5 ภาพ คือ lp01.jpg ถึง lp05.jpg
เรื่องนี้เล่าใน ตอนที่ 6 ข้อ 1 มีแบบผ่าน Windows Explorer และผ่าน Android Studio

2.2 ใส่ข้อมูลใน string.xml ประกอบด้วย ข้อความแบบหนา ข้อความธรรมดา และแท็กภาพ

<string name=”data1″>
<b>hello world!</b> Can you see me? <img src=”lp01″ />
</string>

ใน layout_main.xml ที่ Template เตรียมมาให้ใน Basic Activity นั้น
มองหา android:text=”Hello World!”
เปลี่ยนเป็น android:text=”@string/data1″
ถ้า run ตอนนี้
จะเห็นข้อความ Hello world! เป็นตัวหนา
ส่วนข้อความ Can you see me? เป็นตัวธรรมดา
แต่ภาพ lp01 ไม่เห็นว่ามีภาพนี้ออกมา
อธิบายในเบื้องต้น คือ TextView ไม่สนับสนุนการใส่ Tag:img แแบบนี้
ถ้าให้เห็นต้องทำขั้นต่อไป

 

3. สร้างคลาส ImageGetter เพื่อให้แสดงภาพ ตาม Tag:img
3.1 จะใช้งาน Tag:img ใน TextView ได้ต้องมีคลาส ImageGetter ใน MainActivity.java ก็เริ่มจากไปหาคัดลอกคลาสนี้มา แล้วเปลี่ยน packagename เป็น ของท่าน ของผมใช้ com.thaiall.www.imageintextview ใน code กำหนดขนาดภาพที่ผ่านคลาสนี้ให้กว้าง 48*2 และ 64*2 โดยตัวอย่างนี้มี 2 ส่วนคือ ส่วนของ import และส่วนของคลาส ให้สร้างไว้ภายใน class MainActivity
ปล. พอมี ImageGetter แล้ว ในหัวข้อ 3.4 จะเรียกใช้ผ่าน Html.fromHtml ()

import android.text.Html;
import android.os.Build;
import android.graphics.drawable.Drawable;

private class ImageGetter implements Html.ImageGetter {
public Drawable getDrawable(String source) {
int id;
id = getResources().getIdentifier(source, “drawable”, getPackageName());
if (id == 0) {
// the drawable resource wasn’t found in our package, maybe it is a stock android drawable?
id = getResources().getIdentifier(source, “drawable”, “com.thaiall.www.imageintextview“);
}
if (id == 0) {
// prevent a crash if the resource still can’t be found
return null;
}
else {
Drawable d;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //>= API 21
d = getResources().getDrawable(id, getApplicationContext().getTheme());
} else {
d = getResources().getDrawable(id);
}
//d.setBounds(0,0,d.getIntrinsicWidth(),d.getIntrinsicHeight());
d.setBounds(0,0,48 * 2,64 * 2);
return d;
} } }

3.2 การทำให้มีข้อมูลปรากฎใน TextView ผ่าน MainActivity.java
เริ่มต้นจากตั้งชื่อให้ TextView ใน content_main.xml
โดยเพิ่มว่า android:id=”@+id/textView”

3.3 เปลี่ยน data1 และเพิ่ม data2
เพื่อแสดงเทคนิคการจัดการ Tag:img ว่า ใส่แบบ data2 แล้วไม่สำเร็จ
ต้องใส่ Tag:img แบบ data1 ใน strings.xml แล้วใช้ java ช่วยจัดการ

<string name=”data1″>data1 : ok imglp01 imglp02 imglp03</string>
<string name=”data2″>data2 : error <img src=’lp01′ /> <img src=”lp02″ /></string>

3.4 หลังเตรียมข้อมูลใน strings.xml ก็มาเตรียม code ที่จะจัดการกับ Tag:img
โดยเพิ่ม code ข้างล่างนี้ใน MainActivity.java เพื่อจัดการ content_main.xml

import android.content.res.Resources;
import android.widget.TextView;
Resources res = getResources();
String mData1 = res.getString(R.string.data1);
String mData2 = res.getString(R.string.data2); // error here
String mData3 = “data 3 in java file : ok <img src=\”lp04\” /> <img src=lp05 />”;
for(int i=1;i<=3;i++) {
mData1 = mData1.replace(“imglp0” + i, “<img src=lp0″ + i + ” />”);
}
String[] mList ={mData1,mData2,mData3};
String mData = android.text.TextUtils.join(“<br/>”, mList);
TextView htmlTextView = (TextView)findViewById(R.id.textView);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
htmlTextView.setText(Html.fromHtml(mData, Html.FROM_HTML_MODE_LEGACY, new ImageGetter(), null)); // for 24 api and more
} else {
htmlTextView.setText(Html.fromHtml(mData, new ImageGetter(),null)); // or for older api
}

https://gist.github.com/thaiall/9fcead1b4fb4baea6b0751957e5df56f

4. สร้าง layout ใหม่ และ string ที่มี HTML tag หลายตัว 
4.1 สร้าง layout_main.xml
แล้วลาก TextView มาวาง เหมือนใน ตอนที่ 7 ข้อ 4
แล้วเติม ScrollView คลุม TextView ตาม ตอนที่ 7 ข้อ 5 ด้วย
พบว่า id ของ TextView คือ android:id=”@+id/textView2″

4.2 เตรียม myArticle ใน strings.xml ที่มีข้อมูลครบถ้วน
จากการไปอ่านบทความของ grokkingandroid.com ทำให้รู้ว่าใน string ต้องใช้ Entity reference คือ &lt; ตอนปิด Tag ไม่จำเป็นต้องใช้ &gt; ก็ได้ หากส่งเข้า TextView ผ่านฟังก์ชัน setText() ในโปรแกรม Java อย่างที่ใช้คือ MainActivity.java

<string name=”myArticle”>
&lt;h1&gt;ไอทีในชีวิตประจำวัน #611 เมื่อเพื่อนขอใช้โทรศัพท์เข้าสื่อสังคม&lt;/h1&gt;&lt;br/&gt; อาจมีสักครั้งที่เพื่อนสนิท หัวหน้า กิ๊ก หรือแฟนขอยืมสมาร์ทโฟนของเรา …
</string>

https://gist.github.com/thaiall/b220a4cb2b8137f747648c56a5bd086d

 

5. ทำให้ปุ่มสั่งเปิด Layout ใหม่ได้ และ Tag:img ทำงานได้
การปรับเพิ่ม MainActivity.java สำหรับรองรับการสั่งเปิด layout_main.xml
เริ่มจากการเพิ่มคำสั่งใน Activity เมื่อคลิ๊กปุ่ม
โดยเพิ่มใน Block : onClick ของ fab.setOnClickListener(..)
เพื่อคุม FloatingActionButton
ทำตาม ตอนที่ 7 ข้อ 6 มีคำสั่งเพียงบรรทัดเดียวที่ต้องเพิ่ม

setContentView(R.layout.layout_main);

แล้วตามด้วยชุดคำสั่งที่ต้องเพิ่ม

Resources res = getResources();
// for layout_main.xml
String mArticle = res.getString(R.string.myArticle);
for(int i=1;i<=3;i++) {
mArticle = mArticle.replace(“imglp0” + i, “<img src=lp0″ + i + ” />”);
}
TextView htmlTextView2 = (TextView)findViewById(R.id.textView2);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
htmlTextView2.setText(Html.fromHtml(mArticle, Html.FROM_HTML_MODE_LEGACY, new ImageGetter(), null)); // for 24 api and more
} else {
htmlTextView2.setText(Html.fromHtml(mArticle, new ImageGetter(),null)); // or for older api
}

 

 

 

https://gist.github.com/thaiall/1e23a3bcf79ee293b6b4baea14bcfd9a

</process>

<website_guide>
+ http://abhiandroid.com/ui/html
+ http://www.grokkingandroid.com/..html-fromhtml/ (webview better)
+ https://developer.android.com/../string-resource.html (&lt;)
+ https://stackoverflow.com/..strings-xml-in-android (spanned)
https://developer.android.com/studio/projects/templates.html
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here

#AndroidStudio ตอนที่ 7 การมีภาพประกอบบทความแบบเป็นพื้นหลัง และแยกเฟรม เปลี่ยนบทความด้ายการลากซ้ายขวา และเปลี่ยนปุ่มลอยทับ

#AndroidStudio ตอนที่ 7 การมีภาพประกอบบทความแบบเป็นพื้นหลัง
และแยกเฟรม 
เปลี่ยนบทความด้ายการลากซ้ายขวา และเปลี่ยนปุ่มลอยทับ

<introduction>
อารัมภบท
การแสดงข้อมูลก็ต้องมีภาพประกอบสิครับ เป็นเรื่องที่ต่อยอดมาจาก ตอนที่ 5 เล่าเรื่องแสดงข้อมูล และ ตอนที่ 6 เล่าเรื่องแสดงภาพ ตอนนี้จึงนำภาพกับข้อมูลมาแสดงร่วมกัน แต่ตอนนี้เล่าไว้เพียง 2 แบบ คือการแสดงแบบแยกเฟรม กับภาพและข้อความซ้อนกันเหมือนเป็น Background

สิ่งที่น่าสนใจในตอนนี้ คือ การใช้ Navigation แบบลากไปด้านข้างแบบ Swipe Views  ผ่าน ViewPager และการใช้ FloatingActionButton ที่ทำให้ปุ่มรอรับคำสั่งเหนือข้อความ เป็นสิ่งที่มีมาใน Tabbed Activity ทำให้หยิบมาใช้ได้เลย ในตอนนี้ผมได้สร้าง  layout_main.xml แล้วก็เพิ่ม ScrollView คลุม TextView จะได้เลื่อนขึ้นลงได้ และใช้ FrameLayout แบ่งส่วนว่าส่วนไหนควรแสดงภาพ หรือแสดงบทความ

สรุปกระบวนการได้ 8 ขั้นตอน ประกอบด้วย 1) เลือก Tabbed Activity 2) ทำให้กดเลือกบทความจาก string-array 3) การเปลี่ยนภาพประกอบบทความตามเลข Section 4) สร้าง Layout ใหม่ไว้ใช้งาน 5) ทำให้บทความเลื่อนลงมาผ่าน ScrollView 6) ทำให้กดปุ่ม email แล้วเรียก Layout ใหม่ 7) การเปลี่ยนภาพ email เป็น media_play 8) การใช้ FrameLayout แยกส่วนของภาพ และบทความ
</introduction>

กำลังเล่าเรื่อง การใช้โปรแกรม Android Studio สู่เพื่อนนักพัฒนา ผ่าน Blog

<process>
กระบวนการในการพัฒนา APP
เพื่อแสดงบทความ หรือข้อมูล โดยมีภาพประกอบแบบซ้อนข้อความ และแบ่งเฟรม สามารถเลือกบทความต่อไป หรือข้อความที่เหลือผ่านการลากจอภาพทั้ง Vertical (ScrollView) และ Horizontal (Next Article)
มีขั้นตอน ดังนี้

1. เลือก Tabbed Activity
สร้าง New Project แบบ Tabbed Activity ชื่อ imageinarticle
และมี Navigation Style แบบ Swipe Views (View Page)
ที่ Android Studio เตรียมทั้ง Layout และ Activity มาให้แล้ว
พบว่า ใน Layout มี activity_main.xml และ fragment_main.xml
ทดสอบใช้งานใน Smart phone พบว่า
– หน้าหลักมี icon:email และ icon:Toolbar
– คลิ๊ก email จะมี Notification ขึ้นมาว่า Replace with your own action
– คลิ๊ก Toolbar ที่มุมบนขวา ก็จะพบกับคำว่า Settings
– ลากจอไปด้านซ้าย พบหน้าข้อมูลว่า section 2 และ 3 แล้วลากกลับไปขวาก็จะหยุดที่ section 1
– การแสดงทั้ง 3 หน้าเรียกมาจาก fragment_main.xml แต่ใช้ setText ทำให้ข้อความต่างกัน
– โดยหน้าควบคุม Navigation คือ activity_main.xml มีโครงสร้าง Layout สรุปดังนี้

<CoordinatorLayout ..>
<AppBarLayout ..><Toolbar ..></Toolbar></AppBarLayout>
<ViewPager />
<FloatingActionButton />
</CoordinatorLayout>

ส่วนหน้าเนื้อหา fragment_main.xml มีโครงสร้าง Layout สรุปได้ดังนี้

<RelativeLayout ..>
<TextView.. />
</RelativeLayout>

2. ทำให้กดเลือกบทความจาก string-array
เพื่อให้การทดสอบเห็นผลชัดเจน จึงไปหาบทความมา 3 เรื่อง เป็นตัวอย่างสำหรับทำแอพ
แล้วเปิด strings.xml เพื่อส่งบทความเข้าไปใน tag:string-array ตั้งชื่อว่า data
แล้วไปเปิด MainActivity.java
มองหา textView.setText(..) ให้เพิ่ม และ เปลี่ยนเป็น ดังนี้

import android.content.res.Resources;
Resources res = getResources();
String[] mData = res.getStringArray(R.array.data);
textView.setText(mData[getArguments().getInt(ARG_SECTION_NUMBER) – 1]);

ส่วนใน strings.xml ให้นำบทความที่หามาได้ ไปเพิ่มข้อมูลใน strings.xml

<string-array name=”data”>
<item>บทความที่ 611 …</item>
<item>บทความที่ 610 …</item>
<item>บทความที่ 609 …</item>
</string-array>

เพียงเท่านี้บทความทั้ง 3 ก็จะถูกเรียกผ่าน Navigation แบบ ViewPager เรียบร้อยแล้ว

https://gist.github.com/thaiall/4dae3e80398ec868806937fe9ff1e862

3. การเปลี่ยนภาพประกอบบทความตามเลข Section
มีขั้นตอนดังนี้
– เริ่มจากนำภาพ lp01.jpg ถึง lp05.jpg เข้า drawable
– เพิ่ม ImageView เข้า fragment_main.xml ให้อยู่ก่อน TextView

<ImageView
android:id=”@+id/imageView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
app:srcCompat=”@drawable/lp01″ />

– เปลี่ยนค่า width กับ height จะได้ภาพขนาดเล็กประกอบบทความ เช่น 48dp กับ 64dp
– เพิ่ม code ต่อท้าย textView.setText(..) เพื่อให้ภาพเปลี่ยนไปพร้อมข้อมูล

import android.widget.ImageView;
ImageView mImageView = (ImageView) rootView.findViewById(R.id.imageView);
int getV = getArguments().getInt(ARG_SECTION_NUMBER);
String[] List2 ={“lp0”,String.valueOf(getV)};
Resources resimg = getResources();
String mDrawableName = android.text.TextUtils.join(“”, List2);;
//int resID = resimg.getIdentifier(mDrawableName , “drawable”, getPackageName());
int resID = resimg.getIdentifier(mDrawableName , “drawable”, “com.thaiall.www.imageinarticle”);
mImageView.setImageResource(resID);

https://gist.github.com/thaiall/7db6f8048ec674163d501ca5e0155a0f

4. สร้าง Layout ใหม่ไว้ใช้งาน
อยากได้หน้าใหม่ layout ใหม่สำหรับข้อมูลใหม่
– เข้า strings.xml ไปหาคัดลอกบทความที่ 4 เพิ่มแบบ string ตั้งชื่อว่า data4
– เพิ่มหน้า Layout ใหม่ โดยคลิ๊กขวาใน Project Window
สั่ง New, XML, Layout XML File, “layout_main
แล้วกด Finish จะได้แฟ้มชื่อ layout_main.xml
เข้าไปดู Tab:Text ในแฟ้มนี้พบว่ามีเพียง <LinearLayout ..></LinearLayout>
จึงไป Tab:Design แล้วลาก TextView จาก Palette ไปวางใน LinearLayout
แล้วเพิ่มหรือแทนที่คุณสมบัตินี้ android:text=”@string/data4″

5. ทำให้บทความเลื่อนลงมาผ่าน ScrollView
หากทดสอบจะพบว่าข้อมูลเกิน 1 หน้า แต่ Scroll ลงไปข้อมูลส่วนที่เหลือไม่ได้
จึงเพิ่ม ScrollView คลุม TextView ทั้งใน layout_main.xml และ fragment_main.xml

<ScrollView android:layout_width=”wrap_content” android:layout_height=”wrap_content”>
<TextView … ที่นี่ />
</ScrollView>

เมื่อใส่ Tag แล้วก็ทดสอบ Run ข้อมูล 3 หน้า น่าจะเลื่อนลงไปด้านล่างได้แล้ว
ส่วนหน้าใหม่ยังทดสอบไม่ได้ เพราะยังไม่กำหนดให้ layout ใด ๆ ถูกเรียกมาแสดง

https://gist.github.com/thaiall/a2cc3ea288cf98bac57f559a862b1cad

6. ทำให้กดปุ่ม email แล้วเรียก Layout ใหม่
ปรับแก้ปุ่ม email ให้เรียก layout_main.xml ที่สร้างใหม่มาแสดง
แก้ไขโดยทำหมายเหตุ หน้าคำสั่งที่สั่งแสดง Notification

// Snackbar.make(view, “Replace with your own action”, Snackbar.LENGTH_LONG)
// .setAction(“Action”, null).show();

แล้วเพิ่ม method เรียก layout มาแสดง

setContentView(R.layout.layout_main);

7. การเปลี่ยนภาพ email เป็น media_play
ตอนนี้ปุ่ม email ก็มีหน้าที่เรียก layout_main.xml มาแสดงแล้ว
ดูรายการภาพที่คล้าย ic_dialog_email ที่
http://gae.darshancomputing.com/android/1.5-drawables.html
พบ ic_media_play

8. การใช้ FrameLayout แยกส่วนของภาพ และบทความ
ขณะนี้ข้อมูลใน layout_main.xml ยังไม่มีภาพประกอบ
จึงวางแผนว่าจะแบ่งเป็น 2 ซีก คือ ซ้ายกับขวา ให้ซ้ายแสดงภาพ 3 ภาพ
ส่วนขวาเป็นข้อมูลที่ scroll ได้เหมือนเดิม

<LinearLayout..>
<FrameLayout..>
<ImageView.. android:scaleType=”fitStart” />
<ImageView.. />
<ImageView.. android:scaleType=”fitEnd” />
</FrameLayout>
<FrameLayout..>
<ScrollView..><TextView.. /></ScrollView>
</FrameLayout>
</LinearLayout>

https://gist.github.com/thaiall/78ba38a6ef837a5e9bd44c22c1ca0d38

</process>

<website_guide>
+ http://abhiandroid.com/ui/html
+ https://gist.github.com/Kishanjvaghela/
+ https://medium.com/../android-textview-and-image-loading-from-url
+ https://stackoverflow.com/../getdrawable-deprecated-api-22
+ https://stackoverflow.com/../display-inline-images-from-html
+ https://stackoverflow.com/../display-image-in-androids-textview
+ https://developer.android.com/reference/android/text/Html.html
+ http://stacktips.com/tutorials/../display-html-in-android-textview
+ https://developer.android.com/../string-resource.html
+ https://developer.android.com/../arrays.html
+ https://google-developer-training.gitbooks.io/..
+ http://www.thaiall.com/android
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here

#AndroidStudio ตอนที่ 6 การใช้ชื่อภาพแบบซีรี่กำหนดลำดับการแสดงภาพผ่านคลาส TextUtils แทน String.join

#AndroidStudio ตอนที่ 6 การใช้ชื่อภาพแบบซีรี่กำหนดลำดับการแสดงภาพ
ผ่านคลาส TextUtils แทน String.join

<introduction>
นอกจากข้อมูล (String) ที่เล่าไปก่อนหน้านี้ ก็ตามด้วยเรื่อง ภาพ (Image) เข้ามาประกอบการนำเสนอ เคยเล่าในตอนที่ 4 แสดงข้อมูลธรรมดาผ่าน TextView กับตอนที่ 5 แสดงข้อมูลผ่าน NavigationView ที่ทำให้ข้อมูลดูลื่นไหลได้ก็ด้วยการใช้คลาส ScrollView เพื่อทำ Scrolling ได้ เมื่อไปค้นดูพบว่ามีนักพัฒนาเขียนอะไร ทิ้ง Question & Solution ไว้มากมายใน stackoverflow.com คำตอบส่วนใหญ่ผมก็ได้จากที่นั่นหละ

ค้นเรื่องภาพ ก็ไปอ่าน Blog ของ akexorcist.com เล่าเรื่อง Drawable Resource และแนะนำเรื่อง Android Drawable Importer ก็คงต้องหาโอกาสไปอ่านสักวัน แต่ตอนนี้จะเน้นการส่งภาพเข้า Android Studio และนำมาแสดงผลอย่างง่าย คำว่าง่าย ก็ต้องดูว่างง่ายแบบ Front-End หรือ Back-End ทีแรกว่าจะทำภาพ slide ง่าย ๆ แต่ผมตั้งโจทย์ไว้ว่าจะทำ Layout ให้ง่ายที่สุด

งานนี้เลยต้องปรับ Back-End ให้ Front-End ทำงานได้ง่าย สรุป คือ 1) เตรียมเฉพาะ TextView มาเก็บลำดับภาพ และ 2) ImageView มาเก็บภาพ เพียง 2 คลาส แล้วแทนที่ภาพใหม่ทับที่เดิมไปเรื่อย ดังนั้นจะทำงานนี้ให้สำเร็จต้องเข้าไปเขียน Java เยอะหน่อย ไปเจอปัญหาเรื่อง String.join ที่ไม่มีให้ใช้ กว่าจะยอมรับไปใช้ TextUtils.join ก็ไล่อ่าน Blog จนมั่นใจว่าเราต้องเปลี่ยนคำสั่งเชื่อมต่อ String กันแล้ว
</introduction>

<process>
กระบวนการในการพัฒนา APP
เพื่อคลิ๊กไปบนภาพ แล้วเปลี่ยนเป็นภาพต่อไป ไหลไปเช่นนี้วนไปไม่รู้จบ
มีขั้นตอน ดังนี้

1. สร้าง New Project แบบ Empty Activity
เพราะไม่ต้องการความเป็นอัตโนมัติมากนัก ปรับเองบ้าง เมื่อ Project พร้อมทำงานแล้ว
ก็เข้าไป Right Click ที่ res แล้ว New Folder ชื่อ drawable-mdpi
หลังจากนั้นในกรณีมีภาพในเครื่องคอมพิวเตอร์ที่พร้อมนำมาใช้
สำหรับผมเตรียมภาพ lp01.jpg ถึง lp05.jpg แล้ว
ภาพทุกภาพมีขนาด 480*640 เป็นภาพแนวตั้ง
ก็ให้ไปเปิดรายการภาพด้วย Windows Explorer
แล้ว Right Clip บนภาพที่เตรียมไว้ในเครื่องคอมพิวเตอร์ด้วย Windows Explorer
เลือก copy ซึ่งเลือกได้หลายภาพพร้อมกัน โดยใช้ปุ่ม ctrl หรือ shift เข้าช่วย

1.1 วิธีแรก เปิด Project ใน Android Studio แล้วส่งเข้าไป
โดยกลับไปกด Right Clip บน folder : drawable ใน Project
เลือก paste
จะมี Windows ขึ้นถามว่าลงในห้อง drawable หรือ drawable-mdpi
ก็ให้เลือก drawable-mdpi แฟ้มที่ลงไปในห้อง drawable จะมี (mdpi) ต่อท้าย

1.2 วิธีที่สอง เปิด Folder ด้วย Windows Explorer แล้วส่งเข้าไป
เพราะ Project ของ Android Studio ไม่ลึกลับ เห็น Folder Structure คล้ายกัน
ของผมเข้าไปที่ C:\Users\[User Name]
\AndroidStudioProjects\[Project Name]\app\src\main\res\drawable-mdpi
เคย copy ภาพมาแล้ว ก็ paste ได้เลย เมื่อกลับไปเปิดดูใน Android Studio
ก็เห็นว่าภาพเข้าไปอยู่เหมือนเรานำเข้าผ่าน Android Studio ในข้อ 1.1 นั่นหละ

2. เข้า activity_main.xml จะเห็น Layout ของแอพ มีเพียง TextView ตัวเดียว
เปลี่ยนคำว่า “Hello World!” เป็น “1” เตรียมใช้เก็บตำแหน่งภาพแบบซีรี่
แล้วเข้า Tab:Design ถ้าปัจจุบันอยู่ใน Tab:Text
มองหา Palette, Images, ImageView ลากไปวางไว้บนจอภาพ
เป็นการเพิ่มวัตถุลงไปในจอภาพของเราอีก 1 รายการ
จากนั้นจะมีหน้าต่างมาให้เลือกภาพ ก็คลิ๊กที่ภาพ lp01 แล้วกด OK
เท่านี้แอพของเราก็จะมีภาพมาแสดงผลแล้ว

3. เข้า Tab:Text ของ activity_main.xml แล้วปรับ code ดังนี้
– ลบ app:layout ใน TextView ออกทั้งหมด
– ลบ tools:layout ใน ImageView ออกทั้งหมด
– เพิ่ม android:id=”@+id/textview” ให้กับ TextView
– ย้าย code ImageView ขึ้นมาด้านบน อยู่ก่อน TextView น่าจะเห็นเลข 1 ทับภาพ
เท่านี้ก็จะเห็นภาพอยู่ข้างหลัง และมีตัวอักษร 1 ลอยเหนือภาพที่มุมบนซ้าย

4. ไปเพิ่ม Activity ใน MainActivity.java จะอธิบายเฉพาะที่พิเศษ
ส่วน code ทั้งหมด ดูภาพรวมได้จาก gist ด้านล่าง
สิ่งที่ทำคือ เพิ่ม import และ code ใต้ class และ method ดังนี้

4.1 การแสดงข้อความเหนือภาพ เมื่อคลิ๊กภาพ เหมือน Notification เลย
แต่ code 5 บรรทัดนี้
บรรทัดแรก แปลงตัวอักษรจาก TextView เป็น Integer แล้ว + 1 จะได้เลขสำหรับเลื่อนภาพ
บรรทัดที่สอง มีภาพเตรียมไว้ 5 ภาพคือ lp01 ถึง lp05 คุมว่า ถึงเลข 5 ก็วนมาที่ 1 อีก
บรรทัดที่สาม เตรียม List ไว้ทำงานคู่กับ TextUtils.join เพื่อต่อ String
บรรทัดที่สี่ ทำการต่อ String จะได้ข้อความที่ครบถ้วน
บรรทัดสุดท้าย ใช้คลาส Toast แสดงข้อความแบบ Notification ว่าตอนนี้ถึงภาพไหน

int getV = Integer.valueOf(mTextView.getText().toString()) + 1;
if(getV > 5) { getV = 1; }
String[] List1 ={“เลื่อนไปภาพต่อไป ภาพที่ “,String.valueOf(getV)};
String s = TextUtils.join(” “, List1);
Toast.makeText(MainActivity.this, s , Toast.LENGTH_LONG).show();

4.2 การเปลี่ยนภาพใน ImageView
บรรทัดแรก เตรียมข้อความใน List
บรรทัดที่สอง นำสิ่งที่อยู่ใน List มาต่อกันด้วย TextUtils.join เป็นชื่อภาพ
บรรทัดที่เหลือ นำชื่อภาพที่เป็น String ส่งให้กับ

String[] List2 ={“lp0”,String.valueOf(getV)};
s = TextUtils.join(“”, List2);
Resources res = getResources();
String mDrawableName = s;
int resID = res.getIdentifier(mDrawableName , “drawable”, getPackageName());
mImageView.setImageResource(resID);

4.3 สุดท้าย หลังแสดง Notification และเปลี่ยนภาพแล้ว ก็ต้องส่งเลขตัวใหม่ที่ +1 เข้า TextView มี method setText มาช่วย ตามตัวอย่างข้างล่างนี้เลย

mTextView.setText(String.valueOf(getV));

 

https://gist.github.com/thaiall/180de945ef049198d260a08ae20a47cf

</process>

<website_guide>
+ http://www.android-examples.com/set-onclicklistener-on-imageview-in-android-example/
+ http://www.akexorcist.com/2016/07/best-practice-for-android-drawable-resource-management.html
+ https://developer.android.com/guide/practices/screens_support.html
+ http://www.thaiabc.com/lovelampang/nw/index.php
+ https://www.javatpoint.com/java-string-join
+ https://developer.android.com/reference/android/text/TextUtils.html
</website_guide>

หมายเหตุ 
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here