#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

 

 

ใช้โปรแกรม 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 น่าจะนำไปใช้ต่อได้

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" />

 

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" />

 

 

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>

 

</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>

This slideshow requires JavaScript.

#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 อยู่ข้างล่างนี้

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
}

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>

 

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
}

 

 

 

</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 เรียบร้อยแล้ว

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);

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 ใด ๆ ถูกเรียกมาแสดง

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>

</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));

 

</process>

This slideshow requires JavaScript.

<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

#AndroidStudio ตอนที่ 5 สร้างปุ่ม Close App แบบ VectorDrawable ตัวปุ่มภาพหามาได้หลายวิธี และการสั่งเรียกบทความต่างกัน

#AndroidStudio ตอนที่ 5 สร้างปุ่ม Close App แบบ VectorDrawable
ตัวปุ่มภาพหามาได้หลายวิธี และการสั่งเรียกบทความต่างกัน

<introduction>
เคยเห็นแอพทั่วไป มีปุ่ม Close และเรียก String มาแสดงเยอะหน่อย
เมื่อมองหาแอพเริ่มต้น เพราะผมจะไม่เริ่มต้นกับแอพเปล่าแน่
เนื่องจาก Android Studio เค้ามีโครงมาให้แล้ว
แล้วก็ได้พบกับ Project เริ่มต้นชื่อ Bottom Navigation Activity
ที่เตรียมปุ่มมาให้ใน NavigationView จำนวน 3 ปุ่ม
ผมจึงเปลี่ยนภาพจากปุ่ม Home เป็นภาพปุ่ม Close
ตัวภาพเป็นแฟ้มแบบ xml หรือที่เรียกว่า VectorDrawable
มีฐานมาจากภาพแบบ SVG หรือ PNG ยิ่งค้น และอ่านก็ยิ่งสนุก
เพราะมีทางเลือกให้หลายทาง
แต่ Android Studio เตรียมภาพไว้ให้ตั้ง 923 ภาพแล้ว
พอได้ภาพถูกใจแล้ว แล้วก็ใส่ Activity คือ สั่ง close application
ส่วนอีก 2 ปุ่มให้เรียกบทความที่ 610 กับ 611 มาใส่ใน TextView และมี ScrollView
ตามที่เคยเล่าในตอนที่ 4 แล้วนั้น
</introduction>

<process>
กระบวนการในการพัฒนา APP
เพื่อสั่งให้ปุ่มทำงาน และการเลือกภาพประกอบปุ่มที่เป็น VectorDrawable จาก SVG ในหลายวิธี และแสดงบทความตามปุ่มที่กด
มีขั้นตอน ดังนี้

1. เลือกสร้าง New Project แบบ Bottom Navigation Activity
ชื่อ controlbutton
แล้วเข้าไปสำรวจใน activity_main.xml ดูใน ComponentTree
พบ Tag ที่เค้าสร้างไว้ 4 Tag
โดย Tag ที่คุมทุกอย่าง คือ container (LinearLayout)(vertical)
ประกอบด้วย content(FrameLayout) กับ navigation (BottomNavigationView)
และพบ message(TextView) อยู่ใน content(FrameLayout)
สั่ง Build APK ก็ไม่พบปัญหาอะไร และ run ได้ปกติ มีกำลังใจแล้วครับ

2. การใส่ Data ใน TextView เพื่อจะได้สั่ง Scroll แบบ Vertical ไปดูด้านล่างได้
เริ่มจากสร้าง

<string name=”data1″>ข้อมูลที่นี่ มาจากกบทความ 611</string>

ใน app, res, values, strings.xml
แล้วเรียกใช้ใน TextView ว่า android:text=”@string/data1″ />

3. แม้จะมีข้อมูลมากพอแล้ว แต่ผลการทดสอบพบว่า Scroll ไม่ทำงาน
หน้าจอยังไม่รองรับการ Scroll ไปหาข้อมูลส่วนที่เหลือไม่ได้ เห็นหน้าเดียว
แก้ไขโดยเปิดแฟ้ม activity_main.xml
แล้วเพิ่ม ScrollView คลุมหัวท้ายของ TextView

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

 

