I need to render a quote block of arbitrary length. The text must be aligned to the left, while the block itself aligned to the right, similar to this one:
For that I'm trying a TextView
with android:width="wrap_content"
, android:gravity="start"
, and android:layout_gravity="end"
. However, this works as expected only when the text fits into single line — if text is longer than that, the TextView
behaves like this:
Raw persistence may be the only option other than giving up entirely.
— still the block behaves like match_parent
.Here's the layout (paddingRight
was replaced with layout_marginRight
for highlight purpose — the behavior is the same either way):
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:lineSpacingExtra="3.5dp"
android:paddingLeft="24dp"
android:layout_marginRight="24dp"
android:text="Raw persistence may be the only option other than giving up entirely."
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:lineSpacingExtra="3.5dp"
android:paddingLeft="24dp"
android:layout_marginRight="24dp"
android:text="Raw persistence may be the only option other than giving up entirely."
/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:textAppearance="@style/TextAppearance.AppCompat.Body1"
android:lineSpacingExtra="3.5dp"
android:paddingLeft="24dp"
android:layout_marginRight="24dp"
android:text="@string/Raw persistence may be the only option\nother than giving up entirely."
/>
</LinearLayout>
Is there a way to lay this out adequately, without having to resort to multiple strings for different device width etc? =\
OK, after some examination of TextView
's code I put together the solution that does what I need:
package com.actinarium.persistence.common;
import android.annotation.TargetApi;
import android.content.Context;
import android.os.Build;
import android.text.Layout;
import android.util.AttributeSet;
import android.widget.TextView;
public class BlockquoteTextView extends TextView {
public BlockquoteTextView(Context context) {
super(context);
}
public BlockquoteTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public BlockquoteTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public BlockquoteTextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// Now fix width
float max = 0;
Layout layout = getLayout();
for (int i = 0, size = layout.getLineCount(); i < size; i++) {
final float lineWidth = layout.getLineMax(i);
if (lineWidth > max) {
max = lineWidth;
}
}
final int height = getMeasuredHeight();
final int width = (int) Math.ceil(max) + getCompoundPaddingLeft() + getCompoundPaddingRight();
setMeasuredDimension(width, height);
}
}
The default implementation of onMeasure
does not take line widths into account unless they are broken down by \n
's (code). I used getLineMax
instead of getLineWidth
because the latter measured trailing whitespace — the culprit of misalignment in block #3 in the original post.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With