Create Layout Resource Programmatically Kotlin Android

16,560

Ok the solution is as following:

Just need to add removeAllView on all parents before adding the childs

protected fun createXmlElement(title:String,description:String){
    val parent = LinearLayout(this)
    parent.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    parent.orientation = LinearLayout.HORIZONTAL



    //children of parent linearlayout
    val iv = ImageView(this)
    val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lp.setMargins(0, 11, 7, 0)
    iv.setLayoutParams(lp)
    iv.setImageResource(R.drawable.ic_action_play)
    iv.getLayoutParams().height = 40
    iv.getLayoutParams().width = 46


    parent.addView(iv); // lo agregamos al layout

    val relativeP = RelativeLayout(this)
    relativeP.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
            RelativeLayout.LayoutParams.MATCH_PARENT)

    val linearCH = LinearLayout(this)
    linearCH.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)
    // TextView1
    val tv1 = TextView(this)
    val lptv1 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lptv1.setMargins(0, 7, 0, 0)

    tv1.setLayoutParams(lptv1)
    tv1.setText(title) // title
    tv1.setTextSize(TypedValue.COMPLEX_UNIT_SP,25F)
    tv1.setTypeface(null, Typeface.BOLD)

    // TextView2
    val tv2 = TextView(this)
    val lptv2 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lptv2.setMargins(0, 11, 7, 0)

    tv2.setLayoutParams(lptv1)
    tv2.setText(description) // description
    tv2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25F)
    tv2.setTypeface(null, Typeface.BOLD)

    linearCH.removeAllViews()
    linearCH.addView(tv1)
    linearCH.addView(tv2)

    relativeP.removeAllViews()
    relativeP.addView(linearCH)

    // last ImageView
    val iv2 = ImageView(this)
    val lpiv2 = RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
            LinearLayout.LayoutParams.WRAP_CONTENT)

    lpiv2.setMargins(0, 11, 7, 0)
    lpiv2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
    iv2.setLayoutParams(lpiv2)
    iv2.setImageResource(R.drawable.ic_action_share)
    iv2.getLayoutParams().height = 40
    iv2.getLayoutParams().width = 46


    parent.removeAllViews()
    parent.addView(iv)
    parent.addView(relativeP)
    parent.addView(iv2)

    val finalParent = this.findViewById(R.id.contenedor) as ViewGroup

    finalParent.addView(parent)
}

Thanks NSion, the error on logcat point to me the right direction!

Share:
16,560
klys
Author by

klys

want to know a bit for about me? https://klys.dev/

Updated on June 25, 2022