4. ในกล่อง BottomNavigationView บน Smartphone หรือ Emulator
จะพบ 3 Icon ด้านล่าง : Home + Dashboard + Notifications
แต่คลิ๊กเข้าไปก็เห็นว่าข้อความใน TextView เปลี่ยนไปตามปุ่มกดเท่านั้น
ไปดูในแฟ้ม MainActivity.java พบส่วนหนึ่งของ code
ที่สั่ง setText ให้เปลี่ยนไปตามการ switch ของ ItemId ที่รับมา
แล้วพบการประกาศ title_home หรือ R.string.title_home
ถูกกำหนดไว้ในแฟ้ม strings.xml เช่นเดียวกับตัวอื่น และ data1
จะเปลี่ยนคำว่า home เป็น close ก็ต้องเปลี่ยนที่แฟ้มนี้ด้วย

5. ถ้าเปลี่ยนจากปุ่ม home เป็น close ต้องทำดังนี้
– ใน app,res,values,strings.xml เปลี่ยนจาก home เป็น close ให้หมด
– ใน app,java,[package name],MainActivity.java เปลี่ยนจาก home เป็น close ให้หมด
– ใน app,res,menu,navigation.xml
เปลี่ยนจาก home เป็น close ให้หมด ยกเว้น @drawable/ic_home_black_24dp
เพราะใน project ยังไม่มีภาพ close เลย

6. เกี่ยวกับภาพปุ่มแบบ Vector มีเรื่องเล่าดังนี้
6.1 เปิดเว็บไซต์ค้นหาภาพปุ่ม close แบบไม่ต้องลงมือทำเอง
พบ https://github.com/mtotschnig/MyExpenses/blob/master/
พบแฟ้มภาพ ic_menu_close_clear_cancel.xml
ให้ copy code ไว้
แล้ว right click เหนือคำว่า drawable, new, file
แล้วพิมพ์ชื่อแฟ้ม ic_menu_close_clear_cancel.xml
ให้ paste code ลงไปในแฟ้มที่สร้างใหม่ จะเห็นรูปกากบาทใน preview ทันที

6.2 ใน Android Studio มีบริการ icon ให้เลือกเพียบ
Right click บน app, New, Vector Asset, Material icon
คลิ๊กภาพ Android ที่อยู่หลังคำว่า icon มีให้เลือก 923 ภาพ
ถ้าเลือกแบบ chevron left แล้วกด next ก็จะได้ภาพ
ไปอยู่ใน app, res, drawable
และ These icons are available under the Apache License Version 2.0

6.3 หากไปได้แฟ้มภาพ .svg ที่สร้างจากที่อื่นมาแล้ว
ก็นำเข้าผ่าน Android Studio ได้โดยง่าย
ในหน้า Vector Asset ก็เลือก Local File
เลือกแฟ้มจากในคอมพิวเตอร์ แล้วกด next ก็จะได้ภาพ
ไปอยู่ใน app, res, drawable เช่นกัน

6.4 ข้อมูลภาพแบบ Vector Drawable ที่เห็นกันนี้วาดเองก็ได้
มี Tool สำหรับวาดแบบ Online
ที่ http://editor.method.ac/ สั่ง Save ได้แฟ้ม .svg
แล้วแปลงแฟ้ม .svg เป็น xml สำหรับ android
ที่ http://inloop.github.io/svg2android/

<?xml version=”1.0″ encoding=”utf-8″?>
<vector xmlns:android=”http://schemas.android.com/apk/res/android”
android:width=”24dp”
android:height=”24dp”
android:viewportWidth=”24″
android:viewportHeight=”24″>
<path
android:fillColor=”?colorControlNormal”
android:pathData=”M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59
19 19 17.59 13.41 12z” />
<path
android:pathData=”M0 0h24v24H0z” />
</vector>

