Android 当我使用自定义文本视图对齐文本时,如何修复大文本?
我在GitHub上发现了Nyakokishi编写的一段代码,它允许通过自定义类在TextView中证明文本的合理性,对于最初的目的来说效果很好,但当文本太大时,会产生另一个问题,即无法全部显示 自定义TextView类感谢Droidroid的创作和Nyakokishi的精彩演示:Android 当我使用自定义文本视图对齐文本时,如何修复大文本?,android,textview,scrollview,Android,Textview,Scrollview,我在GitHub上发现了Nyakokishi编写的一段代码,它允许通过自定义类在TextView中证明文本的合理性,对于最初的目的来说效果很好,但当文本太大时,会产生另一个问题,即无法全部显示 自定义TextView类感谢Droidroid的创作和Nyakokishi的精彩演示: import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.os.Build;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import androidx.appcompat.widget.AppCompatTextView;
import mz.ac.ucm.fgti.newsfgti.android_client.R;
/**
* Created by Droidroid on 2016/3/24.
*/
public class JustifyTextView extends AppCompatTextView {
private TextPaint mPaint;
private Layout mLayout;
// Row height
private int mTextHeight;
// Y-axis
private float mLineY;
// View content width
private int mContentWidth;
// Character spacing
private float mCharacterSpace;
// Half of the character spacing
private float mGapWidth;
// Line spacing
private int mLineSpace;
// Full-width character width
private float mSBCwith;
// Aligned
private boolean isToAlignChars;
public JustifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
private void init(Context context, AttributeSet attrs) {
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.JustifyTextView);
mCharacterSpace = ta.getDimensionPixelSize(ta.getIndex(R.styleable.JustifyTextView_character_space)
, 0);
mLineSpace = ta.getDimensionPixelSize(ta.getIndex(R.styleable.JustifyTextView_line_space), 1);
isToAlignChars = ta.getBoolean(ta.getIndex(R.styleable.JustifyTextView_align_chars), true);
ta.recycle();
mGapWidth = mCharacterSpace / 2;
String text = getText().toString();
if (text.charAt(text.length() - 1) == 10) {
text = text.substring(0, text.length() - 1);
setText(text);
}
}
@Override
protected void onDraw(Canvas canvas) {
mPaint = getPaint();
mPaint.setColor(getCurrentTextColor());
mPaint.drawableState = getDrawableState();
String text = getText().toString();
mLayout = getLayout();
// layout.getLayout() has a NullPointerException in 4.4.3
if (mLayout == null) {
return;
}
Paint.FontMetrics fm = mPaint.getFontMetrics();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
mTextHeight = (int) (Math.ceil(fm.descent - fm.ascent) + getLineSpacingExtra());
} else {
mTextHeight = (int) (Math.ceil(fm.descent - fm.ascent) + mLineSpace);
}
mTextHeight = (int) (mTextHeight * mLayout.getSpacingMultiplier() + mLayout.getSpacingAdd());
// The width of the view content
mContentWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight();
// Full-width character width
mSBCwith = getSBCwidth(text);
if (mSBCwith > 0) {
if (isToAlignChars) {
drawAligmentLines(canvas, text);
} else {
drawSBCLines(canvas, text);
}
} else {
drawDBCLines(canvas, text);
}
}
private void drawSBCLines(Canvas canvas, String text) {
mLineY = getTextSize() + getPaddingTop();
float x = getPaddingLeft();
for (int i = 0; i < text.length(); i++) {
String c = String.valueOf(text.charAt(i));
if (c.equals(" ")) {
continue;
}
float cw = StaticLayout.getDesiredWidth(c, getPaint());
canvas.drawText(c, x, mLineY, getPaint());
x += cw + mCharacterSpace;
if (x + cw - mCharacterSpace > mContentWidth + getPaddingLeft() || c.equals("\n")) {
mLineY += mTextHeight;
x = getPaddingLeft();
}
// The last character in a line can squeeze
else if (x + cw > mContentWidth + getPaddingLeft()
&& x - mCharacterSpace + cw <= mContentWidth + getPaddingLeft()) {
x -= mCharacterSpace;
}
}
}
private void drawAligmentLines(Canvas canvas, String text) {
mLineY = getTextSize() + getPaddingTop();
float x = getPaddingLeft();
for (int i = 0; i < text.length(); i++) {
String c = String.valueOf(text.charAt(i));
if (c.equals(" ")) {
continue;
}
float cw = StaticLayout.getDesiredWidth(c, getPaint());
float currentGapWidth = getGapWidth(text.charAt(i));
canvas.drawText(c, x + currentGapWidth, mLineY, getPaint());
if (i < text.length() - 1) {
x += cw + 2 * currentGapWidth;
float nextCw = StaticLayout.getDesiredWidth(String.valueOf(text.charAt(i + 1)), getPaint());
float nextGapWidth = getGapWidth(text.charAt(i + 1));
if (x + nextCw + 2 * nextGapWidth > mContentWidth + getPaddingLeft() || c.equals("\n")) {
mLineY += mTextHeight;
x = getPaddingLeft();
}
}
}
}
private void drawDBCLines(Canvas canvas, String text) {
mLineY = getTextSize() + getPaddingTop();
float x = getPaddingLeft();
int lineCount = mLayout.getLineCount();
if (lineCount > 1) {
for (int i = 0; i < lineCount; i++) {
int lineStart = mLayout.getLineStart(i);
int lineEnd = mLayout.getLineEnd(i);
float lineWidth = mLayout.getLineWidth(i);
String line = text.substring(lineStart, lineEnd);
float wordSpace = (mContentWidth - lineWidth) / (getBlankCount(line) - 1);
for (int j = 0; j < line.length(); j++) {
String c = String.valueOf(line.charAt(j));
float cw = StaticLayout.getDesiredWidth(c, getPaint());
canvas.drawText(c, x, mLineY, getPaint());
if (i < lineCount - 1 && line.charAt(j) == 32) {
x += cw + wordSpace;
} else {
x += cw;
}
}
mLineY += mTextHeight;
x = getPaddingLeft();
}
} else {
int lineStart = mLayout.getLineStart(0);
int lineEnd = mLayout.getLineEnd(0);
String line = text.substring(lineStart, lineEnd);
for (int j = 0; j < line.length(); j++) {
String c = String.valueOf(line.charAt(j));
float cw = StaticLayout.getDesiredWidth(c, getPaint());
canvas.drawText(c, x, mLineY, getPaint());
x += cw;
}
}
}
private int getBlankCount(String line) {
int count = 0;
for (char c : line.toCharArray()) {
if (c == 32) {
count++;
}
}
return count;
}
private float getSBCwidth(String text) {
for (int i = 0; i < text.length(); i++) {
String c = String.valueOf(text.charAt(i));
if (Character.UnicodeBlock.of(text.charAt(i)) == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS) {
return StaticLayout.getDesiredWidth(c, getPaint());
}
}
return -1;
}
private float getGapWidth(char c) {
float gapWidth = (mSBCwith - StaticLayout.getDesiredWidth(String.valueOf(c)
, getPaint())) / 2 + mGapWidth;
return gapWidth;
}
}
请注意,当我使用嵌入式文本视图时,会显示整个文本
提前谢谢。试试这个解决方案
创建一个自定义类并使用
JustifyTextView.java
仍在削减开支在这里分享屏幕截图hi@Quick learner,我正在分析这两个代码,我发现为了使它符合我在您的版本中的需要,我必须在第行添加-2:textHeight=int textHeight*layout.getSpacingMultiplier+layout.getSpacingAdd;如下所示:textHeight=int textHeight*layout.getSpacingMultiplier+layout.getSpacingAD-2;。我的TeXVIEW将接收多达15000个字符,我不知道这是不是要考虑的事情,但如果有人有一些问题,可以看到所有这些细节。基本上,这个解决方案比我的代码更好,所以它对我来说是有效的。我所做的调整不是一个优雅的方式,但它正在工作,谢谢。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/white"
android:clickable="true"
android:paddingLeft="10sp"
android:paddingRight="10sp">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="10sp"
android:scrollbarAlwaysDrawHorizontalTrack="false"
android:scrollbars="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5sp"
android:orientation="vertical"
android:overScrollMode="never">
<mz.ac.ucm.fgti.newsfgti.android_client.view.adapters.JustifyTextView
android:id="@+id/col_titulo_detalhe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:editable="false"
android:enabled="false"
android:fontFamily="@font/ubuntu_bold"
android:gravity="center|top"
android:inputType="textMultiLine"
android:justificationMode="inter_word"
android:lineSpacingExtra="8sp"
android:text="texto para nao dar erro com JustifiedTextViee, sera substituido"
android:textColor="@color/colorPrimary"
android:textSize="24sp"
android:textStyle="bold" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="5sp"
android:orientation="horizontal"
android:overScrollMode="never">
<TextView
android:id="@+id/col_categoria_detalhe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5.5sp"
android:layout_weight="1"
android:editable="false"
android:enabled="false"
android:fontFamily="@font/ubuntu_light"
android:gravity="right"
android:textColor="@color/colorBlack"
android:textSize="12sp" />
<TextView
android:id="@+id/col_privilegio_detalhe"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:editable="false"
android:enabled="false"
android:fontFamily="@font/ubuntu_light"
android:textColor="@color/colorBlack"
android:textSize="12sp" />
</LinearLayout>
<TextView
android:id="@+id/col_data_detalhe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="20sp"
android:editable="false"
android:enabled="false"
android:fontFamily="@font/ubuntu_light_italic"
android:gravity="center"
android:textColor="@color/colorBlack"
android:textSize="12sp"
android:textStyle="italic" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:overScrollMode="never">
<mz.ac.ucm.fgti.newsfgti.android_client.view.adapters.JustifyTextView
android:id="@+id/col_conteudo_detalhe"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:editable="false"
android:ems="10"
android:enabled="false"
android:fontFamily="@font/ubuntu_light"
android:inputType="textMultiLine"
android:justificationMode="inter_word"
android:lineSpacingExtra="8sp"
android:paddingBottom="10sp"
android:text="texto para nao dar erro com JustifiedTextViee, sera substituido"
android:textColor="@color/colorBlack"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</RelativeLayout>
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.fragment.app.Fragment;
import mz.ac.ucm.fgti.newsfgti.android_client.R;
import mz.ac.ucm.fgti.newsfgti.android_client.view.adapters.JustifyTextView;
public class TbInformacaoDetalheFragment extends Fragment {
public JustifyTextView col_titulo_detalhe;
public TextView col_privilegio_detalhe;
public TextView col_categoria_detalhe;
public TextView col_data_detalhe;
public JustifyTextView col_conteudo_detalhe;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View itemView = LayoutInflater.from(container.getContext())
.inflate(R.layout.fragment_tb_informacao_detalhe, container, false);
Bundle bundle = getActivity().getIntent().getExtras();
col_titulo_detalhe = (JustifyTextView) itemView.findViewById(R.id.col_titulo_detalhe);
col_privilegio_detalhe = (TextView) itemView.findViewById(R.id.col_privilegio_detalhe);
col_categoria_detalhe = (TextView) itemView.findViewById(R.id.col_categoria_detalhe);
col_data_detalhe = (TextView) itemView.findViewById(R.id.col_data_detalhe);
col_conteudo_detalhe = (JustifyTextView) itemView.findViewById(R.id.col_conteudo_detalhe);
col_titulo_detalhe.setText(getArguments().getString("titulo"));
//A BARRA ANTES DO TEXTO SERVE PARA DEFINIR UMA SEPARACAO VISUAL ENTRE A CATEGORIA E O PRIVILEGIO
col_privilegio_detalhe.setText("| " + getArguments().getString("privilegio"));
col_categoria_detalhe.setText(getArguments().getString("categoria"));
col_data_detalhe.setText(getArguments().getString("data"));
col_conteudo_detalhe.setText(getArguments().getString("conteudo"));
return itemView;
}
}
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.text.Layout;
import android.text.StaticLayout;
import android.text.TextPaint;
import android.util.AttributeSet;
import android.widget.TextView;
public class JustifyTextView extends TextView {
private int mLineY;
private int mViewWidth;
public static final String TWO_CHINESE_BLANK = " ";
public JustifyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onDraw(Canvas canvas) {
TextPaint paint = getPaint();
paint.setColor(getCurrentTextColor());
paint.drawableState = getDrawableState();
mViewWidth = getMeasuredWidth();
String text = getText().toString();
mLineY = 0;
mLineY += getTextSize();
Layout layout = getLayout();
// layout.getLayout()在4.4.3出现NullPointerException
if (layout == null) {
return;
}
Paint.FontMetrics fm = paint.getFontMetrics();
int textHeight = (int) (Math.ceil(fm.descent - fm.ascent));
textHeight = (int) (textHeight * layout.getSpacingMultiplier() + layout.getSpacingAdd());
for (int i = 0; i < layout.getLineCount(); i++) {
int lineStart = layout.getLineStart(i);
int lineEnd = layout.getLineEnd(i);
float width = StaticLayout.getDesiredWidth(text, lineStart, lineEnd, getPaint());
String line = text.substring(lineStart, lineEnd);
if (needScale(line) && i < layout.getLineCount() -1) {
drawScaledText(canvas, lineStart, line, width);
} else {
canvas.drawText(line, 0, mLineY, paint);
}
mLineY += textHeight;
}
}
private void drawScaledText(Canvas canvas, int lineStart, String line, float lineWidth) {
float x = 0;
if (isFirstLineOfParagraph(lineStart, line)) {
String blanks = " ";
canvas.drawText(blanks, x, mLineY, getPaint());
float bw = StaticLayout.getDesiredWidth(blanks, getPaint());
x += bw;
line = line.substring(3);
}
int gapCount = line.length() - 1;
int i = 0;
if (line.length() > 2 && line.charAt(0) == 12288 && line.charAt(1) == 12288) {
String substring = line.substring(0, 2);
float cw = StaticLayout.getDesiredWidth(substring, getPaint());
canvas.drawText(substring, x, mLineY, getPaint());
x += cw;
i += 2;
}
float d = (mViewWidth - lineWidth) / gapCount;
for (; i < line.length(); i++) {
String c = String.valueOf(line.charAt(i));
float cw = StaticLayout.getDesiredWidth(c, getPaint());
canvas.drawText(c, x, mLineY, getPaint());
x += cw + d;
}
}
private boolean isFirstLineOfParagraph(int lineStart, String line) {
return line.length() > 3 && line.charAt(0) == ' ' && line.charAt(1) == ' ';
}
private boolean needScale(String line) {
if (line == null || line.length() == 0) {
return false;
} else {
return line.charAt(line.length() - 1) != '\n';
}
}
}