Android 当我使用自定义文本视图对齐文本时,如何修复大文本?

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

我在GitHub上发现了Nyakokishi编写的一段代码,它允许通过自定义类在TextView中证明文本的合理性,对于最初的目的来说效果很好,但当文本太大时,会产生另一个问题,即无法全部显示

自定义TextView类感谢Droidroid的创作和Nyakokishi的精彩演示:

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';
        }
    }

}