#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 คือ < ตอนปิด Tag ไม่จำเป็นต้องใช้ > ก็ได้ หากส่งเข้า TextView ผ่านฟังก์ชัน setText() ในโปรแกรม Java อย่างที่ใช้คือ MainActivity.java
<string name=”myArticle”>
<h1>ไอทีในชีวิตประจำวัน #611 เมื่อเพื่อนขอใช้โทรศัพท์เข้าสื่อสังคม</h1><br/> อาจมีสักครั้งที่เพื่อนสนิท หัวหน้า กิ๊ก หรือแฟนขอยืมสมาร์ทโฟนของเรา …
</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 (<)
+ https://stackoverflow.com/..strings-xml-in-android (spanned)
+ https://developer.android.com/studio/projects/templates.html
</website_guide>
หมายเหตุ
ถ้าสนใจติดตามเนื้อหาในบล็อกนี้ สามารถ subscribe ด้วย email ที่อยู่ข้างขวา หรือ click here