Android TextViewの自動改行問題
Android TextViewでテキストを表示する際、行が一杯になる前に次の行にジャンプしてしまうという問題があります。
1) 中国語のテキストを表示する場合、句読点を行頭と行末に表示することができません。句読点が行末にちょうどある場合、前の文字と一緒に次の行にジャンプしてしまいます。
2) 英単語を2行で表示できない(TextViewが英語を表示する場合、行末の句読点は許容されるが、英単語も区切ることができない)。
句読点を行末に表示させたいだけなら、句読点の後にスペースを入れれば、行末に表示される簡単な方法があります。
末尾揃えの表示にしたい場合は、2つの方法があります。
1) Android のソースコードを修正します。frameworks/base/core/java/android/text 下にある StaticLayout.java ファイルから以下のコードを取得します。
if (c == ' ' || c == '/t' ||
((c == '. || c == ',' || c == ':' || c == ';') &&
(j - 1 < here || !Character.isDigit(chs[j - 1 - start])) &&
(j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
((c == '/' || c == '-') &&
(j + 1 >= next || !Character.isDigit(chs[j + 1 - start]))) ||
(c >= FIRST_CJK && isIdeographic(c, true) &&
j + 1 < next && isIdeographic(chs[j + 1 - start], false)) {
okwidth = w;
ok = j + 1;
if (fittop < oktop)
oktop = fittop;
if (fitascent < okascent)
okascent = fitascent;
if (fitdescent > okdescent)
okdescent = fitdescent;
if (fitbottom > okbottom)
okbottom = fitbottom;
}
削除すればいい。削除すると、句読点を行頭と行末に表示したり、英単語を2行に分けて表示したりすることができます。
2) テキストを表示するビューをカスタマイズする
この問題を解決するためにカスタムViewsを使っている人がWeb上にいるので、実験してまとめてみました。
Viewをカスタマイズする手順。
1) View クラスまたはそのサブクラスを継承します。この例では TextView クラスを継承しています。
2) XML経由でプロパティを取得するコンストラクタを記述します(このステップでプロパティをカスタマイズできます、例を参照してください)。
3) 親クラスの関数をオーバーライドします。通常は on で始まる関数で、この例では onDraw() と onMeasure() 関数をオーバーライドしています。
=========================StartCustomTextView.java =============================
public class StartCustomTextView extends TextView {
public static int m_iTextHeight; // the height of the text
public static int m_iTextWidth; //Width of the text
private Paint mPaint = null;
private String string = "";
private float LineSpace = 0;//line spacing
private int left_Margin;
private int right_Margin;
private int bottom_Margin;
public StartCustomTextView(Context context, AttributeSet set)
{
super(context, set);
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
TypedArray typedArray = context.obtainStyledAttributes(set, R.styleable.CYTextView);
int width = displayMetrics.widthPixels;
left_Margin = 29;
right_Margin = 29;
bottom_Margin = 29;
width = width - left_Margin - right_Margin;
float textsize = typedArray.getDimension(R.styleable.CYTextView_textSize, 34);
int textcolor = typedArray.getColor(R.styleable.CYTextView_textColor, getResources().getColor(R.color.white));
float linespace = typedArray.getDimension(R.styleable.CYTextView_lineSpacingExtra, 15);
int typeface = typedArray.getColor(R.styleable.CYTextView_typeface, 0);
typedArray.recycle();
// Set the width and line spacing of CY TextView www.linuxidc.com
m_iTextWidth=width;
Linespace=linespace;
// build paint object
mPaint = new Paint();
mPaint.setAntiAlias(true);
mPaint.setColor(textcolor). mPaint.setTextSize(textcolor);
mPaint.setTextSize(textsize). mPaint.setTextSize(textsize);
switch(typeface){
case 0:
mPaint.setTypeface(Typeface.DEFAULT);
break;
case 1:
mPaint.setTypeface(Typeface.SANS_SERIF);
break;
case 2:
mPaint.setTypeface(Typeface.SERIF);
break;
case 3:
mPaint.setTypeface(Typeface.MONOSPACE);
break;
default:
mPaint.setTypeface(Typeface.DEFAULT);
break;
}
}
@Override
protected
int istart = 0;
int m_iFontHeight;
int m_iRealLine = 0;
int x=2;
int y=30;
Vector m_String = new Vector();
FontMetrics fm = mPaint.getFontMetrics();
m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;//calculate the font height (font height + line spacing)
for (int i = 0; i < string.length(); i++)
{
ch = string.charAt(i);
float[] widths = new float[1];
String srt = String.valueOf(ch);
mPaint.getTextWidths(srt, widths);
if (ch == '\n'){
m_iRealLine++;
m_String.addElement(string.substring(istart, i));
istart = i + 1;
w = 0;
}else{
w += (int) (Math.ceil(widths[0]));
if (w > m_iTextWidth){
m_iRealLine++;
m_String.addElement(string.substring(istart, i));
istart = i;
i--;
w = 0;
}else{
if (i == (string.length() - 1)){
m_iRealLine++;
m_String.addElement(string.substring(istart, string.length())));
}
}
}
}
m_iTextHeight=m_iRealLine*m_iFontHeight+2;
canvas.setViewport(m_iTextWidth, m_iTextWidth);
for (int i = 0, j = 0; i < m_iRealLine; i++, j++)
{
canvas.drawText((String)(m_String.elementAt(i)), x, y+m_iFontHeight * j, mPaint);
}
}
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int measuredHeight = measureHeight(heightMeasureSpec);
int measuredWidth = measureWidth(widthMeasureSpec);
this.setMeasuredDimension(measuredWidth, measuredHeight);
LayoutParams layout = new LinearLayout;
layout.leftMargin= left_Margin;
layout.rightMargin= right_Margin;
layout.bottomMargin= bottom_Margin;
this.setLayoutParams(layout);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private int measureHeight(int measureSpec)
{
int specMode = MeasureSpec.getMode(measureSpec);
int specSize = MeasureSpec.getSize(measureSpec);
// Default size if no limits are specified.
initHeight();
int result = m_iTextHeight;
if (specMode == MeasureSpec.AT_MOST){
// Calculate the ideal size of your
// Calculate the ideal size of your control within this maximum size.
// If your control fills the available
// If your control fills the available // space return the outer bound.
result = specSize;
}else if (specMode == MeasureSpec.EXACTLY){
// If your control can fit within these bounds return that value.
// result = specSize;
}
return result;
}
private void initHeight()
{
// Set the initial height of CY TextView to 0
m_iTextHeight=0;
// roughly calculate the required height of CY TextView
FontMetrics fm = mPaint.getFontMetrics();
int m_iFontHeight = (int) Math.ceil(fm.descent - fm.top) + (int)LineSpace;
int line=0;
int istart=0;
int w=0;
for (int i = 0; i < string.length(); i++)
{
char ch
=======================attrs.xml ===============================
このファイルはカスタム属性で、プロジェクト内のres/valuesの下に置かれます
<?xml version="1.0" encoding="utf-8"?>
<ScrollView
xmlns:Android="http://schemas.android.com/apk/res/android"
Android:layout_width="320px"
Android:layout_height="320px"
Android:background="#ffffffff"
>
<LinearLayout
xmlns:Android="http://schemas.android.com/apk/res/android"
Android:orientation="vertikal"
Android:layout_width="fill_parent"
Android:layout_height="fill_parent">
<com.cy.CYTextView.CYTextView
xmlns:cy="http://schemas.Android.com/apk/res/ com.cy.CYTextView "
Android:id="@+id/mv"
Android:layout_height="wrap_content"
Android:layout_width="wrap_content"
cy :textwidth="320"
cy :textSize="24sp"
cy :textColor="#aa000000"
cy :lineSpacingExtra="15sp"
cy :typeface="serif">
</com. cy .CYTextView.CYTextView>
</LinearLayout>
</ScrollView>
=======================main.xml ==========================
public class Main extends Activity {
CYTextView mCYTextView;
String text = "Android提供了精巧和有力的组件化模型构建用户的UI部分。主要是基于布局类:View和 ViewGroup。在此基础上,android平台提供了大量的预制的View和xxxViewGroup子 类,即布局(layout)和窗口小部件(widget)。可以用它们构建自己的UI。";
/** Wird aufgerufen, wenn die Aktivität zum ersten Mal erstellt wird. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
mCYTextView = (CYTextView)findViewById(R.id.mv);
mCYTextView.SetText(text);
}
}
(a) 青いコードがカスタムViewで、cyの名前空間で始まるプロパティがカスタムプロパティです。
=======================Main.java =============================
public class Main extends Activity {
CYTextView mCYTextView;
String text = "Android provides a subtle and powerful componentized model to build the UI part of the user. Mainly based on layout classes: View and ViewGroup. on top of that, android platform provides a large number of prefabricated View and xxxViewGroup subclasses, i.e. layout (layout) and widget (widget). You can use them to build your own UI;
/* Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setContentView(R.layout.main);
mCYTextView = (CYTextView)findViewById(R.id.mv);
mCYTextView.SetText(text);
}
}
<スパン
詳細については、WeChatでフォローしてください:caaz01
から取得した。 http://hi.baidu.com/java_rose/blog/item/2940a030d1ec7f3e96ddd847.html
関連
-
ADBサーバーがACKしなかった
-
RecyclerView がアダプタが接続されていませんと表示され、レイアウトソリューションをスキップする
-
Error:タスク ':app:compileDebugJavaWithJavac' の実行に失敗しました。解決方法
-
AndroidでFragmentを使用すると、Fragmentの内部コントロールを取得できず、findViewById()の結果がNullになる - 解決済み
-
ArrayAdapter のソリューションでは、リソース ID が TextView である必要があります。
-
Android ViewPager のエラーです。NULLオブジェクトの参照で仮想メソッドxxxを呼び出そうとした
-
BUG: android アクティビティはエクスポートされるか、インテント・フィルタを含む必要があります。
-
Manifest merger failed : Android 12以降をターゲットとするアプリは、明示的な指定が必要です。
-
Androidアプリの放送受信機登録(registerReceiver)処理の分析
-
Android Studioのインポートプロジェクトが表示されます。ファイルをクランチするのに失敗しました
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
AndroidStudioのエラーAAPT2エラーの解決:詳細のログを確認する
-
ADBサーバーがACKしない問題を解決しました。
-
Android フロントカメラのビデオ録画に失敗しました (MediaRecorder: start failed: -19)
-
AndroidManifest.xml は、アプリが Google 検索でインデックス化されていないことを警告しています。
-
アンドロイドバージョン一覧
-
java.lang.SecurityException を解決してください。android パッケージは 10065 に属していません。
-
Android 高機能版 (xxv) setTextColor() パラメータ設定方法
-
Android Studioのヒント - これを読めば、すべてのヒントが役に立つ
-
Android android-support-multidexを使用すると、Dexがメソッドの制限を超える問題を解決し、アプリケーションがバーストしなくなります。
-
android studioエミュレータの起動に失敗しました