我最近在SO上阅读了很多关于自动调整文本大小的线程,以便填充其视图,这是四年前开始的最全面的this one。还在继续(虽然它涉及必须包装的文本,这不是我在下面的代码中所做的)。对于刚接触Java(和Android)的人来说,一些答案的剪切复杂性是令人难以置信的,所以我抓住了最简单的一些,posted by Sander就在几个月前。我已根据自己的需要对其进行了重新设计,但为了使其正常工作,我必须在计算中包含屏幕密度,而我不明白为什么。我希望有人可以向我解释,因为它让我疯狂。 (我无法回复Sander的帖子,因为我在SO上还是新手。)
我已经完整地发布了下面的代码,包括我在放入脑中时所提出的所有评论,以防它对其他人有用。 (抱歉由于我的经验不足导致错误或效率低下。)
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.view.WindowManager;
import android.widget.Button;
/*--------------------------------------------------------------------------------------------------
* Defines a subclass of Button, myButton, that has a "resize" method. The text size is set so that
* the desired button text fits inside the rectangles formed by dividing the screen into a grid of
* rows and columns (which are a grid of buttons in the original application). Note that all of the
* text will appear on a single line, rather than wrapping.
*
* Example usage:
* (Button) findViewById(R.id.button)).setText(text);
* ((myButton) findViewById(R.id.button)).resize(text, 2, 3);
*
* Make sure "Button" is replaced by "myButton" in the .xml and in any casting in the code that uses
* the resize method.
*
* "Button" could easily be substituted for other views and the dimensions of the desired rectangle
* could be provided explicitly rather than calculated.
*------------------------------------------------------------------------------------------------*/
public class myButton extends Button {
// Inherit constructor from the Button superclass
public myButton (Context context, AttributeSet attrs) {
super(context, attrs);
}
public void resize (String text, int rows, int cols) {
// Get the screen's physical dimensions, in pixels
DisplayMetrics metrics = new DisplayMetrics();
((WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay().getMetrics(metrics);
float width = metrics.widthPixels;
float height = metrics.heightPixels;
float density = metrics.density; // px = dp * density. Used in the calculations, below.
// Modify the width and height to get the effective size of the rectangle that text needs to
// fit inside. The "fraction" variable reduces the rectangle further (e.g. to 90%) to allow
// for error or margins/padding.
float fraction = 0.90f;
float effectiveWidth = ( width / cols ) * fraction ;
float effectiveHeight = ( height / rows ) * fraction ;
// Calculate how many pixels the text would require if the font size was set to an arbitrary
// value
Paint p = new Paint();
Rect bounds = new Rect();
int testTextSize = 1000; // Arbitrary, but large enough to reduce round-off errors
p.setTextSize( testTextSize * density ); // WHY DO I HAVE TO MULTIPLY BY THE DENSITY?
p.getTextBounds(text,0,text.length(),bounds);
// Scale the text in each direction so that it would exactly fit in the space available
float textSizeToFitWidth = testTextSize * ( effectiveWidth / (bounds.width() * density) ); // WHY DO I HAVE TO MULTIPLY BY THE DENSITY?
float textSizeToFitHeight = testTextSize * ( effectiveHeight / (bounds.height() * density) );
// Choose the smaller of these two text sizes, so that the text fits in both directions
int textSize = (int) Math.min( textSizeToFitWidth, textSizeToFitHeight );
// Change the text size of the myButton view:
setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize);
}
}
如果Rect.width()
和Rect.height()
返回dp中的值(是吗?文档不是吗?),我可以理解将它们乘以density
,以保留所有内容像素。但是,为什么我必须将testTextSize
乘以density
(已经是像素?)?
或者它是一个侥幸,计算是错误的,但恰好出现了大致正确的答案,以便它看起来像它的工作?