Измерение высоты текста, который будет нарисован на холсте (Android)
любой прямой способ измерить высоту текста?
Так, как я делаю это сейчас с помощью краски measureText() чтобы получить ширину, затем путем проб и ошибок найти значение, чтобы получить приблизительную высоту. Я также возился с FontMetrics, но все это похоже на приблизительные методы, которые сосут.
Я пытаюсь масштабировать вещи для разных разрешений. Я могу это сделать, но я получаю невероятно подробный код с большим количеством вычислений для определения относительных размеров. Я ненавижу это! Должен быть лучший способ.
8 ответов:
а как же краски.getTextBounds() (метода объекта)
существуют различные способы измерения высоты в зависимости от того, что вам нужно.
getTextBounds
если вы делаете что-то вроде точного центрирования небольшого количества фиксированного текста, вы, вероятно, хотите
getTextBounds. Вы можете получить ограничивающий прямоугольник, как этоRect bounds = new Rect(); mTextPaint.getTextBounds(mText, 0, mText.length(), bounds); int height = bounds.height();как вы можете видеть на следующих изображениях, разные строки будут давать разные высоты (показано на рисунке красный.)
эти разные высоты могут быть недостатком в некоторых ситуациях, когда вам просто нужна постоянная высота независимо от того, что текст. См. следующий раздел.
краски.FontMetrics
вы можете рассчитать высоту шрифта из метрики шрифта. Высота всегда одинакова, потому что она получается из шрифта, а не какой-либо конкретной текстовой строки.
Paint.FontMetrics fm = mTextPaint.getFontMetrics(); float height = fm.descent - fm.ascent;в базовая линия-это линия, на которой находится текст. Спуск, как правило, дальше всего символ будет идти ниже линии и восхождение, как правило, дальше всего символ будет идти выше линии. Чтобы получить высоту, вы должны вычесть восхождение, потому что это отрицательное значение. (Базовая линия
y=0иyуменьшает изображение на экране.)посмотрите на следующее изображение. Высоты для обеих струн являются
234.375.если вы хотите высоту строки, а не только высоту текста, вы можете сделать следующее:
float height = fm.bottom - fm.top + fm.leading; // 265.4297это
bottomиtopлинии. Ведущий (межстрочный интервал) обычно равен нулю, но вы должны добавить его в любом случае.изображения выше из этот проект. Вы можете поиграть с ним, чтобы увидеть, как метрики шрифта работа.
StaticLayout
для измерения высоты многострочного текста следует использовать
StaticLayout. Я говорил об этом в некоторых деталях в ответ, но основной способ получить эту высоту таков:String text = "This is some text. This is some text. This is some text. This is some text. This is some text. This is some text."; TextPaint myTextPaint = new TextPaint(); myTextPaint.setAntiAlias(true); myTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density); myTextPaint.setColor(0xFF000000); int width = 200; Layout.Alignment alignment = Layout.Alignment.ALIGN_NORMAL; float spacingMultiplier = 1; float spacingAddition = 0; boolean includePadding = false; StaticLayout myStaticLayout = new StaticLayout(text, myTextPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding); float height = myStaticLayout.getHeight();
@bramp ответ правильный-частично, в том, что он не упоминает, что вычисленные границы будут минимальным прямоугольником, который содержит текст полностью с неявными начальными координатами 0, 0.
это означает, что высота, например, "Py" будет отличаться от высоты "py" или "hi" или "oi" или "aw", потому что пиксельные они требуют разных высот.
это ни в коем случае не является эквивалентом FontMetrics в классическом Ява.
в то время как ширина текста не очень больно, высота.
в частности, если вам нужно вертикально выровнять по центру нарисованный текст, попробуйте получить границы текста " a " (без кавычек), вместо того, чтобы использовать текст, который вы собираетесь рисовать. Работать на меня...
вот что я имею в виду:
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.LINEAR_TEXT_FLAG); paint.setStyle(Paint.Style.FILL); paint.setColor(color); paint.setTextAlign(Paint.Align.CENTER); paint.setTextSize(textSize); Rect bounds = new Rect(); paint.getTextBounds("a", 0, 1, bounds); buffer.drawText(this.myText, canvasWidth >> 1, (canvasHeight + bounds.height()) >> 1, paint); // remember x >> 1 is equivalent to x / 2, but works much much fasterвертикальное выравнивание по центру текст означает вертикальное выравнивание по центру ограничивающего прямоугольника - что отличается для разных текстов (шапки, длинные письма и т. д.). Но то, что мы на самом деле хотим сделать, - это также выровнять базовые линии отрисованных текстов, чтобы они не казались приподнятыми или рифлеными. Итак, пока мы знаем центр самой маленькой буквы (например, "a"), мы можем повторно использовать ее выравнивание для остальных текстов. Это позволит выровнять по центру все тексты, а также выровнять их по базовой линии.
высота-это размер текста, который вы установили в переменной Paint.
другой способ узнать высоту-это
mPaint.getTextSize();
можно использовать
android.text.StaticLayoutкласс, чтобы указать необходимые границы, а затем вызватьgetHeight(). Вы можете нарисовать текст (содержащийся в макете), вызвав егоdraw(Canvas)метод.
вы можете просто получить размер текста для объекта Paint с помощью метода getTextSize (). Например:
Paint mTextPaint = new Paint (Paint.ANTI_ALIAS_FLAG); //use densityMultiplier to take into account different pixel densities final float densityMultiplier = getContext().getResources() .getDisplayMetrics().density; mTextPaint.setTextSize(24.0f*densityMultiplier); //... float size = mTextPaint.getTextSize();
вы должны использовать
Rect.width()иRect.Height(), который вернулся изgetTextBounds()вместо. Это работает для меня.
Если у кого-то еще есть проблемы, это мой код.
у меня есть пользовательский вид, который является квадратным (ширина = высота), и я хочу назначить ему символ.
onDraw()показывает, как получить высоту символа, хотя я его не использую. Символ будет отображаться в середине представления.public class SideBarPointer extends View { private static final String TAG = "SideBarPointer"; private Context context; private String label = ""; private int width; private int height; public SideBarPointer(Context context) { super(context); this.context = context; init(); } public SideBarPointer(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; init(); } public SideBarPointer(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); this.context = context; init(); } private void init() { // setBackgroundColor(0x64FF0000); } @Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec){ super.onMeasure(widthMeasureSpec, heightMeasureSpec); height = this.getMeasuredHeight(); width = this.getMeasuredWidth(); setMeasuredDimension(width, width); } protected void onDraw(Canvas canvas) { float mDensity = context.getResources().getDisplayMetrics().density; float mScaledDensity = context.getResources().getDisplayMetrics().scaledDensity; Paint previewPaint = new Paint(); previewPaint.setColor(0x0C2727); previewPaint.setAlpha(200); previewPaint.setAntiAlias(true); Paint previewTextPaint = new Paint(); previewTextPaint.setColor(Color.WHITE); previewTextPaint.setAntiAlias(true); previewTextPaint.setTextSize(90 * mScaledDensity); previewTextPaint.setShadowLayer(5, 1, 2, Color.argb(255, 87, 87, 87)); float previewTextWidth = previewTextPaint.measureText(label); // float previewTextHeight = previewTextPaint.descent() - previewTextPaint.ascent(); RectF previewRect = new RectF(0, 0, width, width); canvas.drawRoundRect(previewRect, 5 * mDensity, 5 * mDensity, previewPaint); canvas.drawText(label, (width - previewTextWidth)/2, previewRect.top - previewTextPaint.ascent(), previewTextPaint); super.onDraw(canvas); } public void setLabel(String label) { this.label = label; Log.e(TAG, "Label: " + label); this.invalidate(); } }


Comments