1

I got a problem when trying to update dynamically the layoutParams of a view.

The view to update is a ConstraintLayout, and I want to dynamically change it's app:layout_constraintDimensionRatio property.

The fragment XML :

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout 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=".LevelFragment">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:id="@+id/board"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginStart="32dp"
            android:layout_marginEnd="32dp"
            android:layout_marginTop="32dp"
            android:layout_marginBottom="32dp"
            android:background="@color/black"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintDimensionRatio="1:1"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent">

        </androidx.constraintlayout.widget.ConstraintLayout>

</FrameLayout>

But when I try to change it from Kotlin fragment code

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    board = view.findViewById(R.id.board)
    // Set ratio
    val layoutParams = board!!.layoutParams as ConstraintLayout.LayoutParams
    layoutParams.dimensionRatio = "5:1"
    board!!.layoutParams = layoutParams
}

It fails with this error after debug build :

android.widget.FrameLayout$LayoutParams cannot be cast to androidx.constraintlayout.widget.ConstraintLayout$LayoutParams

So, I'm wondering why it complains about FrameLayout to ConstraintLayout cast, because the layoutParams is taken from the board View, which is a ConstraintLayout...

Does the paramsLayout refers to the parent view and not the view itself ?

And if so, how to update view dimensionRatio property ?

Thanks !

Doubidou
  • 1,573
  • 3
  • 18
  • 35
  • Layout params are provided by views parent, in this case `ConstraintLayout` is child of `FrameLayout` so the latter is responsible for laying it out. – Pawel Mar 04 '21 at 20:19
  • @Pawel Ok, I can understand that ; but most of examples I found (Stackoverflow included) cast the layoutParams with the view type, and not the parent type.. How can I update the current view property ? FrameLayout doesn't have a "dimensionRatio" property :/ – Doubidou Mar 04 '21 at 20:26
  • Also, update view.layoutParams seems to update the view and not the parent ? – Doubidou Mar 04 '21 at 20:30
  • Replace `FrameLayout` with another `ConstraintLayout` then you'll be able to use constraints. Even though params are held within the view they are parsed by its parent during layout cycle. – Pawel Mar 04 '21 at 20:32
  • It's a brain broker.. So to update specific layout property, its parent has to be of the same type ? I cannot update specific ConstraintLayout property (which is applied on itself) because its parent is a FrameLayout.. – Doubidou Mar 04 '21 at 20:35
  • Your `board` has `FrameLayout.LayoutParams` because it's a child of `FrameLayout`. – Pawel Mar 04 '21 at 20:44
  • Okay ; does this mean that `app:layout_constraintDimensionRatio="1:1"` property on the ConstraintLayout (XML) has no effect on itself, because its parent is a FrameLayout ? Otherwise, if it's legit like it is, is there a way to update it without modifying XML ? – Doubidou Mar 04 '21 at 21:04

1 Answers1

3

LayoutParams are the parameters which parent ViewGroup uses to layout its children. Each child has its own LayoutParams which has a specific type based on type of its parent. i.e. children of FrameLayout has FrameLayout.LayoutParams as their LayoutParams and children of LinearLayout has LinearLayout.LayoutParams as their LayoutParams and so on. Also they can not get cast to each other, it means you can not cast LinearLayout.LayoutParams to FrameLayout.LayoutParams since they have different implementation of LayoutParams. But all of LayoutParams have exteded ViewGroup.LayoutParams, so it is safe to cast them to ViewGroup.LayoutParams.
In your case you are casting board.layoutParams to ConstraintLayout.LayoutParams but since parent of board is a FrameLayout then its LayoutParams is of type FrameLayout.LayoutParams and can not get cast to ConstraintLayout.LayoutParams.
If you want to fix this you have to replace parent of board which is a FrameLayout with a ConstraintLayout.
Also you can read here if you want to see how LayoutParams works.

Amin Mousavi
  • 1,220
  • 10
  • 21
  • Thanks, if I understand correctly, a layout can only hold params that its parent supports ? Disappointed that AndroidStudio didn't warn me when adding these properties on the XML side – Doubidou Mar 04 '21 at 21:30
  • Yes that is exactly how it works. And I do agree with you about the disappointment part since I also got lots of crashes because of casting layout parameters to a wrong type :D – Amin Mousavi Mar 04 '21 at 21:41