2

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:

enter image description here

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
mackenir
  • 10,801
  • 16
  • 68
  • 100
  • 1
    I ended up creating a new LayoutParams with the width/height constructor (passing `ViewGroup.LayoutParams.WRAP_CONTENT` for these parameters). This worked. – mackenir Jul 10 '21 at 16:48

0 Answers0