Comments

  • klys
    klys almost 2 years

    I'm having problems trying to make this Layout totally programmatically, every time the process run end without success and the app crashes.

    The Part of XML im trying to create programmatically is it :

    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="horizontal">
    
            <ImageView
                android:id="@+id/idImagenPlay0"
                android:layout_width="62dp"
                android:layout_height="54dp"
                android:layout_marginRight="10dp"
                android:layout_marginTop="15dp"
                android:src="@drawable/ic_action_play" />
            <RelativeLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">
    
            <LinearLayout
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:orientation="vertical">
    
                <TextView
                    android:id="@+id/idNombre0"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="10dp"
                    android:text="Description"
                    android:textSize="25sp"
                    android:textStyle="bold" />
    
                <TextView
                    android:id="@+id/idInfo0"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginBottom="15dp"
                    android:layout_marginRight="10dp"
                    android:text="Title" />
    
            </LinearLayout>
    
            <ImageView
                android:id="@+id/idImagenShare0"
                android:layout_width="54dp"
                android:layout_height="48dp"
                android:layout_alignParentRight="true"
                android:layout_marginRight="10dp"
                android:layout_marginTop="15dp"
                android:src="@drawable/ic_action_share" />
            </RelativeLayout>
        </LinearLayout>
    

    I'm trying to recreate it with the following kotlin code:

    fun createXmlElement(title:String,description:String){
        val parent = LinearLayout(this)
        parent.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
                LinearLayout.LayoutParams.WRAP_CONTENT)
    
        parent.orientation = LinearLayout.HORIZONTAL
    
        //children of parent linearlayout
        val iv = ImageView(this)
        val lp = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT)
    
        lp.setMargins(0, 11, 7, 0)
        iv.setLayoutParams(lp)
        iv.setImageResource(R.drawable.ic_action_play)
        iv.getLayoutParams().height = 40;
        iv.getLayoutParams().width = 46;
    
        parent.addView(iv); // lo agregamos al layout
    
        val relativeP = RelativeLayout(this)
        relativeP.layoutParams = RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
                RelativeLayout.LayoutParams.MATCH_PARENT)
    
        val linearCH = LinearLayout(this)
        linearCH.layoutParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT)
        // TextView1
        val tv1 = TextView(this)
        val lptv1 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT)
    
        lptv1.setMargins(0, 7, 0, 0)
    
        tv1.setLayoutParams(lptv1)
        tv1.setText(title) // nombre de la musica
        tv1.setTextSize(TypedValue.COMPLEX_UNIT_SP,25F)
        tv1.setTypeface(null, Typeface.BOLD);
    
        // TextView2
        val tv2 = TextView(this)
        val lptv2 = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT)
    
        lptv2.setMargins(0, 11, 7, 0)
    
        tv2.setLayoutParams(lptv1)
        tv2.setText(description) // Descripcion de la musica
        tv2.setTextSize(TypedValue.COMPLEX_UNIT_SP, 25F)
        tv2.setTypeface(null, Typeface.BOLD);
    
        linearCH.addView(tv1)
        linearCH.addView(tv2)
    
        relativeP.addView(linearCH)
    
        // last ImageView
        val iv2 = ImageView(this)
        val lpiv2 = RelativeLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
                LinearLayout.LayoutParams.WRAP_CONTENT)
    
        lpiv2.setMargins(0, 11, 7, 0)
        lpiv2.addRule(RelativeLayout.ALIGN_PARENT_RIGHT)
        iv2.setLayoutParams(lpiv2)
        iv2.setImageResource(R.drawable.ic_action_share)
        iv2.getLayoutParams().height = 40;
        iv2.getLayoutParams().width = 46;
    
    
        parent.addView(iv)
        parent.addView(relativeP)
        parent.addView(iv2)
    
    
    }
    

    This is the error I'm getting in logcat

    04-27 10:51:01.224 6973-6973/com.klystru.app.appE/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.klystru.app.app, PID: 6973
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.klystru.app.app/com.klystru.app.app.MainActivity}: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2583)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2665)
        at android.app.ActivityThread.-wrap11(ActivityThread.java)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1499)
        at android.os.Handler.dispatchMessage(Handler.java:111)
        at android.os.Looper.loop(Looper.java:207)
        at android.app.ActivityThread.main(ActivityThread.java:5765)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
     Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
        at android.view.ViewGroup.addViewInner(ViewGroup.java:4453)
        at android.view.ViewGroup.addView(ViewGroup.java:4281)
        at android.view.ViewGroup.addView(ViewGroup.java:4222)
        at android.view.ViewGroup.addView(ViewGroup.java:4195)
        at com.klystru.app.app.MainActivity.createXmlElement(MainActivity.kt:284)
        at com.klystru.app.app.MainActivity.onCreate(MainActivity.kt:121)
        at android.app.Activity.performCreate(Activity.java:6309)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1113)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2530)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2665) 
        at android.app.ActivityThread.-wrap11(ActivityThread.java) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1499) 
        at android.os.Handler.dispatchMessage(Handler.java:111) 
        at android.os.Looper.loop(Looper.java:207) 
        at android.app.ActivityThread.main(ActivityThread.java:5765) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679) 
    

    I still research what it can be, I'm suspecting it may be wrong LayoutParams, but it's not really clear about how to set up correctly those resources programmatically.

    Thanks in advance.

    PD: If I found something I will update.

    Any help will be really welcome!

    UPDATE 1.0:

    Ok following the logcat I have to call removeView in child's parent, but I don't know exactly where. I am looking for that.

    • NSimon
      NSimon about 6 years
      Maybe that would be helpful to post the crash you're getting as well?
    • klys
      klys about 6 years
      Thank you!, I forget to check the logcats!! Look like i have to call removeView() first anywhere....
    • NSimon
      NSimon about 6 years
      Logcat states the error lies into the function createMusicElement(), and not in the createXmlElement() that you pasted (unless they are indeed the same, just renamed when pasted here)
    • klys
      klys about 6 years
      Yeah, they are the same, i just renamed it. Done...
    • EpicPandaForce
      EpicPandaForce about 6 years
      Is there any particular reason why you're skipping the layout inflater?
    • klys
      klys about 6 years
      @EpicPandaForce Because im new to kotlin and android layout? Just maybe...
    • EpicPandaForce
      EpicPandaForce about 6 years
      No see that makes me double not understand why you are writing it from code. You're skipping the AppCompatLayoutInflater this way. That's why people use the XML layout.
    • klys
      klys about 6 years
      @EpicPandaForce i may be new to android layout, but im not nwe to kotlin and sqlite, and i need sqlite functionality which will require a constantly changing layout, and there is where creating layout from code help a lot!
    • EpicPandaForce
      EpicPandaForce about 6 years
      No, if you need "constantly changing layout", then you need a RecyclerView.
    • klys
      klys about 6 years
      Ok, my actual approach is working fine but implementing RecyclerView i think is better than my actual code.... I will give a check, thank you for the advise!