7. เมื่อได้ภาพ Vector สำหรับ Android มาแล้ว
เข้า app,res,menu,navigation.xml เพื่อเปลี่ยนสิ่งที่ทำค้างไว้
มองหา @drawable/ic_home_black_24dp
เป็นเป็น @drawable/ic_menu_close_clear_cancel
ถือว่าจบขั้นตอนการเปลี่ยนภาพ icon จาก home เป็น close

8. เพิ่ม Activity ให้กดปุ่ม Close เพื่อสั่งปิด Application หรือปิดตัวเอง
เปิดแฟ้ม MainActivity.java
มองหา case R.id.navigation_close:
mTextMessage.setText(R.string.title_close);
return true;
เปลี่ยนเป็น case R.id.navigation_close:
finish();
System.exit(0);
return true;

9. ทำให้ปุ่ม สั่งเรียกบทความที่ต่างกัน ปุ่มหนึ่งเรียก 610 อีกปุ่มก็เรียก 611
ถ้ากดปุ่ม notification ใน navigation
ให้แสดงบทความที่ 611 จาก data1 เหมือนค่า default
กดปุ่ม dashboard
ให้แสดงบทความที่ 610 จาก data2
ก็ให้ไปเพิ่มบทความใน strings.xml คือ data2 เพราะ data1 มีแล้ว
แล้วมาแก้ MainActivity.java
มองหา case R.id.navigation_dashboard:
mTextMessage.setText(R.string.title_dashboard);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.title_notifications);
return true;
เปลี่ยนเป็น case R.id.navigation_dashboard:
mTextMessage.setText(R.string.data1);
return true;
case R.id.navigation_notifications:
mTextMessage.setText(R.string.data2);
return true;

ทั้ง project และ apk เอาไปลองกันได้ที่
https://www.4shared.com/folder/AgIkeXaS/android.html

</process>

<website_guide>
+ http://editor.method.ac/
+ http://inloop.github.io/svg2android/
+ https://github.com/mtotschnig/MyExpenses/tree/master/myExpenses/src/main/res/drawable
+ http://www.thaiall.com/android
</website_guide>

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

#AndroidStudio ตอนที่ 4 ทำหน้าเพจที่มีข้อมูลมากจนต้อง scroll ลงไป และการเพิ่ม icon ประจำแอพ

ตอนที่ 4 ทำหน้าเพจที่มีข้อมูลมากจนต้อง scroll ลงไป และการเพิ่ม icon ประจำแอพ

<introduction>
แอพพลิเคชั่น มักจะหมายถึง โปรแกรมที่ทำงานบน Smartphone เดี๋ยวนี้ใคร ๆ ก็ใช้แทน Desktop กันเยอะ แล้วแอพก็ยังโด่งดังมาจากกระแสนิยมโหลดโปรแกรมใน App Store ของ Apple และ Google ก็ทำ Play Store สิ่งที่อยู่ในแอพ เป็นอะไรก็ได้ แต่สิ่งหนึ่งที่ไม่อาจมองข้ามคือข้อมูล ให้อ่าน ให้ศึกษา และเรียนรู้ อาทิ บทความ ประวัติความเป็นมา เรื่องเล่า และนิยายพื้นบ้าน เป็นต้น

ถ้าเรื่องราวที่ต้องการใส่ในแอพ คือ ชุดตัวอักษรที่มีจำนวนมาก การใส่ตัวอักษรจำนวนมากในหนึ่งหน้า แล้วเราก็เปิดอ่านอย่างต่อเนื่อง เลื่อนลงไปผ่าน Scroll Bar นั่นเป็นโจทย์ที่น่าสนใจ สำหรับการอธิบายขั้นตอนการสร้างแอพครั้งนี้ แล้วผมก็มีบทความที่จะทดสอบกับบทเรียนนี้ คือ ไอทีในชีวิตประจำวัน เรื่องที่่ 611 และปิดบทความ How to ครั้งนี้ด้วยขั้นตอนการติดตั้ง icon ประจำแอพ หากใคร install app ใน smart phone ก็จะมี icon สวย ๆ ปรากฎไม่ใช้สัญลักษณ์ android ที่เค้าทำเป็นค่า Default มาให้
</introduction>

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

