안드로이드에서 텍스트 뷰의 텍스트 크기를 차지하는 공간에 맞게 텍스트 크기를 조정하는 방법이 있습니까?
예를 들어 a를 사용하고 각 행에 s를 TableLayout
추가하고 TextView
있습니다. TextView
s가 텍스트를 줄 바꿈하고 싶지 않기 때문에 내용의 글꼴 크기가 줄어 듭니다.
어떤 아이디어?
나는 시도 measureText
했지만 열의 크기를 모르기 때문에 사용하기가 까다로워 보입니다. 이것은 글꼴 크기를 적합한 것으로 변경하려는 코드입니다.
TableRow row = new TableRow(this);
for (int i=0; i < ColumnNames.length; i++) {
TextView textColumn = new TextView(this);
textColumn.setText(ColumnNames[i]);
textColumn.setPadding(0, 0, 1, 0);
textColumn.setTextColor(getResources().getColor(R.drawable.text_default));
row.addView(textColumn, new TableRow.LayoutParams());
}
table.addView(row, new TableLayout.LayoutParams());
답변
아래 솔루션은 여기에 모든 제안을 통합합니다. Dunni가 처음 게시 한 것으로 시작합니다. gjpc와 같은 이진 검색을 사용하지만 좀 더 읽기 쉽습니다. 그것은 또한 그렘의 버그 수정과 내 버그 수정을 포함합니다.
import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
public class FontFitTextView extends TextView {
public FontFitTextView(Context context) {
super(context);
initialise();
}
public FontFitTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialise();
}
private void initialise() {
mTestPaint = new Paint();
mTestPaint.set(this.getPaint());
//max size defaults to the initially specified text size unless it is too small
}
/* Re size the font so the specified text fits in the text box
* assuming the text box is the specified width.
*/
private void refitText(String text, int textWidth)
{
if (textWidth <= 0)
return;
int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
float hi = 100;
float lo = 2;
final float threshold = 0.5f; // How close we have to be
mTestPaint.set(this.getPaint());
while((hi - lo) > threshold) {
float size = (hi+lo)/2;
mTestPaint.setTextSize(size);
if(mTestPaint.measureText(text) >= targetWidth)
hi = size; // too big
else
lo = size; // too small
}
// Use lo so that we undershoot rather than overshoot
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int height = getMeasuredHeight();
refitText(this.getText().toString(), parentWidth);
this.setMeasuredDimension(parentWidth, height);
}
@Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
refitText(text.toString(), this.getWidth());
}
@Override
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
if (w != oldw) {
refitText(this.getText().toString(), w);
}
}
//Attributes
private Paint mTestPaint;
}
답변
TextView를 확장하고 이것을 수행하는 클래스를 작성했습니다. 제안한대로 measureText를 사용합니다. 기본적으로 최대 텍스트 크기와 최소 텍스트 크기 (변경 가능)가 있으며 가장 큰 텍스트를 찾을 때까지 그 사이의 크기를 1 씩 줄입니다. 특별히 우아하지는 않지만 다른 방법은 모르겠습니다.
코드는 다음과 같습니다.
import android.content.Context;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.widget.TextView;
public class FontFitTextView extends TextView {
public FontFitTextView(Context context) {
super(context);
initialise();
}
public FontFitTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialise();
}
private void initialise() {
testPaint = new Paint();
testPaint.set(this.getPaint());
//max size defaults to the intially specified text size unless it is too small
maxTextSize = this.getTextSize();
if (maxTextSize < 11) {
maxTextSize = 20;
}
minTextSize = 10;
}
/* Re size the font so the specified text fits in the text box
* assuming the text box is the specified width.
*/
private void refitText(String text, int textWidth) {
if (textWidth > 0) {
int availableWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
float trySize = maxTextSize;
testPaint.setTextSize(trySize);
while ((trySize > minTextSize) && (testPaint.measureText(text) > availableWidth)) {
trySize -= 1;
if (trySize <= minTextSize) {
trySize = minTextSize;
break;
}
testPaint.setTextSize(trySize);
}
this.setTextSize(trySize);
}
}
@Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
refitText(text.toString(), this.getWidth());
}
@Override
protected void onSizeChanged (int w, int h, int oldw, int oldh) {
if (w != oldw) {
refitText(this.getText().toString(), w);
}
}
//Getters and Setters
public float getMinTextSize() {
return minTextSize;
}
public void setMinTextSize(int minTextSize) {
this.minTextSize = minTextSize;
}
public float getMaxTextSize() {
return maxTextSize;
}
public void setMaxTextSize(int minTextSize) {
this.maxTextSize = minTextSize;
}
//Attributes
private Paint testPaint;
private float minTextSize;
private float maxTextSize;
}
답변
이것은 speedplane ‘sFontFitTextView
이지만 텍스트를 맞추기 위해 필요한 경우 에만 글꼴 크기를 줄이고 그렇지 않으면 글꼴 크기를 유지합니다. 높이에 맞게 글꼴 크기를 늘리지 않습니다.
public class FontFitTextView extends TextView {
// Attributes
private Paint mTestPaint;
private float defaultTextSize;
public FontFitTextView(Context context) {
super(context);
initialize();
}
public FontFitTextView(Context context, AttributeSet attrs) {
super(context, attrs);
initialize();
}
private void initialize() {
mTestPaint = new Paint();
mTestPaint.set(this.getPaint());
defaultTextSize = getTextSize();
}
/* Re size the font so the specified text fits in the text box
* assuming the text box is the specified width.
*/
private void refitText(String text, int textWidth) {
if (textWidth <= 0 || text.isEmpty())
return;
int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
// this is most likely a non-relevant call
if( targetWidth<=2 )
return;
// text already fits with the xml-defined font size?
mTestPaint.set(this.getPaint());
mTestPaint.setTextSize(defaultTextSize);
if(mTestPaint.measureText(text) <= targetWidth) {
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, defaultTextSize);
return;
}
// adjust text size using binary search for efficiency
float hi = defaultTextSize;
float lo = 2;
final float threshold = 0.5f; // How close we have to be
while (hi - lo > threshold) {
float size = (hi + lo) / 2;
mTestPaint.setTextSize(size);
if(mTestPaint.measureText(text) >= targetWidth )
hi = size; // too big
else
lo = size; // too small
}
// Use lo so that we undershoot rather than overshoot
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int height = getMeasuredHeight();
refitText(this.getText().toString(), parentWidth);
this.setMeasuredDimension(parentWidth, height);
}
@Override
protected void onTextChanged(final CharSequence text, final int start,
final int before, final int after) {
refitText(text.toString(), this.getWidth());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh) {
refitText(this.getText().toString(), w);
}
}
}
다음은 xml에서 어떻게 사용되는지에 대한 예입니다.
<com.your.package.activity.widget.FontFitTextView
android:id="@+id/my_id"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="My Text"
android:textSize="60sp" />
텍스트가 너비에 맞는 한 글꼴 크기를 60sp로 유지합니다. 텍스트가 더 길면 글꼴 크기가 줄어 듭니다. 이 경우 TextView
s 높이도로 인해 변경됩니다 height=wrap_content
.
버그를 발견하면 자유롭게 편집하십시오.
답변
다음은 에뮬레이터와 전화에서 작동하지만 Eclipse 레이아웃 편집기에서는 잘 작동하지 않는 솔루션입니다. kilaka의 코드에서 영감을 얻었지만 텍스트의 크기는 Paint에서 얻지 않고 TextView 자체를 호출하여 측정하여 얻습니다 measure(0, 0)
.
자바 클래스 :
public class FontFitTextView extends TextView
{
private static final float THRESHOLD = 0.5f;
private enum Mode { Width, Height, Both, None }
private int minTextSize = 1;
private int maxTextSize = 1000;
private Mode mode = Mode.None;
private boolean inComputation;
private int widthMeasureSpec;
private int heightMeasureSpec;
public FontFitTextView(Context context) {
super(context);
}
public FontFitTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public FontFitTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray tAttrs = context.obtainStyledAttributes(attrs, R.styleable.FontFitTextView, defStyle, 0);
maxTextSize = tAttrs.getDimensionPixelSize(R.styleable.FontFitTextView_maxTextSize, maxTextSize);
minTextSize = tAttrs.getDimensionPixelSize(R.styleable.FontFitTextView_minTextSize, minTextSize);
tAttrs.recycle();
}
private void resizeText() {
if (getWidth() <= 0 || getHeight() <= 0)
return;
if(mode == Mode.None)
return;
final int targetWidth = getWidth();
final int targetHeight = getHeight();
inComputation = true;
float higherSize = maxTextSize;
float lowerSize = minTextSize;
float textSize = getTextSize();
while(higherSize - lowerSize > THRESHOLD) {
textSize = (higherSize + lowerSize) / 2;
if (isTooBig(textSize, targetWidth, targetHeight)) {
higherSize = textSize;
} else {
lowerSize = textSize;
}
}
setTextSize(TypedValue.COMPLEX_UNIT_PX, lowerSize);
measure(widthMeasureSpec, heightMeasureSpec);
inComputation = false;
}
private boolean isTooBig(float textSize, int targetWidth, int targetHeight) {
setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
measure(0, 0);
if(mode == Mode.Both)
return getMeasuredWidth() >= targetWidth || getMeasuredHeight() >= targetHeight;
if(mode == Mode.Width)
return getMeasuredWidth() >= targetWidth;
else
return getMeasuredHeight() >= targetHeight;
}
private Mode getMode(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
if(widthMode == MeasureSpec.EXACTLY && heightMode == MeasureSpec.EXACTLY)
return Mode.Both;
if(widthMode == MeasureSpec.EXACTLY)
return Mode.Width;
if(heightMode == MeasureSpec.EXACTLY)
return Mode.Height;
return Mode.None;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if(!inComputation) {
this.widthMeasureSpec = widthMeasureSpec;
this.heightMeasureSpec = heightMeasureSpec;
mode = getMode(widthMeasureSpec, heightMeasureSpec);
resizeText();
}
}
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after) {
resizeText();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
if (w != oldw || h != oldh)
resizeText();
}
public int getMinTextSize() {
return minTextSize;
}
public void setMinTextSize(int minTextSize) {
this.minTextSize = minTextSize;
resizeText();
}
public int getMaxTextSize() {
return maxTextSize;
}
public void setMaxTextSize(int maxTextSize) {
this.maxTextSize = maxTextSize;
resizeText();
}
}
XML 속성 파일 :
<resources>
<declare-styleable name="FontFitTextView">
<attr name="minTextSize" format="dimension" />
<attr name="maxTextSize" format="dimension" />
</declare-styleable>
</resources>
이 클래스의 최신 버전은 내 github 을 확인하십시오 . 누군가에게 유용 할 수 있기를 바랍니다. 버그가 발견되었거나 코드에 설명이 필요한 경우 Github에서 문제를 자유롭게여십시오.
답변
https://stackoverflow.com/users/234270/speedplane에 감사드립니다 . 좋은 답변입니다!
다음은 높이를 처리하고 글꼴 크기를 제한하는 maxFontSize 속성과 함께 제공되는 향상된 응답 버전입니다 (제 경우에는 유용했기 때문에 공유하고 싶었습니다).
package com.<your_package>;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.widget.TextView;
public class FontFitTextView extends TextView
{
private Paint mTestPaint;
private float maxFontSize;
private static final float MAX_FONT_SIZE_DEFAULT_VALUE = 20f;
public FontFitTextView(Context context)
{
super(context);
initialise(context, null);
}
public FontFitTextView(Context context, AttributeSet attributeSet)
{
super(context, attributeSet);
initialise(context, attributeSet);
}
public FontFitTextView(Context context, AttributeSet attributeSet, int defStyle)
{
super(context, attributeSet, defStyle);
initialise(context, attributeSet);
}
private void initialise(Context context, AttributeSet attributeSet)
{
if(attributeSet!=null)
{
TypedArray styledAttributes = context.obtainStyledAttributes(attributeSet, R.styleable.FontFitTextView);
maxFontSize = styledAttributes.getDimension(R.styleable.FontFitTextView_maxFontSize, MAX_FONT_SIZE_DEFAULT_VALUE);
styledAttributes.recycle();
}
else
{
maxFontSize = MAX_FONT_SIZE_DEFAULT_VALUE;
}
mTestPaint = new Paint();
mTestPaint.set(this.getPaint());
//max size defaults to the initially specified text size unless it is too small
}
/* Re size the font so the specified text fits in the text box
* assuming the text box is the specified width.
*/
private void refitText(String text, int textWidth, int textHeight)
{
if (textWidth <= 0)
return;
int targetWidth = textWidth - this.getPaddingLeft() - this.getPaddingRight();
int targetHeight = textHeight - this.getPaddingTop() - this.getPaddingBottom();
float hi = maxFontSize;
float lo = 2;
// final float threshold = 0.5f; // How close we have to be
final float threshold = 1f; // How close we have to be
mTestPaint.set(this.getPaint());
Rect bounds = new Rect();
while ((hi - lo) > threshold)
{
float size = (hi + lo) / 2;
mTestPaint.setTextSize(size);
mTestPaint.getTextBounds(text, 0, text.length(), bounds);
if (bounds.width() >= targetWidth || bounds.height() >= targetHeight)
hi = size; // too big
else
lo = size; // too small
// if (mTestPaint.measureText(text) >= targetWidth)
// hi = size; // too big
// else
// lo = size; // too small
}
// Use lo so that we undershoot rather than overshoot
this.setTextSize(TypedValue.COMPLEX_UNIT_PX, lo);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int height = getMeasuredHeight();
refitText(this.getText().toString(), parentWidth, height);
this.setMeasuredDimension(parentWidth, height);
}
@Override
protected void onTextChanged(final CharSequence text, final int start, final int before, final int after)
{
refitText(text.toString(), this.getWidth(), this.getHeight());
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh)
{
if (w != oldw)
{
refitText(this.getText().toString(), w, h);
}
}
}
해당 /res/values/attr.xml 파일 :
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="FontFitTextView">
<attr name="maxFontSize" format="dimension" />
</declare-styleable>
</resources>
예:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:res-auto="http://schemas.android.com/apk/res-auto"
android:id="@+id/home_Layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/background"
tools:ignore="ContentDescription" >
...
<com.<your_package>.FontFitTextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:singleLine="true"
android:text="Sample Text"
android:textSize="28sp"
res-auto:maxFontSize="35sp"/>
...
</RelativeLayout>
새 maxFontSize
속성 을 사용하려면 xmlns:res-auto="http://schemas.android.com/apk/res-auto"
예제에 표시된대로 추가해야합니다 .
답변
나는 같은 문제가 있었고 나를 위해 일하는 것처럼 보이는 수업을 썼습니다. 기본적으로 정적 레이아웃을 사용하여 별도의 캔버스에 텍스트를 그리고 맞는 글꼴 크기를 찾을 때까지 다시 측정했습니다. 아래 주제에 게시 된 수업을 볼 수 있습니다. 도움이 되길 바랍니다.
답변
이제 타사 라이브러리 나 위젯없이이 작업을 수행 할 수 있습니다. API 레벨 26의 TextView에 내장되어 있습니다.에 추가 android:autoSizeTextType="uniform"
하고 TextView
높이를 설정하십시오. 그게 다야.
https://developer.android.com/guide/topics/ui/look-and-feel/autosizing-textview.html
<?xml version="1.0" encoding="utf-8"?>
<TextView
android:layout_width="match_parent"
android:layout_height="200dp"
android:autoSizeTextType="uniform" />
TextViewCompat
호환성을 위해 사용할 수도 있습니다 .