Tut: Android: Cách chia text thành các trang sử dụng StaticLayout
Chào các bạn, hnay m sẽ giới thiệu cho các bạn cách chia 1 đoạn text dài (1 chương sách hay cả cuốn sách) thành dạng trang phù hợp với màn hình điện thoại mà bạn đang sử dụng. Sau khi hoàn thành phần hướng dẫn này, các bạn sẽ đạt đc kết quả như sau: + kế thừa từ class android.text.Layout + Constructor: StaticLayout(CharSequence source, TextPaint paint, int width, Layout.Alignment align, float spacingmult, float spacingadd, boolean includepad) StaticLayout có tác dụng là sắp xếp đoạn text của bạn theo layout đã xác lập. Nó sử dụng các tham số:
-
CharSequence
source: đoạn text của bạn
-
TextPaint paint: quy định màu chữ, font, cỡ chữ, style…
Và dùng để vẽ text lên canvas (xem thêm về Canvas và các phương thức draw).
-
int width: chiều rộng của trang sách (phần hiển thị
chữ, không kể căn lề) mà bạn muốn.
-
Layout.Alignment align:
-
float spacingmult, float spacingadd: khoảng cách dòng,…
-
boolean includepad:
+ StaticLayout “viết”
chữ của bạn ntn?StaticLayout sử dụng phương thức draw(Canvas canvas) để vẽ text lên 1 canvas. Như vậy chúng ta có thể thu được 1 đối tượng Bitmap như sau:
bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
// Tạo canvas để vẽ lên
Canvas c = new Canvas(bitmap);
// Vẽ lên canvas
staticlayout.draw(c);
II. Thực hiện: 1. Chuẩn bị: - Như bạn đã thấy, StaticLayout sẽ vẽ text lên canvas và chúng ta thu đc 1 bitmap. Để đơn giản, m sẽ sử dụng ImageView để view bitmap này. - Việc đầu tiên là tạo ra 1 project mới, ở đây m lấy tên là BitmapTest. - Các bạn sửa layout của main.xml như sau: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent" > <ImageView android:id="@+id/imgview" android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:src="#ffFDF8A6"></ImageView> </LinearLayout> ▲Ở đây, ImageView với id là image sẽ đảm nhận nhiệm vụ hiển thị bitmap thu đc. ▲Chạy chương trình vào lúc này sẽ cho bạn 1 màn hình màu vàng (ffFDF8A6). -Tinh chỉnh 1 chút cho chương trình đẹp hơn:
+ Các bạn sửa method onCreate()
như sau để chương trình thành full screen:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
}
-Tiếp theo, chúng ta cần có 1 đoạn text. Bạn có thể chọn đoạn text bất kỳ nhưng fải đảm bảo đủ dài. String story = “<nội dung>” -Khai báo thêm vài thông số cần thiết:
// width, height: chiều dài,
rộng màn hình
int width, height; // Các thông số khác int textSize = 20; // cỡ chữ int textColor = 0xffA7573E; // màu chữ int pageColor = 0xffFDF8A6; // màu nền int topPadding = 30, leftPadding = 10; // căn trên, căn dưới // Paint vẽ text
TextPaint myTextPaint;
-Thêm dòng sau vào phương thức onCreate của activity để tìm width, height của màn hình:
Display
display = ((WindowManager)this.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
width =
display.getWidth();height = display.getHeight(); -Khai báo textPaint: +Bạn có thể thêm phông chữ cho sinh động hơn:
// Xác lập font chữ
Typeface tf = Typeface.createFromAsset(this.getAssets(),"fonts/UVNDaLat_R.TTF");
// Xác lập các thông số về
font chữ
myTextPaint = new TextPaint();
myTextPaint.setColor(textColor);myTextPaint.setTextSize(textSize); myTextPaint.bgColor = pageColor; myTextPaint.setAntiAlias(true); myTextPaint.setTypeface(tf); 2.Tiến hành -Sau đây m sẽ dùng SL để vẽ đoạn text lên màn hình:
//
public Bitmap
getPageBitmap() { Bitmap pageContentBitmap; // Bitmap chứa text pageContentBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // Tạo canvas để vẽ lên Canvas c = new Canvas(pageContentBitmap); // Tạo StaticLayout cho nội dung text StaticLayout layout = new StaticLayout(story, myTextPaint, width - (leftPadding << 1), Layout.Alignment.ALIGN_NORMAL, 0.5f, 10f, false); // Vẽ lên canvas layout.draw(c); return pageContentBitmap;
}
▲Ở đây, tham số width được truyền vào là width - (leftPadding << 1) với mục đích căn trái cho đoạn text(chừa lề khi viết, kok viết hết toàn bộ chiều rộng màn hình). -Hiển thị bitmap lên màn hình:
khai báo và set ảnh cho ImageView:
image = (ImageView)
findViewById(R.id.imgview);
image.setImageBitmap(getPageBitmap());
▲Bạn chạy chương trình sẽ thấy đoạn text đã đc vẽ lên. Nhg đc vẽ ở vị trí (0,0) của màn hình. Chúng ta cần chỉnh lại 1 chút method getPageBitmap():
//
public Bitmap
getPageBitmap() { Bitmap pageBitmap, pageContentBitmap; // Bitmap nền pageBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); // Bitmap chứa text pageContentBitmap = Bitmap.createBitmap(width-(leftPadding<<1), height-topPadding, Bitmap.Config.ARGB_8888); // Tạo canvas để vẽ lên Canvas c = new Canvas(pageContentBitmap); // Tạo StaticLayout cho nội dung text StaticLayout layout = new StaticLayout(story, myTextPaint, width - (leftPadding << 1), Layout.Alignment.ALIGN_NORMAL, 0.5f, 10f, false); // Vẽ lên canvas layout.draw(c); // Canvas của nền cho vẽ ảnh nội dung lên Canvas c2 = new Canvas(pageBitmap); // Tô màu nền c2.drawColor(pageColor); // vẽ ảnh nội dung c2.drawBitmap(pageContentBitmap, leftPadding<<1, topPadding, myTextPaint); return pageBitmap;
}
-Bi h, chạy chương trình sẽ cho kết quả đoạn text được căn chỉnh lại. Tuy nhiên, vẫn có những dòng thừa ở cuối màn hình. Điều này là do SL chỉ có tác dụng WRAP-TEXT nên bạn sẽ thu đc kết quả tương tự như hiển thị text dài trên 1 TextView. Vậy cách giải quyết vấn đề này ntn? Nếu bạn muốn cắt bỏ đoạn text thừa ở cuối dòng, thì đoạn text của bạn fải chia nhỏ ra sao cho khớp với kích thước trang. Hay nói cách khác, bạn fải biết đc vị trí cần cắt text. Vị trí đó nằm ổ cuối dòng-dòng cuối cùng của trang (gold position). Thật may mắn, SL cho chúng ta 2 method:
-
public int
getLineForVertical (int vertical): Trả về dòng nằm ở tọa độ (0, vertical)
-
public int
getOffsetForHorizontal(int line, float horiz): Trả về index của đoạn text
nằm ở dòng line và có tọa độ (horiz,0);
-Và đây là cách mà m đã làm:// public void splitTextIntoPages() { // các chỉ mục dùng để cắt text int offsetI = 0, offsetII = 0; // Tạo Static Layout cho toàn bộ text StaticLayout layout = new StaticLayout(story, myTextPaint, width - (leftPadding << 1), Layout.Alignment.ALIGN_NORMAL, 0.5f, 10f, false); // Tổng số dòng int totalLines = layout.getLineCount(); // Số dòng từng trang int linePerPage = layout.getLineForVertical(height - (topPadding << 1)); // loop to the end int i = 0; do{ // Log.i("Thong bao", "Dang chia..."); // int line = Math.min(linePerPage * (i+1), totalLines-1); // vi tri của ký tự cuối trang offsetII = layout.getOffsetForHorizontal(line, width - (leftPadding << 1)); // Lấy subString String sub = story.substring(offsetI, offsetII); // offsetI = offsetII; // Thêm vào danh sách listOfPages.add(sub); // i++; }while (offsetII<story.length()); } ▲Ở mỗi vòng lặp, chúng ta sẽ lấy “gold position” và cắt text dựa vào nó. Các đoạn text được cắt (sẽ khớp với kích thước trang) được lưu theo thứ tự vào Vector<String> listOfPages. -Thử hiển thị trang đầu tiên:
+ method onCreate(): thêm splitTextIntoPages() vào trước dòng set ảnh cho ImageView.
+ method getPageBitmap():
bạn sửa đoạn khai báo SL:
StaticLayout layout = new StaticLayout(listOfPages.elementAt(0), myTextPaint, width- (leftPadding << 1), Layout.Alignment.ALIGN_NORMAL, 0.5f,
10f, false);▲Chạy thử chương trình sẽ thấy các dòng thừa đã mất. -Để hiển thị tiếp các trang sau bạn có thể làm như sau:
+ Thêm biến chỉ mục trang: int
index=0;
+ method
onCreate:
image.setOnClickListener(new
OnClickListener() {@Override public void onClick(View v) { // if (index > listOfPages.size()-1) { index = 0; } // Xác lập ảnh image.setImageBitmap(getPageBitmap()); // index++; // }
});
+ method getPageBitmap():
sửa khai báo SL:
StaticLayout layout = new StaticLayout(listOfPages.elementAt(index), myTextPaint, width
- (leftPadding << 1),
Layout.Alignment.ALIGN_NORMAL, 0.5f, 10f, false);
Tut đến đây là kết thúc. Hy vọng những thông tin này sẽ giúp ích cho bạn. Download source code: http://www.mediafire.com/?bt9p65ud4nf59wm |