Reputation: 1085
I am trying to align my textview in the constraint layout without using margins so the layout can be responsive in all the devices but so far I am stuck in positioning. Here is my code and expected output attached in the image. I just want to make the amount align slightly with currency text.
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/year_bar_chart_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Total"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<TextView
android:id="@+id/yearBarChartCurrency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RM"
app:layout_constraintEnd_toEndOf="@+id/yearBarChartAmount"
app:layout_constraintHorizontal_bias="0.17"
app:layout_constraintStart_toStartOf="@id/year_bar_chart_total"
app:layout_constraintTop_toBottomOf="@id/year_bar_chart_total"
tools:text="RM"/>
<TextView
android:id="@+id/yearBarChartAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="tOTAL"
app:layout_constraintHorizontal_bias="0.17"
app:layout_constraintStart_toEndOf="@id/yearBarChartCurrency"
app:layout_constraintTop_toBottomOf="@id/year_bar_chart_total"
tools:text="233.34"/>
</android.support.constraint.ConstraintLayout>
Upvotes: 2
Views: 2900
Reputation: 62831
I assume you want to align the tops of the text.
A TextView
has an internal structure based upon the typography of the font. "Android 101: Typography" has a good explanation of Android typography. This diagram is particularly useful.
So, the following layout looks like this in design view. As you can see, the tops of the text do not line up.
activity_main.xml
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#4778C5"
android:orientation="vertical"
tools:context=".MainActivity">
<TextView
android:id="@+id/year_bar_chart_total"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:alpha="0.7"
android:text="Balance"
android:textColor="@android:color/white"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/yearBarChartCurrency"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RM"
android:textColor="@android:color/white"
android:textSize="24sp"
app:layout_constraintStart_toStartOf="@+id/year_bar_chart_total"
app:layout_constraintTop_toBottomOf="@+id/year_bar_chart_total"
tools:text="RM" />
<TextView
android:id="@+id/yearBarChartAmount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingStart="4sp"
android:paddingLeft="4sp"
android:text="233.34"
android:textColor="@android:color/white"
android:textSize="36sp"
android:textStyle="bold"
app:layout_constraintStart_toEndOf="@+id/yearBarChartCurrency"
app:layout_constraintTop_toTopOf="@+id/yearBarChartCurrency" />
</android.support.constraint.ConstraintLayout>
Although the fonts of the TextViews
are the same, the different font sizes prevent alignment of the tops of the actual text even though the TextViews
have their tops align. This is because the metrics differ.
So, to align the actual tops of the text, we need to determine how far below the TextView
tops the actual text starts and shift the text by those amounts. The following code does this. Comments are in the code.
MainActivity.java
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
TextView yearBarChartAmount = findViewById(R.id.yearBarChartAmount);
TextView yearBarChartCurrency = findViewById(R.id.yearBarChartCurrency);
yearBarChartCurrency.setTranslationY(-getTopOfText(yearBarChartCurrency));
yearBarChartAmount.setTranslationY(-getTopOfText(yearBarChartAmount));
}
private int getTopOfText(TextView textView) {
// Force measure of text pre-layout.
textView.measure(0, 0);
// bounds will store the rectangle that will circumscribe the text.
Rect bounds = new Rect();
// Get the bounds for the text. Top and bottom are measured from the baseline. Left
// and right are measured from 0.
String text = (String) textView.getText();
textView.getPaint().getTextBounds(text, 0, text.length(), bounds);
return textView.getBaseline() + bounds.top;
}
}
The following is what is displayed:
There may be other considerations, but this is the gist of the solution. It may be worthwhile to encapsulate this into a custom TextView
.
Upvotes: 2
Reputation: 7661
You can use guidelines to achieve this :
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.1" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.25" />
<TextView
android:id="@+id/textView4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="balance"
app:layout_constraintBottom_toTopOf="@+id/textView5"
app:layout_constraintStart_toStartOf="@+id/guideline3" />
<TextView
android:id="@+id/textView5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="RM"
app:layout_constraintBottom_toTopOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="@+id/guideline3" />
<TextView
android:id="@+id/textView8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="233.34"
app:layout_constraintEnd_toStartOf="@+id/guideline4"
app:layout_constraintStart_toEndOf="@+id/textView5"
app:layout_constraintTop_toBottomOf="@+id/textView4" />
It will look like this:
I must emphasize one thing that really bothered me:
"margins so the layout can be responsive in all the devices" - this is not true and let me explain.
what makes your screen responsive to all screen sizes is constraintLayout and how you use it, I agree that a large number of margin in dp
will make your screen not responsive but small margins are recommended to use in google material design - it will actually give your app better look and prevent your views from being attached directly to the parent border.
Upvotes: 2