Android 如何根据视图最大尺寸自动调整多行文本视图上的文本大小?

Android 如何根据视图最大尺寸自动调整多行文本视图上的文本大小?,android,textview,word-wrap,typeface,text-size,Android,Textview,Word Wrap,Typeface,Text Size,我一直在寻找一种在文本视图中自动调整文本的方法。通过搜索,我找到了许多解决方案,如: 但和其他许多人一样,这些并不能解决我的问题。 当我们使用带有多行的TextView时,它们不能按预期工作 基本上,我的目标是: 如您所见,文本根据宽度、高度调整大小,并注意换行,从而创建多行文本视图。还可以更改字体 我解决这个问题的一个想法是: int size = CONSTANT_MAX_SIZE; TextView tv = (TextView) findViewById(R.id.text

我一直在寻找一种在文本视图中自动调整文本的方法。通过搜索,我找到了许多解决方案,如:

但和其他许多人一样,这些并不能解决我的问题。 当我们使用带有多行的TextView时,它们不能按预期工作

基本上,我的目标是:

如您所见,文本根据宽度、高度调整大小,并注意换行,从而创建多行文本视图。还可以更改字体

我解决这个问题的一个想法是:

int size = CONSTANT_MAX_SIZE;
TextView tv = (TextView) findViewById(R.id.textview1)
while(Math.abs(tv.getMeasuredHeight()) >= TEXTVIEW_MAX_HEIGHT) {
    size--;
    tv.setTextSize(size);
    tv.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
    i++;
}
<TextView
     android:id="@+id/textview1"
     android:layout_width="200dp"
     android:layout_height="wrap_content"
     android:singleLine="false"
     android:inputType="textMultiLine"
     android:text=""
     android:textSize="150sp" />
public int getHeightOfMultiLineText(String text,int textSize, int maxWidth) {
    paint = new TextPaint();
    paint.setTextSize(textSize);
    int index = 0;
    int linecount = 0;
    while(index < text.length()) {
        index += paint.breakText(text,index,text.length,true,maxWidth,null);
        linecount++;
    }

    Rect bounds = new Rect();
    paint.getTextBounds("Yy", 0, 2, bounds);
    // obtain space between lines
    double lineSpacing = Math.max(0,((lineCount - 1) * bounds.height()*0.25)); 

    return (int)Math.floor(lineSpacing + lineCount * bounds.height());
常量\u MAX\u SIZE是定义字体最大大小的常量(TextView中的textsize property)

TEXTVIEW_MAX_HEIGHT是一个常量,用于定义TEXTVIEW可以具有的最大大小

每次更改textview中的文本时都会调用此函数

textview xml是这样的:

int size = CONSTANT_MAX_SIZE;
TextView tv = (TextView) findViewById(R.id.textview1)
while(Math.abs(tv.getMeasuredHeight()) >= TEXTVIEW_MAX_HEIGHT) {
    size--;
    tv.setTextSize(size);
    tv.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
    i++;
}
<TextView
     android:id="@+id/textview1"
     android:layout_width="200dp"
     android:layout_height="wrap_content"
     android:singleLine="false"
     android:inputType="textMultiLine"
     android:text=""
     android:textSize="150sp" />
public int getHeightOfMultiLineText(String text,int textSize, int maxWidth) {
    paint = new TextPaint();
    paint.setTextSize(textSize);
    int index = 0;
    int linecount = 0;
    while(index < text.length()) {
        index += paint.breakText(text,index,text.length,true,maxWidth,null);
        linecount++;
    }

    Rect bounds = new Rect();
    paint.getTextBounds("Yy", 0, 2, bounds);
    // obtain space between lines
    double lineSpacing = Math.max(0,((lineCount - 1) * bounds.height()*0.25)); 

    return (int)Math.floor(lineSpacing + lineCount * bounds.height());

由于XML中的宽度会受到限制,因此只需要考虑视图的高度,因为在需要时调整视图会自动创建多行

虽然这是一个潜在的解决方案,但它的工作并不完美(远远不是),并且它不支持向下调整大小(当您删除文本时)


有什么建议和/或想法吗?

当我等待这个问题的可能解决方案时,我一直在尝试并试图找出答案

这个问题最接近的解决方案是基于paint的方法

基本上,paint有一个名为“breaktext”的方法,该方法:

公共int-breakText(字符序列文本、int-start、int-end、布尔值 测量向前,浮点最大宽度,浮点[]测量宽度)

在API级别1中添加

测量文本,如果测量的宽度超过 最大宽度。返回已测量的字符数,如果 measuredWidth不为空,请在其中返回实际测量的宽度

我将其与绘画“getTextBounds”相结合,其中:

public void getTextBounds(字符串文本、int-start、int-end、Rect-bounds)

在API级别1中添加

在边界内返回(由调用方分配)包含所有>字符的最小矩形,其隐含原点为(0,0)

现在我可以得到适合给定宽度的字符数和这些字符的高度

使用while,您可以继续移动要测量的字符串中的删除字符,并获得行数(使用while(index 此外,还必须为每两行添加一个可变高度,这两行表示行之间的空间(不计入getTextBounds)

作为示例代码,了解多行文本高度的函数如下所示:

int size = CONSTANT_MAX_SIZE;
TextView tv = (TextView) findViewById(R.id.textview1)
while(Math.abs(tv.getMeasuredHeight()) >= TEXTVIEW_MAX_HEIGHT) {
    size--;
    tv.setTextSize(size);
    tv.measure(MeasureSpec.UNSPECIFIED,MeasureSpec.UNSPECIFIED);
    i++;
}
<TextView
     android:id="@+id/textview1"
     android:layout_width="200dp"
     android:layout_height="wrap_content"
     android:singleLine="false"
     android:inputType="textMultiLine"
     android:text=""
     android:textSize="150sp" />
public int getHeightOfMultiLineText(String text,int textSize, int maxWidth) {
    paint = new TextPaint();
    paint.setTextSize(textSize);
    int index = 0;
    int linecount = 0;
    while(index < text.length()) {
        index += paint.breakText(text,index,text.length,true,maxWidth,null);
        linecount++;
    }

    Rect bounds = new Rect();
    paint.getTextBounds("Yy", 0, 2, bounds);
    // obtain space between lines
    double lineSpacing = Math.max(0,((lineCount - 1) * bounds.height()*0.25)); 

    return (int)Math.floor(lineSpacing + lineCount * bounds.height());
不幸的是,就我所知,这是我从上面的图片中获得这一方面的唯一方法


希望这能对任何试图克服这一障碍的人有所帮助。

你在这个问题上有一个很好的解决方案,但我从不同的角度看了这个问题。我认为这种逻辑更简单,更容易理解,至少对于新的android开发者来说是这样。 该思想的基础是在大字符串的空格之间插入“\n”字符。然后,我将textView中编辑的字符串设置为显示文本。 下面是代码

private String insertNewLineCharAtString(String str, int step){
    StringBuilder sb = new StringBuilder();
    int spaceCounter = 0;
    String[] strArray = str.split(" ");
    for(int i = 0; i < strArray.length; i++){



        if(spaceCounter == step){
            sb.append('\n');
            sb.append(strArray[i]);
            spaceCounter = 0;
        }else{
            sb.append(" "+strArray[i]);
        }
        spaceCounter++;


    }
    return sb.toString();
}

希望这能帮助你们中的许多人,让你们不想深入了解TextPaint、Rects和math函数。

可编译的、已修复的代码:复制粘贴此代码,而不是已接受的代码,因为您需要修复它:)


谢谢你的解决方案,你是超人!我已经在TextView的派生类中实现了您的代码。该代码被转换为Xamarin android的C#代码。如果需要,您可以轻松地转换为Java(删除Java的第一个构造函数)

公共类AutoFitTextView:TextView
{
公共AutoFitTextView(System.IntPtr javaReference,Android.Runtime.jnihandle所有权转移)
:base(javaReference,transfer)
{
}
公共AutoFitTextView(上下文)
:基本(上下文)
{
}
公共AutoFitTextView(上下文上下文,IAttributeSet属性)
:base(上下文、属性)
{
}
公共void ResizeFontSize()
{
int textSize=50;
int maxHeight=这个.Height;
while(GetHeightOfMultiLineText(this.Text、textSize、this.Width)>maxHeight)
{
文本大小--;
}
float scaleFactor=Context.Resources.DisplayMetrics.ScaledDensity;
浮动附加系数=1.2f;
TextSize=((浮点)(TextSize/(additionalFactor*scaleFactor));
}
私有int GetHeightOfMultiLineText(字符串文本、int textSize、int maxWidth)
{
TextPaint paint=新的TextPaint();
paint.TextSize=TextSize;
int指数=0;
int lineCount=0;
while(索引
下面是AXML代码

        <touchtest.AutoFitTextView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/tvLabel2"
        android:singleLine="false"
        android:inputType="textMultiLine"
        android:text="I am here To test this text" />

使用,我编写了一个TextView派生类,它可以自动调整文本大小并支持多行

import android.content.Context;
import android.os.Handler;
import android.text.Layout;
import android.text.TextPaint;
import android.text.TextUtils.TruncateAt;
import android.util.AttributeSet;
import android.util.TypedValue;

public class AutoResizeTextView extends TextView {

    private Handler measureHandler = new Handler();
    private Runnable requestLayout = new Runnable() {
        @Override
        public void run() {
            requestLayout();
        }
    };

    public AutoResizeTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public AutoResizeTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public AutoResizeTextView(Context context) {
        super(context);
    }

    @Override
    protected void onMeasure(final int widthMeasureSpec,
                             final int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        final float maxWidth = getWidth();
        final float maxHeight = getHeight();
        if (maxWidth < 1.0f || maxHeight < 1.0f) {
            return;
        }

        int index = 0;
        int lineCount = 0;
        CharSequence text = getText();
        final TextPaint paint = getPaint();
        while (index < text.length()) {
            index += paint.breakText(text, index, text.length(), true, maxWidth, null);
            lineCount++;
        }
        final float height = lineCount * getLineHeight() + (lineCount > 0 ?
                (lineCount - 1) * paint.getFontSpacing() : 0);
        if (height > maxHeight) {
            final float textSize = getTextSize();
            setTextSize(TypedValue.COMPLEX_UNIT_PX, (textSize - 1));
            measureHandler.post(requestLayout);
        }
    }
}
导入android.content.Context;
导入android.os.Handler;
导入android.text.Layout;
导入android.text.TextPaint;
导入android.text.TextUtils.TruncateAt;
导入android.util.AttributeSet;
导入android.util.TypedValue;
公共类AutoResizeTextView扩展了TextView{
私有处理程序measureHandler=新处理程序();
private Runnable requestLayout=new Runnable(){