1. 程式人生 > >Android 文字和圖片混排,文字環繞圖片

Android 文字和圖片混排,文字環繞圖片

在平時我們做專案中,或許有要對一張圖片或者某一個東西進行文字和圖片說明,這時候要求排版美觀,所以會出現文字和圖片混排的情況,如圖:


這種情況就是上下兩個文字說明是連續在一起的,這就要求我們計算上面的文字說明怎麼和下面的文字說明連貫結合在一起呢,這就要求我們進行計算了,下面給出程式碼,程式碼中也有詳細的註釋,原理也很簡單。

因為算是比較簡單,直接就在activity中去計算了:

package com.example.test;

import android.app.Activity;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.ViewTreeObserver;
import android.widget.ImageView;
import android.widget.TextView;

public class MainActivity extends Activity {

	boolean imageMeasured = false;
	TextView tv_right;
	TextView tv_bottom;

	static final String text = "葉凡:小說主角,與眾老同學在泰山聚會時一同被九龍拉棺帶離地球," +
			"進入北斗星域,得知自己是荒古聖葉凡 葉凡體。歷險禁地,習得源術,鬥聖地世家,戰太古生物," +
			"重組天庭,葉凡輾轉四方得到許多際遇和挑戰,功力激增,眼界也漸漸開闊。一個浩大的仙俠世界," +
			"就以他的視角在讀者面前展開。姬紫月:姬家小姐,出場年齡十七歲。被葉凡劫持一同經歷青銅古殿歷險," +
			"依靠碎裂的神光遁符解除禁制,反過來挾持葉凡一同進入太玄派尋找祕術。" +
			"在葉凡逃離太玄後姬紫月在孔雀王之亂中被華雲飛追殺,又與葉凡[2]相遇,被葉凡護送回姬家" +
			",漸漸對葉凡產生微妙感情。後成為葉凡的妻子,千載後於飛仙星成仙,在葉凡也進入仙路後再見龐博:" +
			"葉凡大學時最好的朋友,壯碩魁偉,直率義氣。到達北斗星域後因服用了聖果被靈墟洞天作為仙苗," +
			"在青帝墳墓處為青帝十九代孫附體離去,肉身被錘鍊至四極境界。後葉凡與黑皇鎮壓老妖神識," +
			"龐博重新掌控自己身軀,取得妖帝古經和老妖本體祭煉成的青蓮法寶,習得妖帝九斬和天妖八式," +
			"但仍偽裝成老妖留在妖族。出關後找上葉凡,多次與他共進退。星空古路開啟後由此離開北斗," +
			"被葉凡從妖皇墓中救出,得葉凡授予者字祕、一氣化三清,與葉凡同闖試煉古路,一起建設天庭";
	// 螢幕的高度
	int screenWidth = 0;
	// 總共可以放多少個字
	int count = 0;
	// textView全部字元的寬度
	float textTotalWidth = 0.0f;
	// textView一個字的寬度
	float textWidth = 0.0f;
	Paint paint = new Paint();

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		tv_right = (TextView) findViewById(R.id.test_tv_right);
		tv_bottom = (TextView) findViewById(R.id.test_tv_bottom);
		final ImageView imageView = (ImageView) findViewById(R.id.test_image);
		imageView.setImageResource(R.drawable.ee);

		screenWidth = getWindowManager().getDefaultDisplay().getWidth();

		/**
		 * 獲取一個字的寬度
		 */
		textWidth = tv_right.getTextSize();
		paint.setTextSize(textWidth);

		/**
		 * 因為圖片一開始的時候,高度是測量不出來的,通過增加一個監聽器,即可獲取其圖片的高度和長度
		 */
		ViewTreeObserver vto = imageView.getViewTreeObserver();
		vto.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
			public boolean onPreDraw() {
				if (!imageMeasured) {
					imageMeasured = true;
					int height = imageView.getMeasuredHeight();
					int width = imageView.getMeasuredWidth();
					drawImageViewDone(width, height);
				}
				return imageMeasured;
			}
		});
	}

	private void drawImageViewDone(int width, int height) {
		// 一行字型的高度
		int lineHeight = tv_right.getLineHeight();
		// 可以放多少行
		int lineCount = (int) Math.ceil((double) height / (double) lineHeight);
		// 一行的寬度
		float rowWidth = screenWidth - width - tv_right.getPaddingLeft() - tv_right.getPaddingRight();
		// 一行可以放多少個字
		int columnCount = (int) (rowWidth / textWidth);

		// 總共字型數等於 行數*每行個數
		count = lineCount * columnCount;
		// 一個TextView中所有字串的寬度和(字型數*每個字的寬度)
		textTotalWidth = (float) ((float) count * textWidth);

		measureText();
		tv_right.setText(text.substring(0, count));

		// 檢查行數是否大於設定的行數,如果大於的話,就每次減少一個字元,重新計算行數與設定的一致
		while (tv_right.getLineCount() > lineCount) {
			count -= 1;
			tv_right.setText(text.substring(0, count));
		}
		tv_bottom.setPadding(0, lineCount * lineHeight - height, 0, 0);
		tv_bottom.setText(text.substring(count));
	}

	/**
	 * 測量已經填充的長度,計算其剩下的長度
	 */
	private void measureText() {
		String string = text.substring(0, count);
		float size = paint.measureText(string);
		int remainCount = (int) ((textTotalWidth - size) / textWidth);
		if (remainCount > 0) {
			count += remainCount;
			measureText();
		}
	}

}

其中xml檔案佈局如下:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content" >

        <ImageView
            android:id="@+id/test_image"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:scaleType="fitXY" />

        <TextView
            android:id="@+id/test_tv_right"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_toRightOf="@id/test_image"
            android:gravity="fill_horizontal"
            android:paddingLeft="7dp"
            android:textSize="16sp" />

        <TextView
            android:id="@+id/test_tv_bottom"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:layout_below="@id/test_image"
            android:gravity="fill_horizontal"
            android:textSize="16sp" />
    </RelativeLayout>

</ScrollView>

程式碼很少,原理也很簡單,後來發現這種做法在大部分手機執行是完美的,但是少部分手機還是有點問題。是什麼問題呢,是在我們測量textView的長度的是,因為是我們剛剛進行setText,然後馬上進行測量,這樣得到的結果是不正確的,所以大家可以優化一下。溫馨提示,當我們setText之後,可以延時一些時間再去測量,這樣獲取的值就是掙錢的了,當然那個延遲的時間很短50毫秒就可以了,因為我們要相信textView的繪製速度還是很快的。