背景
很多时候,我们需要将TextView的字体自动调整到给定的边界 .
问题
可悲的是,即使有很多线程和帖子(和建议的解决方案)谈论这个问题(例如here,here和here),但它们都没有真正奏效 .
这就是为什么,我决定测试每一个,直到找到真正的交易 .
我认为来自这样一个textView的要求应该是:
-
应允许使用任何字体,字体,样式和字符集 .
-
应处理宽度和高度
-
没有截断,除非文本由于限制而无法适应,我们已经给它(例如:文本太长,可用尺寸太小) . 但是,如果我们愿意,我们可以请求水平/垂直滚动条,仅适用于那些情况 .
-
应允许多行或单行 . 如果是多行,请允许最大和最小行 .
-
计算不应该慢 . 使用循环找到最佳尺寸?至少要优化它,不要每次增加1个采样 .
-
如果是多行,应该允许更喜欢调整大小或使用更多行,和/或允许使用“\ n”字符自己选择行 .
我尝试过的
我已经尝试过这么多样本(包括链接的那些,我已经写过了),而且我也尝试修改它们来处理这些情况,我已经谈过了,但没有一个真正起作用 .
我做了一个示例项目,让我可以直观地看到TextView是否正确自动匹配 .
目前,我的示例项目只是随机化文本(英文字母加数字)和textView的大小,并让它保持单行,但即使这对我尝试过的任何样本都不起作用 .
这是代码(也可用here):
文件res / layout / activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
android:layout_height="match_parent" tools:context=".MainActivity">
<Button android:id="@+id/button1" android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" android:text="Button" />
<FrameLayout android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_above="@+id/button1"
android:layout_alignParentLeft="true" android:background="#ffff0000"
android:layout_alignParentRight="true" android:id="@+id/container"
android:layout_alignParentTop="true" />
</RelativeLayout>
文件src /.../ MainActivity.java
public class MainActivity extends Activity
{
private final Random _random =new Random();
private static final String ALLOWED_CHARACTERS ="qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM1234567890";
@Override
protected void onCreate(final Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final ViewGroup container=(ViewGroup)findViewById(R.id.container);
findViewById(R.id.button1).setOnClickListener(new OnClickListener()
{
@Override
public void onClick(final View v)
{
container.removeAllViews();
final int maxWidth=container.getWidth();
final int maxHeight=container.getHeight();
final FontFitTextView fontFitTextView=new FontFitTextView(MainActivity.this);
final int width=_random.nextInt(maxWidth)+1;
final int height=_random.nextInt(maxHeight)+1;
fontFitTextView.setLayoutParams(new LayoutParams(width,height));
fontFitTextView.setSingleLine();
fontFitTextView.setBackgroundColor(0xff00ff00);
final String text=getRandomText();
fontFitTextView.setText(text);
container.addView(fontFitTextView);
Log.d("DEBUG","width:"+width+" height:"+height+" text:"+text);
}
});
}
private String getRandomText()
{
final int textLength=_random.nextInt(20)+1;
final StringBuilder builder=new StringBuilder();
for(int i=0;i<textLength;++i)
builder.append(ALLOWED_CHARACTERS.charAt(_random.nextInt(ALLOWED_CHARACTERS.length())));
return builder.toString();
}
}
这个问题
有没有人知道实际工作的这个常见问题的解决方案?
即使是一个解决方案,其功能要少得多,我所写的内容,例如一个只有一定数量的文本行,并根据其大小调整其字体,但从来没有奇怪的故障和文本也得到了与可用空间相比大/小 .
GitHub项目
由于这是一个非常重要的TextView,我决定发布一个库,这样每个人都可以轻松地使用它,并为它做出贡献,here .
15 回答
感谢MartinH的简单修复here,此代码还处理
android:drawableLeft
,android:drawableRight
,android:drawableTop
和android:drawableBottom
标记 .我的回答应该会让你开心Auto Scale TextView Text to Fit within Bounds
我修改了你的测试用例:
我在这里根据android开发人员的请求发布代码:
Final effect:
Sample Layout file:
And the Java code:
Warning:
请注意Android 3.1(Honeycomb)中的这个resolved bug .
我已经修改了M-WaJeEh的答案,以考虑侧面的复合抽屉 .
getCompoundPaddingXXXX()
方法返回padding of the view + drawable space
. 参见例如:TextView.getCompoundPaddingLeft()Issue: 这修复了可用于文本的TextView空间的宽度和高度的度量 . 如果我们不考虑可绘制的大小,它将被忽略,文本将最终与drawable重叠 .
Updated segment adjustTextSize(String):
好的,我上周使用了大量重写我的代码,以适合您的测试 . 您现在可以复制1:1,它将立即起作用 - 包括
setSingleLine()
. 如果你想要极端值,请记得调整MIN_TEXT_SIZE
和MAX_TEXT_SIZE
.聚合算法如下所示:
全班可以be found here.
结果现在非常灵活 . 这与xml中声明的相同,如下所示:
...以及在测试中以编程方式构建 .
我真的希望你现在可以使用它 . 您现在可以调用
setText(CharSequence text)
来使用它 . 该课程照顾了极少数的例外,应该是坚如磐石的 . 该算法唯一支持的是:setMaxLines(x)
,其中x >= 2
但是如果你愿意的话,我已经添加了大量的评论来帮助你构建它!
Please note:
如果您只是正常使用它而不将其限制为单行,那么可能会出现如前所述的破字 . 这是 an Android feature , not
AutoFitText
的错误 . Android总是会破坏TextView太长的单词,而今后需要做的就是将单词分开,然后根据需要进行修改 .总结:您应该高度考虑重写您的测试以支持空间字符,如下所示:
这将产生非常美妙(和更现实)的结果 .
你会发现评论也可以帮助你开始这个问题 .
祝你好运和最好的问候
我的要求是
单击ScalableTextView
打开listActivity并显示各种长度的字符串项 .
选择一个列表中的文字 .
将文本设置回另一个活动中的ScalableTextView .
我提到了链接:Auto Scale TextView Text to Fit within Bounds(包括评论)和DialogTitle.java
我发现提供的解决方案很简单但不会动态地改变文本框的大小 . 当列表视图中的选定文本长度大于
ScalableTextView
中的现有文本长度时,它非常有用 . 当选择长度小于ScalableTextView
中现有文本的文本时,它不会增加文本的大小,显示较小的文本 .我修改了ScalableTextView.java以根据文本长度重新调整文本大小 . 这是我的
ScalableTextView.java
快乐编码....
Warning, bug in Android 3 (Honeycomb) and Android 4.0 (Ice Cream Sandwich)
机器人版本:3.1 - 4.04有一个bug,即TextView中的setTextSize()仅在第一次工作时(第一次调用) .
该错误在Issue 22493: TextView height bug in Android 4.0和Issue 17343: button's height and text does not return to its original state after increase and decrease the text size on HoneyComb中描述 .
解决方法是在更改大小之前向分配给TextView的文本添加换行符:
我在我的代码中使用它如下:
我在文本的左侧和右侧添加了这个“\ u3000”字符,以使其保持居中 . 如果您将其对齐到左侧,则仅附加到右侧 . 当然它也可以嵌入AutoResizeTextView小部件,但我想将修复代码保留在外面 .
现在已经有了这个问题的官方解决方案 . 使用Android O自动调整TextViews可在支持库26中获得,并且向后兼容到Android 4.0 .
https://developer.android.com/preview/features/autosizing-textview.html
我不确定为什么包含此信息的https://stackoverflow.com/a/42940171/47680已被管理员删除 .
我将解释这个属性是如何逐步降低android版本的:
1-在项目gradle文件中导入android支持库26.x.x.如果IDE上没有支持库,则会自动下载 .
2-打开布局XML文件,并像TextView一样重构这个标记 . 这种情况是:在系统上填写字体大小时,将文本拟合到可用宽度,而不是自动换行 .
将文本视图转换为图像,并在边界内缩放图像 .
以下是有关如何将视图转换为图像的示例:Converting a view to Bitmap without displaying it in Android?
问题是,你的文字将无法选择,但它应该可以解决问题 . 我没有尝试过,所以我不确定它的外观(因为缩放) .
从2018年6月起Android正式支持this feature为 Android 4.0 (API level 14) and higher.
使用Android 8.0(API级别26)及更高版本:
Android 8.0之前的Android版本(API级别26):
查看我的详细信息answer .
下面是avalancha TextView,增加了自定义Font的功能 .
用法:
不要忘记添加:xmlns:foo =“http://schemas.android.com/apk/res-auto” . 字体应该在资产中
已知错误:没有't work with Android 4.03 - fonts are invisible or very small (original avalancha doesn'也可以工作)下面是该错误的解决方法:https://stackoverflow.com/a/21851239/2075875
试试这个
如果您正在寻找更容易的东西:
快速解决@Malachiasz描述的问题
我已经通过在auto resize类中为此添加自定义支持来修复此问题:
只需调用
yourView.setTextCompat(newTextValue)
而不是yourView.setText(newTextValue)
尝试将
LayoutParams
和MaxWidth
以及MaxHeight
添加到TextView
. 它将强制布局尊重父容器而不是溢出 .从Android O开始,可以在xml中自动调整文本大小:
https://developer.android.com/preview/features/autosizing-textview.html