#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 ตอนที่ 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

#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 ได้ปกติ มีกำลังใจแล้วครับ

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

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;

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

ทั้ง 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 ตอนที่ 3 ใช้ CustomTabs แทน WebView สั่งเปิดโฮมเพจ

ตอนที่ 3 ใช้ CustomTabs แทน WebView สั่งเปิดโฮมเพจ

<introduction>
หลังแชร์ App และ .zip ของ Project ทั้ง 12 ตัว ที่ผมได้เปิด new project และ build เป็น APK ตาม Activity ที่ Android Studio มีมาให้ ใน ตอนที่ 1 เพื่อเป็นการเริ่มต้นสร้างความเคยชินในการสร้าง App เชิงสำรวจ IDE Tool ก็ต่อด้วยการสร้าง App ที่ใช้ WebView เพื่อเชื่อมออนไลน์แล้วนำ Homepage ตาม URL มาแสดงใน App

หลังจากนั้นก็พบว่า Oatrice เขียนเรื่อง “ยังใช้ Webview กันอยู่หรือ Chrome custom tabs เร็วกว่า 2 เท่านะ รู้ยัง” พอเข้าไปลองดูก็พบว่าเป็นการสั่งให้ Browser ทำงาน โดยส่ง URL ในแอพ ซึ่ง pasko ได้แชร์ code ของ project ที่สมบูรณ์ไว้ที่ github.com ซึ่งเข้าไปดู code แล้วเห็นว่ามีการใช้งาน CustomTabs ร่วมกับ WebView ได้อย่างลงตัว

ใน Post ตอนนี้้ ผมจะพูดถึงการติดตั้ง CustomTabs ผ่าน Dependencies และการเขียน Code เพื่อเรียกใช้อย่างง่าย ตั้งชื่อว่า Openweb2 ซึ่งต่อมาจาก ตอนที่ 2 นั่นเอง
</introduction>

<process>
กระบวนการในการพัฒนา APP
เพื่อติดตั้ง CustomTabs และเขียน code เรียกใช้งาน
สั่งเปิด Homepage ตาม URL ใน Browser ของ Smartphone
มีขั้นตอน ดังนี้

1. หลังอ่านเรื่อง CustomTabs ไปพักหนึ่ง พบว่า สิ่งที่ไม่ชัดเจน คือ Version เพราะจะติดตั้งก็ต้องรู้เลข Version แต่ละคนเขียนเล่าไว้ในแต่ละช่วงเวลา อ้างเลข Version ไม่ตรงกัน Copy Code ไปติดตั้งใน dependencies ก็จะมี Error ใน Warning แน่เหมือนแช่แป้ง ดังนี้ผมจึงเข้า Support Library Packages – https://developer.android.com เพื่อดูเลขรุ่นล่าสุด ผมใช้วิธีกดปุ่ม Ctrl+F หาคำว่า “customtabs” เมื่อ 2 สิงหาคม 2560
ก็พบครับ ใช้รุ่นนี้เลย

com.android.support:customtabs:26.0.0

2. การติดตั้ง Package ใหม่ ต้องเข้าไปใน Project ที่อยู่ใน IDE
ดังนั้นจึงสร้าง New Project แบบ Empty Activity ให้เรียบร้อย แล้วก็รอให้ project ติดตั้งจน Gradle build finished จนพร้อมในหน้า IDE เป็นขั้นตอนปกติเลยครับ

Android Studio Started
Android Studio Started

3. การติดตั้ง CustomTabs ใน Project ของเรา
ต้องเข้าใน Project Explore หรือ Project Windows หรือ Project Tab ที่อยู่มุมบนซ้าย
จะพบ 2 กลุ่มงาน คือ app กับ Gradle Scripts
ให้คลิ๊ก Gradle Script, build.gradle(Module: app)
แล้วพิมพ์คำว่า
compile ‘com.android.support:customtabs:26.+’
ก่อน testCompile ‘junit:junit:4.12’
ผมใส่ 26.0.0 แล้วติด Error พอใช้ 26.+ เหมือน Package ด้านบน ก็ผ่านครับ