เพื่อแสดงข้อมูลเป็น Text หรือ String ที่มีขนาดยาวเกิน 1 หน้าที่จะแสดงผลได้
จึงต้องใช้ความสามารถในการทำ ScrollView

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

1. เริ่มต้นก็สร้าง Project แบบ Empty Activity แล้วจากการสำรวจว่า TextView อยู่ตรงไหน เพราะเป็นพระเอกของตอนนี้ โดยเข้าไปใน app, res, layout, activity_main.xml  พบว่า สามารถเข้าดูได้ 2 แบบคือ Tab:Design หรือ Tab:Text ถ้าเลือกดูแบบ Text ก็เหมือนดู Source code ที่เป็น XML จะพบกับ Tag ที่ชื่อ TextView มี Properties คือ android:text=”Hello World!” ซึ่งคำยอดนิยมนี้ สามารถเปลี่ยนได้ตามต้องการ

2. สังเกตก็จะพบส่วนของ properties หรือ คุณสมบัติ ของ TextView จะเห็นได้หากเราคลิ๊กคำว่า TextView ใน Component Tree จะพบ Properties Windows ทางด้านขวา
และมองเห็นคุณสมบัติของ layout_width กับ layout_height ที่เดิมมีค่าเป็น wrap_content ซึ่งหมายความว่า จะเปลี่ยนแปลงตำแหน่งตามเนื้อ content และมีตำแหน่งกลางจอภาพโดยอัตโนมัติ หากเปลี่ยนคุณสมบัติใน layout ทั้ง 2 เป็น match_parent
ก็จะทำให้อ้างอิงกับหน้าต่าง และ TextView ขยายเต็มจอภาพ และคำว่า Hello World! ก็จะไปอยู่ที่มุมบนซ้าย

นี่เป็นคุณสมบัติเติมขณะที่ไม่ได้แก้ไขใด ๆ
<TextView
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”Hello World!”
app:layout_constraintBottom_toBottomOf=”parent”
app:layout_constraintLeft_toLeftOf=”parent”
app:layout_constraintRight_toRightOf=”parent”
app:layout_constraintTop_toTopOf=”parent” />

แล้วถ้าสร้าง TextView ด้วยการใช้เครื่องมือ แบบ Drag and Drop ก็จะได้ Code ดังนี้

<TextView
android:id=”@+id/textView”
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:text=”TextView” />

3. ขั้นต่อไป ก็ไปหาเนื้อหา (Content) มาวางในช่อง text เพื่อให้มีข้อมูลแสดงผลมากกว่าแค่ Hello World! ผมหาบทความที่มีข้อมูลขนาด 2313 ตัวอักษร แล้ว paste ลงไป เรียงต่อกันเป็นพรืด เมื่อทดสอบแสดงผลใน Device emulator : Nexus_5X_API_19 พบว่าไม่แสดงภาษาไทย หายไปหมด เหลือแต่ภาษาอังกฤษ 

การพัฒนา App ในเครื่อง สามารถส่งงานไปแสดงผลในอุปกรณ์ได้หลายวิธี แต่การเลือก Device emulator อาจไม่สวยงาม และช้ากับเครื่องที่แรมน้อย จึงเปลี่ยนไป Run บน Smartphone ก็จะได้ผลงานเหมือนจริงที่ไม่ใช่การจำลองอุปกรณ์

4. การทำให้แสดงผลแบบมี Scroll Bar ให้เลือนขึ้นลง ดูข้อมูลที่เกิน 1 หน้าได้ ต้องใช้ ScrollView ร่วมกับ TextView มีตัวอย่างตาม Code ด้านล่าง และทำงานใน Smart Phone ได้อย่างถูกต้อง

