Reputation: 832
Hopefully I'm not being completely thick here, but I'm unable to align the baseline of a TextView to a Guideline in a ConstraintLayout. It appears the guideline does not have a baseline, which is pretty annoying. Does anyone know how I might achieve this? Here's a bit of layout xml that doesn't work (this is within a ConstraintLayout):
<TextView
android:id="@+id/textToAlignBaseline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:maxLines="1"
android:paddingRight="6dp"
android:textAppearance="@style/TextStyles.Body"
app:layout_constraintBaseline_toBaselineOf="@+id/guidelineBottomMargin"
app:layout_constraintLeft_toLeftOf="parent" />
<Button
android:id="@+id/buttonToAlignBottom"
android:layout_width="wrap_content"
android:layout_height="39dp"
android:layout_marginRight="20dp"
android:background="@drawable/selector_button_bg"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:text="@string/clickme"
android:textAppearance="@style/TextStyles.Body"
app:layout_constraintBottom_toTopOf="@+id/guidelineBottomMargin"
app:layout_constraintRight_toRightOf="parent" />
<android.support.constraint.Guideline
android:id="@+id/guidelineBottomMargin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="20dp" />
Upvotes: 5
Views: 2929
Reputation: 855
I've found a workaround to align the text following exactly the Material Design guideline as mentioned by @robinst .
Firstly add an ImageView, with 0 as layout_width
, your desired baseline as layout_height
, no src
and baselineAlignBottom
set to true
:
<ImageView
android:id="@+id/typeTextBaseline"
android:layout_width="0dp"
android:layout_height="24dp"
android:baselineAlignBottom="true"
android:visibility="invisible"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
Then you can align your TextView's baseline to this ImageView's baseline:
<TextView
android:id="@+id/typeTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:textAppearance="@style/TextAppearance.MaterialComponents.Overline"
app:layout_constraintBaseline_toBaselineOf="@id/typeTextBaseline"
app:layout_constraintStart_toStartOf="parent" />
I found this workaround when searching all implementations of View's getBaseline
method, and the ImageView's implementation is as follow:
public int getBaseline() {
if (mBaselineAlignBottom) {
return getMeasuredHeight();
} else {
return mBaseline;
}
}
So, once you set baselineAlignBottom
to true
, the ImageView's baseline becomes its bottom edge and it is magically served as a guideline now:)
Upvotes: 0
Reputation: 31417
I had this question when I tried to implement a two-line list according to Material Design, where the "Two-line item" baseline should be 32dp from the top:
It looks like a plain View
or Guideline
doesn't have a baseline because it returns -1 from getBaseline
. So what I ended up with is using an invisible TextView
like this:
<TextView
android:id="@+id/guideline"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="32dp"
android:textSize="0sp"
android:visibility="invisible"
app:layout_constraintTop_toTopOf="parent" />
And then use app:layout_constraintBaseline_toBaselineOf="@id/guideline"
for aligning the other view to it.
Upvotes: 5
Reputation: 832
I think I might have come up with a solution, I tried extending Baseline and returning 0 from 'getBaseline' but that was never called, so I tried extending AppCompatButton instead and returning 'getMeasuredHeight' from 'getBaseline' instead (just like ImageView does when 'baselineAlignBottom' is used) and this seems to work correctly now. The TextView just needs changing to align its baseline to the button instead of the guideline. I need to clean it up with attributes similar to ImageView but this is what I've got for now:
public class ButtonBottomBaseline extends android.support.v7.widget.AppCompatButton {
public ButtonBottomBaseline(Context context) {
super(context);
}
public ButtonBottomBaseline(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ButtonBottomBaseline(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public int getBaseline() {
return getMeasuredHeight();
}
}
Upvotes: 2