Reputation: 4166
I am coming to Android from an iOS developer background and am having some difficulty getting ConstraintLayout to work correctly when adding views programatically.
I have a very simple activity with a ConstraintLayout and a single button that I placed inside of the Android Studio design window. When the button is pressed I am adding a textView and another button. I am trying to constrain these such that they are the same distance from the top of the ConstraintLayout, and the leading edge of the textView is constrained to the left side of the ConstraintLayout, and the button is constrained to the right side of the ConstraintLayout.
My XML follows:
<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:id="@+id/parentViewConstraintLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@android:color/holo_orange_dark"
tools:context=".MainActivity">
<Button
android:id="@+id/addWidgetButton"
style="@style/Widget.AppCompat.Button.Borderless"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="28dp"
android:layout_marginEnd="8dp"
android:layout_marginStart="8dp"
android:fontFamily="@font/muli_bold"
android:text="Add New Widget"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</android.support.constraint.ConstraintLayout>
And the Kotlin in question
addWidgetButton.setOnClickListener() {
val textView = TextView(this)
textView.setTextColor(Color.BLACK)
textView.setTextSize(20f)
textView.setText("Text message for testing")
val newButton = Button(this)
newButton.setText("Push me")
parentViewConstraintLayout.addView(textView)
parentViewConstraintLayout.addView(newButton)
val constraintSet = ConstraintSet()
constraintSet.clone(parentViewConstraintLayout)
constraintSet.connect(textView.id, ConstraintSet.TOP, parentViewConstraintLayout.id, ConstraintSet.TOP, 10)
constraintSet.connect(textView.id, ConstraintSet.START, parentViewConstraintLayout.id, ConstraintSet.START, 10)
constraintSet.connect(newButton.id, ConstraintSet.END, parentViewConstraintLayout.id, ConstraintSet.END, 30)
constraintSet.connect(newButton.id, ConstraintSet.TOP, parentViewConstraintLayout.id, ConstraintSet.TOP, 50)
constraintSet.applyTo(parentViewConstraintLayout)
}
When the button is pressed, instead of the expected behavior I get this:
If I comment out some code so that I only add one view (either the button or the textView) it works correctly. There is some strange interaction between them that I don't understand.
Upvotes: 1
Views: 1440
Reputation: 27246
I am trying to constrain these such that they are the same distance from the top of the ConstraintLayout, and the leading edge of the textView is constrained to the left side of the ConstraintLayout, and the button is constrained to the right side of the ConstraintLayout.
Ok, so if I don’t get that wrong… what you want is a TextView and a Button side by side, correct?
| [TextView] [Button]|
or
| [TextView][Button] |
or
| [TextView ][Button ]|
or
?
Depending what you want, the constraints have to be different.
Additionally, you say:
they are the same distance from the top of the ConstraintLayout
This means that they will effectively be on top of the previous one if you keep pressing the button, is this intended?
Or did you mean “I want them below the previous, respecting the “top margin” so the vertical space between each element is the same?”
In any case, you should (since you’re using CL 1.0.2) correctly specify all the attributes of these Views.
Think of AutoLayout, unless a View has an intrinsic size, you need to pin the start/end/top/bottom before the algorithm can determine where the view must go.
Anyway back to your sample…
I added
textView.id = View.generateViewId()
and
newButton.id = View.generateViewId()
and ran your code and it works… but each new “pair” of button/text is added on top.
If you need to do |[Tv ][btn]|
you can simply add these two:
textView.layoutParams = Constraints.LayoutParams(ConstraintSet.MATCH_CONSTRAINT, ConstraintSet.WRAP_CONTENT)
and
constraintSet.connect(textView.id, ConstraintSet.END, newButton.id, ConstraintSet.START, 10)
that should give you that.
Upvotes: 1
Reputation: 62841
ConstraintLayout
constraints work with resource ids. I see where you create the TextView
and Button
, but I don't see where you set the ids for these views. Maybe some Kotlin magic?
For API 17+, you can use View.generateViewId()
to generate the id and View.setId()
to set it. You can then refer to the ids in the ConstraintSet
. Right now they are both View.NO_ID
..
I will also add that if you want to refer to the parent as a constraint it is ConstraintSet.PARENT_ID
.
Upvotes: 3