5. พบว่า IDE ของ Android Studio  แนะนำว่าให้ใช้ @String แทนการวางข้อมูลจำนวนมากใน TextView โดยตรง จึงเข้า app, res, values, strings.xml แล้วเพิ่ม Tag นี้

<string name=”data1“>
ข้อมูลที่นี่จำนวน 2313 ตัวอักษร เป็นบทความที่ย้ายไปเขียนไว้ด้านล่าง
</string>

แล้วไปแก้ไขแฟ้ม activity_main.xml ให้อ้างอิงข้อมูลจาก data1 ตาม code ด้านล่างนี้

<TextView
android:id=”@+id/textView1″
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
android:scrollbars=”vertical”
android:text=”@string/data1” />

6. การกำหนดภาพ icon ประจำ Project ถ้าไม่ชอบภาพตัว Android ที่เค้ามีมาให้ ก็เข้าไปกด right click ที่ app, res แล้วเลือก New, image asset เลือก image เลือก file ภาพจากในคอมพิวเตอร์ แล้วกด next, finish หลังจากนั้น ภาพที่อัพโหลดเข้าไปจะไปปรากฎใน app, res, mipmap, ic_launcher.png จำนวน 5 ภาพ ต่อไปถ้าส่ง APK เข้า Smartphone ก็จะได้เห็นภาพสวย ๆ ชวนให้ Click กัน

7. เขียนโปรแกรมเสร็จแล้วก็ต้องทดสอบ RUN แฟ้มที่ต้องการนำไปใช้
คือ app-debug.apk  มักอยู่ใน C:\Users\[user name]
\AndroidStudioProjects\[project name]\app\build\outputs\apk\

การทดสอบก็มักใช้ Device Emulator เพราะง่ายที่สุด แต่เครื่องคอมพิวเตอร์ที่ใช้มี RAM 4GB ลง Win10 OEM ที่โหลด Windows Defender ตลอดเวลาอีก เมื่อสั่งเปิด Emulator ก็จะทำให้เครื่องช้าลงอย่างเห็นได้ชัด และผลการจำลองก็ไม่สวยงาม จึงเลือกที่จะส่งแฟ้ม app-debug.apk ไปประมวลผล นอกเครื่องคอมพิวเตอร์ แล้วผมเลือกส่งออกไปทาง Smart Phone ผ่านการเชื่อมต่อของ APP : WiFi ADB และทำผ่าน DOS ก็สะดวก จะส่งผ่าน Android Studio ก็ทำได้ ซึ่งการ Connect ทำครั้งเดียว ส่วนการ Install จะทำหลังจากการ Build ในแต่ละครั้ง

</process>

<website_guide>
https://guides.codepath.com/android/Working-with-the-ScrollView
http://www.viralandroid.com/2015/10/how-to-make-scrollable-textview-in-android.html
+ http://blog.teamgrowth.net/index.php/android/how-to-make-the-textview-in-android-scrollable
+ http://www.thaiall.com/itinlife
+ https://play.google.com/store/apps/details?id=com.thaiall.itarticle
</website_guide>

 

ไอทีในชีวิตประจำวัน #611 เมื่อเพื่อนขอใช้โทรศัพท์เข้าสื่อสังคม ()

อาจมีสักครั้งที่เพื่อนสนิท หัวหน้า กิ๊ก หรือแฟนขอยืมสมาร์ทโฟนของเราเข้าสื่อสังคม ในกรณีที่โทรศัพท์ของผู้ที่เข้ามายืมมีปัญหาและมีเหตุผลจำเป็น คำตอบโดยปกติคือ ไม่ให้ยืม แต่ถ้าคำตอบต้องเป็นให้ยืม แล้วต้องทำอย่างไร บางครั้งอาจต้องมีการทำงานกลุ่ม ต้องการภาพ หรือคลิ๊ปที่มีคุณสมบัติเหมือนกันจากสมาร์ทโฟนเครื่องเดียวกันเพื่ออัพโหลด หรือในกลุ่มมีเพียงของเราที่เชื่อมต่อเครือข่าย 3G หรือ WiFi ได้ หรือในกลุ่มพร้อมใจกันไม่ได้พกอุปกรณ์ติดตัวไปด้วย นั่นมีเหตุผลมากมายที่ต้องให้ยืม แล้วผู้พัฒนาแอพพลิเคชั่นเข้าใจเงื่อนไขเหล่านี้ จึงพัฒนาโปรแกรมบราวเซอร์ให้สามารถเปลี่ยนเป็นโหมดส่วนตัวที่ไม่บันทึกข้อมูลขณะใช้งาน และหายไปเมื่อเลิกใช้ได้ ซึ่งรองรับการให้เพื่อนยืมสมาร์ทโฟนเพื่อเข้าสื่อสังคมได้

