My goal is to programmatically create and add TextView widgets to a ConstraintLayout, positioned at different angles around a circle relative to another widget, ie using the circular layout constraint.
In my activity.xml I add a TextView txtCentred
centred in the layout, and a TextView txtPositioned
positioned relative to this using the circular constraint.
At runtime, I then add new TextView widgets to the view. For each new widget I make a copy of txtPositioned.LayoutParams
, modify the circleAngle field of the copy, and set the copy on the new TextView
The result I get is that all TextViews are positioned in the same place, as if they are being positioned using the last LayoutParams
I created. They are also all sized using the size of the last TextView I added. It seems like even though the LayoutParams are separate copies, they all link to some single object behind the scenes.
One thing I noticed is that all the different LayoutParams objects's "ConstraintWidget" has the same hashcode. But maybe this is just the txtCentred widget?
Screenshot of app running in the emulator, showing all widgets positioned in the same location:
The manifest xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/parentLayout">
<TextView
android:id="@+id/txtCentred"
android:text="X"
android:layout_width="wrap_content" android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="parent"/>
<TextView
android:id="@+id/txtPositioned"
android:text="R"
android:layout_width="wrap_content" android:layout_height="wrap_content"
app:layout_constraintCircle="@id/txtCentred"
app:layout_constraintCircleRadius="80dp"
app:layout_constraintCircleAngle="10"
android:fontFamily="sans-serif-black"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintBottom_toBottomOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
The activity class
package com.example.myapplication
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.constraintlayout.widget.ConstraintLayout
class MainActivity : AppCompatActivity() {
// Add a TextView, circular positioning
@RequiresApi(Build.VERSION_CODES.M)
fun AddTextView(text: String, atAngle: Float, parent: ConstraintLayout, layoutParamsSource: TextView):TextView {
var newWidget = TextView(this)
parent.addView(newWidget)
newWidget.setTextAppearance(R.style.TextAppearance_AppCompat_Large)
var layoutParamsCopy =
ConstraintLayout.LayoutParams(layoutParamsSource.layoutParams as ConstraintLayout.LayoutParams)
layoutParamsCopy.circleAngle = atAngle
newWidget.layoutParams = layoutParamsCopy
newWidget.setText(text)
newWidget.scaleX = 5.0F
newWidget.scaleY = 5.0F
return newWidget
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var parentLayout = findViewById<View>(R.id.parentLayout) as ConstraintLayout
var txtPositioned = findViewById<View>(R.id.txtPositioned) as TextView;
// add 4 TextViews in cardinal directions relative to txtCentred
var o = AddTextView("O", 0.0F, parentLayout, txtPositioned)
o.setTextColor(Color.parseColor("#80ff0000"))
var k = AddTextView("K", 90.0F, parentLayout, txtPositioned)
k.setTextColor(Color.parseColor("#8000ff00"))
k.scaleX = 5.0F
var a = AddTextView("A", 180.0F, parentLayout, txtPositioned)
a.setTextColor(Color.parseColor("#800000ff"))
a.scaleX = 5.0F
var y = AddTextView("Y", 270.0F, parentLayout, txtPositioned)
y.setTextColor(Color.parseColor("#80ff8000"))
y.scaleX = 5.0F
Log.d("d", "o=${(o.layoutParams as ConstraintLayout.LayoutParams).circleAngle}")
Log.d("d", "k=${(k.layoutParams as ConstraintLayout.LayoutParams).circleAngle}")
Log.d("d", "a=${(a.layoutParams as ConstraintLayout.LayoutParams).circleAngle}")
Log.d("d", "y=${(y.layoutParams as ConstraintLayout.LayoutParams).circleAngle}")
}
}
LogCat debug output showing different circleAngle values for each widget:
2021-07-10 15:16:10.569 29143-29143/com.example.myapplication D/d: o=0.0
2021-07-10 15:16:10.569 29143-29143/com.example.myapplication D/d: k=90.0
2021-07-10 15:16:10.569 29143-29143/com.example.myapplication D/d: a=180.0
2021-07-10 15:16:10.569 29143-29143/com.example.myapplication D/d: y=270.0