4. จากนั้น Clear Project ผ่าน Menu Bar, Build
แล้วนั่งรอระบบแป๊ปนึง รอ Gradle Build Running
ผลการ Build แล้วก็ไม่พบ Message อะไรให้กวนใจ
แล้วเข้าไปดูว่าเรียบร้อยไหม ผ่าน Project Structure, Module, App, Dependencies
ก็จะพบว่า Package ของเรา เข้าไปรอให้ถูกเรียกใช้เรียบร้อยแล้ว

5. เนื่องจาก CustomTabs คือ Package ที่สามารถเรียก Browser มารับ URL ที่ App ส่งไปให้ ผมนำเสนอตัวอย่างใน openweb2 โดยแก้ไขเฉพาะแฟ้ม MainActivity.java โดยไม่ไปแก้ไข Layout ใน activity_main.xml ใน emulator แม้ไม่มี Chrome ก็เรียก Browser ในเครื่องมาแสดงผล แล้วส่งไปให้ Smart Phone ก็จะมีการถามว่าจะใช้ Browser ตัวใดในการเปิด และ Code ที่ใช้มีเพียงไม่กี่บรรทัด ที่เป็นหน้าที่หลักของ CustomTabs หากสนใจเพิ่มเติม ต้องเพิ่มกันเองตามสะดวกล่ะครับ สำหรับ openweb2.apk กับ openweb2.zip ผมแชร์ใน 4shared.com ที่อยู่ด้านล่างแล้ว

https://gist.github.com/thaiall/9551cc6b1f7508663f372f760518b59f

</process>

https://www.4shared.com/folder/AgIkeXaS/android.html

<website_guide>
https://developer.android.com/topic/libraries/support-library/packages.html
+ https://guides.codepath.com/android/Chrome-Custom-Tabs#next-steps
+ https://github.com/GoogleChrome/custom-tabs-client/blob/master/Using.md
+ https://developer.chrome.com/multidevice/android/customtabs
+ https://rominirani.com/gradle-tutorial-part-6-android-studio-gradle-c828c5639bb
+ http://www.thaiall.com/android
</website_guide>

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

 

#AndroidStudio ตอนที่ 1 การพัฒนา app สำหรับใช้งานบน Smart Phone ที่ลง Android

ตอนที่ 1 การพัฒนา app สำหรับใช้งานบน Smart Phone ที่ลง Android

<introduction>
หลังจากผมได้คอมพิวเตอร์โน๊ตบุ๊ค แล้ว IT Clinic ลง Windows 10 Home 64Bit (OEM=Original Equipment Manufacture)
ก็นำมาลองสร้างแอพ (App = Application) สำหรับ Moveable Device ด้วย Android Studio
ซึ่งมีผู้พัฒนา คือ บริษัทกูเกิ้ล (Google.com) เริ่มต้นก็คิดว่าจะลงโปรแกรมแล้วเขียนโปรแกรม Hello World ไป Run บน Smart Phone ที่ใช้อยู่
</introduction>

<process>
กระบวนการในการพัฒนา APP
เพื่อให้ได้ .apk ไปใช้งาน
ซึ่ง Google พัฒนา Android Studio เป็น IDE ที่มี everything และใช้งานง่ายกว่าเดิม
มีขั้นตอน ดังนี้

1. Download : Java (jdk-8u144-windows-i586.exe หรือรุ่นใหม่กว่า)
จาก https://java.com/en/download/
เพราะเครื่องมือสำหรับพัฒนาโปรแกรม ต้องใช้ Java Runtime Environment (JRE)
แต่ใน Android Studio รุ่นที่ผมใช้เป็นแบบ Portable
มี JRE Embeded ติดมาให้ด้วย ไม่ต้องติดตั้ง เพราะเรียกใช้งานจากในแฟ้มที่คัดลอกมาได้เลย
ดังนั้นในเครื่องที่ผมใช้พัฒนา Android App จึงไม่ติดตั้ง JAVA ด้วยตนเอง
เพราะมีมาพร้อม Android Studio แล้ว

