web-dev-qa-db-ja.com

プログラムでレイアウトリソースを作成するKotlin Android

このレイアウトを完全にプログラムで作成しようとすると問題が発生します。プロセスを実行するたびに、アプリがクラッシュして失敗します。

プログラムで作成しようとしているXML imの部分はそれです:

<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>

そして私は次のkotlinコードでそれを再作成しようとしています:

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)


}

これはtru 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) 

私はまだそれが何であるかについて調査しています、それが間違ったLayoutParamsの可能性があるのではないかと疑っていますが、これらのリソースをプログラムで正しく設定する方法についてはあまり明確ではありません...

前もって感謝します。

PD:何か見つけたらアップデートします。

どんな助けでも大歓迎です!

アップデート1.0:

Logcatをたどって、子の親でremoveViewを呼び出さなければなりませんが、私は正確にどこがわからないのですか...それを探しています...

5
Jr Jimnz

解決策は次のとおりです:

子を追加する前に、すべての親にremoveAllViewを追加するだけです

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)
}

NSionに感謝します。logcatのエラーは私に正しい方向を示しています!

4
Jr Jimnz

上記の答えに触発されました。これは私のヘルパー関数です。

OnViewCreated内

val titleCard = createNumberCard()
        val verse1Card:CardView = createVerseCard()

        detailLinearLayout.addView(titleCard, 0)
        detailLinearLayout.addView(verse1Card, 1)
private fun createVerseCard(): CardView {
        //verseCard
        val verseCard = CardView(requireActivity())
        verseCard.setId(View.generateViewId())

        val verseCardLayout = ConstraintLayout(activity)
        verseCardLayout.layoutParams = ConstraintLayout.LayoutParams(
            ConstraintLayout.LayoutParams.MATCH_PARENT,
            ConstraintLayout.LayoutParams.MATCH_PARENT
        )

        verseCard.addView(verseCardLayout)

        val set = ConstraintSet()

        val verseView = TextView(activity)
        verseView.text = "Verse 1"
        verseView.setId(View.generateViewId())

        verseCardLayout.addView(verseView, 0)

        set.clone(verseCardLayout)

        set.connect(
            verseView.getId(),
            ConstraintSet.TOP,
            verseCardLayout.getId(),
            ConstraintSet.TOP,
            0
        )

        set.applyTo(verseCardLayout)
        return verseCard
    }

フラグメントでこれらを使用しています。