Reputation: 15535
I have rectf which is drawn in canvas, based on this rectf I have drawn simple bubble alike. I want my text should be inside this bubble.
Here is what I have tried.
I have a textPaint which is initialized with textSize 30, and I'm building static layout like this.
staticLayout = StaticLayout.Builder.obtain(text, start, end, textPaint, width)
.setAlignment(Layout.Alignment.ALIGN_NORMAL)
.setTextDirection(TextDirectionHeuristics.LTR)
.setLineSpacing(0, 1.0f)
.setIncludePad(false)
.setEllipsizedWidth(10)
.setEllipsize(TextUtils.TruncateAt.START)
.setMaxLines(Integer.MAX_VALUE)
.setBreakStrategy(Layout.BREAK_STRATEGY_SIMPLE)
.setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_NONE)
.setJustificationMode(Layout.JUSTIFICATION_MODE_NONE)
.build()
From this static layout I'm getting my TextLayout's height as staticLayout.height
I want my text layout height should not exceed by 70% of my bounds height, so that my text will be always inside my bounds.
float maxTextLayoutHeight = bounds.height() * 0.70f;
And my actual static layout's height
height = staticLayout.height;
From these two values I recalculate text size and applied it to my text paint with following code.
annotationTextSize = (maxTextLayoutHeight / height) * 13;
annotationTextSize = annotationTextSize * 0.80f;
if (annotationTextSize < 25) annotationTextSize = 25; //Limited to min 25
if (annotationTextSize > 99) annotationTextSize = 99; //Limited to max 99
textPaint.setTextSize(annotationTextSize);
Here is some images
With small text size:
Text size looks perfect:
Text size looks bigger:
Any improved calculation will be much helpful.
Upvotes: 5
Views: 906
Reputation: 62841
Unfortunately, I don't think that you will be able to determine the size of the laid out text until it is laid out. Internally, autosized TextViews do measurements of the text to find the best fit through a binary search that lays out the text for each candidate text size. (See AppCompatTextViewAutoSizeHelper here.
You can borrow some code from the AppCompatTextViewAutoSizeHelper or use something simpler as the following although it will not be as quick:
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
var textSize = 99
while (mStaticLayout == null) {
var layout: StaticLayout
textPaint.textSize = textSize.toFloat()
layout = makeStaticLayout(mText, 0, mText.length, textPaint, width)
if (layout.height < height || textSize == 25) {
mStaticLayout = layout
} else {
textSize--
}
}
mStaticLayout?.draw(canvas)
}
You could also use the internal workings of TextView to get a StaticLayout that can be drawn to a canvas.
private fun makeAutoSizeView(
@StringRes textId: Int, width: Int, height: Int
): AppCompatTextView {
return AppCompatTextView(this).apply {
layoutParams = ConstraintLayout.LayoutParams(width, height)
TextViewCompat.setAutoSizeTextTypeWithDefaults(
this,
TextViewCompat.AUTO_SIZE_TEXT_TYPE_UNIFORM
)
text = resources.getString(textId)
}
}
private fun getAutoSizeLayout(width: Int, height: Int): StaticLayout {
val autoSizeTextView = makeAutoSizeView(R.string.good_to_see_you, width, height)
val widthSpec = View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY)
val heightSpec = View.MeasureSpec.makeMeasureSpec(height, View.MeasureSpec.EXACTLY)
autoSizeTextView.measure(widthSpec, heightSpec)
autoSizeTextView.layout(0, 0, width, height)
return autoSizeTextView.layout as StaticLayout
}
Upvotes: 1
Reputation: 197
I calculated the height of text to be rendered using the following method. Might be helpful
private fun getMultilineTextHeight(text: CharSequence, textPaint: TextPaint, width: Int): Int {
val alignment = Layout.Alignment.ALIGN_NORMAL
val spacingMultiplier = 1f
val spacingAddition = 0f
val includePadding = false
val staticLayout =
StaticLayout(text, textPaint, width, alignment, spacingMultiplier, spacingAddition, includePadding)
return staticLayout.height
}
Upvotes: 0