ในสมาร์ทโฟนมักมีโปรแกรมบราวเซอร์ (Browser) อยู่หลายค่าย อาทิ Chrome, Firefox, Opera, Baidu หรือ Dolphin ผู้ใช้บางท่านอาจลงผลิตภัณฑ์หลายทุกค่าย ซึ่งมักมีคุณสมบัติในการเข้าโหมดส่วนตัวทุกค่าย แต่ละค่ายก็จะมีชื่อเรียกโหมด และวิธีการใช้งานที่แตกต่างกันไป แต่โหมดส่วนตัวหรือโหมดปลอดภัยจะมีคุณสมบัติเหมือนกัน คือ จะไม่เก็บรหัสผู้ใช้และรหัสผ่านขณะใช้งานในโหมดปลอดภัยนี้ ไม่บันทึกการใช้งานให้ติดตามได้ใน History และไม่เก็บข้อมูลคุกกี้ไว้ในเครื่องเมื่อเลิกใช้ และทำงานแยกออกจากโหมดใช้งานปกติ ซึ่งผู้ใช้สามารถล๊อกอินเข้าระบบสื่อสังคม อาทิ เฟสบุ๊ค หรือทวิตเตอร์ด้วยบัญชีผู้ใช้ที่แตกต่างกันระหว่างโหมดปกติ และโหมดปลอดภัยคนละชื่อ หากมี 3 โปรแกรมบราวเซอร์ และสลับโหมดก็จะสามารถให้เพื่อนไม่ต่ำกว่า 6 คนเข้าสู่ระบบของสื่อสังคมด้วยบัญชีที่แตกต่างกันได้ แต่คงจะวุ่นวายอยู่ไม่น้อยกับการใช้สมาร์ทโฟนเครื่องเดียวโดยผู้ใช้ 6 คน

การเข้าโหมดลับของโปรแกรม Chrome เรียก New incognito tab แล้วยังเปิดได้หลาย Tab และมี Notification ที่สั่งปิดได้ทุกแท็บ ส่วนโปรแกรม Firefox เข้าผ่าน Private tab หรือ Tools, New Guest Session ก็จะมีคุณสมบัติที่แตกต่างกัน ส่วนโปรแกรม Opera เข้าผ่าน Tab ที่ชื่อ Private คล้ายกับของ Firefox การใช้งานในโหมดลับนี้จะป้องกันการเห็นข้อมูลเฉพาะในตัวเครื่องเท่านั้น การเชื่อมต่อแล้วส่งข้อมูลออกไปภายนอกยังคงเปิดเผย และมีการเก็บข้อมูลการจราจร (Traffic Log) เช่นเดิม ผ่านผู้ให้บริการเครือข่าย ข้อความที่ส่งไปในสื่อสังคมก็ไม่ลับ หากข้อความนั้นมีคุณสมบัติเป็นสาธารณะ ดังนั้นการส่งข้อความใดก็ควรอยู่ในวิจารณญาณว่าจะไม่ก่อความเดือดร้อนให้ตนเอง หรือผู้อื่นไม่ทางใดก็ทางหนึ่ง เพื่อความปลอดภัยของตนเองเป็นที่ตั้ง เพราะความลับไม่มีในโลก และอย่างน้อยความลับที่ว่าลับนักนั้นตนเองก็รู้

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