project structure in android studio
project structure in android studio

2. Download : Android Studio (android-studio-ide-162.4069837-windows32.zip)
จาก https://developer.android.com/studio/
ของผมได้รุ่น Android Studio v2.3.3 (June 2017) ซึ่งใหม่สุด ณ ตอนนี้
ซึ่ง Include Everything มาแล้ว
ทั้ง IDE (Integrated Development Environment) + SDK (Android Software Development Kit) + Emulator
ผมเลือกรุ่น .zip ไม่เลือกแบบ install
เพราะคลาย zip แล้ว เรียกให้โปรแกรม Folder> android-studio\bin\studio.exe ทำงานได้เลย
ทำงานแบบ Portable ที่ไม่ต้องติดตั้งก่อน
และผมไม่เลือกใช้ Eclipse เพราะ sdk-tools-r2602_windows-3859397.zip
จะไม่มี SDK Manager มาให้ ต้องใช้ SDK Manager ใน Android Studio
และ Google ประกาศเลิกสนับสนุน SDK ให้ Software ภายนอกแล้ว

Android Studio can be the portable software
Android Studio can be the portable software

3. เมื่อสั่งให้ studio.exe ทำงาน
ก็สั่ง Menu Bar, File, New, New Project
Application name : My Application
Company domain : www.thaiall.com
Minimum SDK : API 19: Android 4.4 (KitKat)
อาจเลือก API 25: Android 7.1.1 (Nougat)
หรือ API 26: Android 8 (O) ก็แล้วแต่ชอบนะครับ แต่ผมชอบของเก่า
Add an Activity to Mobile
เป็น Template ให้เลือก 12 แบบ แบบแรกที่เลือก คือ Basic Activity
แล้วก็ Finish อะไรไม่แจ้งไว้ แสดงว่าไม่ได้เปลี่ยน

Default Activity on Android Studio
Default Activity on Android
Studio
Default Activity on Android Studio
Default Activity on Android
Studio
Default Activity on Android Studio
Default Activity on Android
Studio

4. เข้าสู่ส่วนของ IDE มีหน้าต่างย่อยเพียบ
เห็นคำว่า Hello World! ใน content_main.xml
พบช่อง Text ด้านขวา สามารถเปลี่ยนเป็น Hello My World! ที่นั่นได้

We can change from hello world to hello my world
We can change from hello world to hello my world

5. ทดสอบประมวลผล
Menu bar, Run, Run ‘app’ หรือ Shift F10

6. เลือก Device
จาก Connected Devices หรือ Available Virtual Devices
หรือกด Create New Virtual Device
ผมสร้าง Device ชื่อ Nexus 5X API 19 ไว้ทดสอบตัวหนึ่ง
สร้างเสร็จก็เลือก Device ที่สร้างขึ้น
จะมีการ Popup อุปกรณ์ Emulator ขึ้นมา เพื่อแสดงผลการ Run

android emulator
android emulator

7. หลังพอใจในผลลัพธ์ ที่เห็นบน Emulator แล้ว
สั่งสร้าง .APK ด้วย Menu bar, Build, Build APK
แฟ้ม .apk ที่ได้ชื่อ app-debug.apk
อยู่ใน C:\Users\[Your Name]\AndroidStudioProjects\basicactivity\app\build\outputs\apk
นำแฟ้มนี้ไปใช้ใน Smart Phone ได้ตามต้องการ
หากผลบน Emulator ไม่น่าพอใจ ก็สั่ง Uninstall
ได้เหมือนกับที่ทำบน Smart Phone คือ ลากลงถังขยะ

we can use apk file on smart phone
we can use apk file on smart phone

 

https://www.4shared.com/folder/AgIkeXaS/android.html

</process>

<website_guide>
+ http://www.thaiall.com/android
</website_guide>

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