-1

I am designing a Feed in which I want the posts in the form of a Card which I implemented using design library of Google. I have created my layout but as the posts will be fetched dynamically therefore I wanted to dynamically create my layout in Kotlin. For that I created a function which will take Image,Title,Description as the parameters and will return a Card View Object.

To set the attributes in CardView I tried layoutParams but using it just crashed my app

 val cardViewParam = cardView.layoutParams as CoordinatorLayout.LayoutParams

In this code I tried every layout type Linear,Relative,Coordinator and even ViewGroup but my app keeps on crashing every time.

This is my layout:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView 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=".Home"
            android:background="@color/DirtyWhite"
            android:scrollbars="none">
    <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            android:tag="FEED">

//This is the card view which I want to create dynamically

        <android.support.v7.widget.CardView android:layout_width="match_parent"
                                            android:layout_height="wrap_content"
                                            android:layout_margin="5dp"
                                            android:elevation="50dp"
                                            app:cardCornerRadius="10dp">

            <LinearLayout android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:orientation="vertical"
                          android:padding="10dp"
                          android:clipToPadding="false">

                <ImageView android:layout_width="match_parent"
                           android:layout_height="180dp"
                           android:src="@drawable/sample"
                           android:scaleType="centerCrop"
                           android:layout_marginTop="-10dp"
                           android:layout_marginStart="-10dp"
                           android:layout_marginEnd="-10dp"
                           android:layout_marginBottom="-10dp"
                           android:adjustViewBounds="true"/>
                <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        style="@style/Base.TextAppearance.AppCompat.Title"
                        android:text="This is a  part of Material Design."
                        android:ellipsize="end"
                        android:maxLines="1"
                        android:layout_marginTop="16dp"
                />
                <TextView
                        android:layout_width="match_parent"
                        android:layout_height="wrap_content"
                        style="@style/TextAppearance.AppCompat.Body2"
                        android:text="This is a  part of Material Design. This is a  part of Material Design. This is a  part of Material Design. "
                        android:ellipsize="end"
                        android:textColor="@color/realGray"
                        android:maxLines="2"
                        android:layout_marginTop="8dp"
                />

                <RelativeLayout android:layout_width="match_parent"
                                android:layout_marginTop="8dp"
                                android:layout_height="wrap_content">
                    <RatingBar android:layout_width="wrap_content" android:layout_height="wrap_content"
                               android:numStars="5"
                               android:rating="3"
                               android:isIndicator="true"
                               android:layout_alignParentLeft="true"
                               android:layout_alignParentStart="true"
                               android:layout_centerInParent="true"
                               style="@style/Base.Widget.AppCompat.RatingBar.Small"/>
                    <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content"
                                  android:layout_alignParentRight="true"
                                  android:layout_alignParentEnd="true">
                        <Button android:layout_width="wrap_content" android:layout_height="wrap_content"
                                android:background="@drawable/ic_favorite_border_black_24dp"
                                android:minHeight="30dp"
                                android:minWidth="30dp"
                                android:layout_marginRight="15dp"
                                android:layout_marginEnd="15dp"
                        />
                        <Button android:layout_width="wrap_content"
                                android:layout_height="wrap_content"
                                android:text="Order Now"
                                android:background="@drawable/rounded_card_button_small"
                                android:textColor="@color/DirtyWhite"
                                android:minHeight="0dp"
                                android:minWidth="0dp"
                                android:padding="5dp"/>
                    </LinearLayout>


                </RelativeLayout>

            </LinearLayout>

        </android.support.v7.widget.CardView>


    </LinearLayout>
</ScrollView>

I tried this code to create layout dynamically: (NOTE: This code was made just to create basic Card excluding the Rating Bar and other Action Buttons)

fun createAdsPost(view: View, photo: ImageView, titleText: String, descText: String): CardView {

    val cardView = CardView(view.context)
    val cardViewParam = cardView.layoutParams as CoordinatorLayout.LayoutParams
    cardView.layoutParams = cardViewParam
    cardViewParam.width = LinearLayout.LayoutParams.MATCH_PARENT
    cardViewParam.height = LinearLayout.LayoutParams.WRAP_CONTENT
    cardViewParam.setMargins(dpToPx(5, view), dpToPx(5, view), dpToPx(5, view), dpToPx(5, view))
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
        cardView.elevation = dpToPx(50, view).toFloat()
    }
    cardView.apply {
    radius = dpToPx(10, view).toFloat()
        this.layoutParams = cardViewParam

    }
    val linear1 = LinearLayout(view.context)
     linear1.orientation = LinearLayout.VERTICAL
     linear1.setPadding(dpToPx(10, view), dpToPx(10, view), dpToPx(10, view), dpToPx(10, view))
     linear1.clipToPadding = false
     val linear1Param = linear1.layoutParams as LinearLayout.LayoutParams
     linear1Param.width = LinearLayout.LayoutParams.MATCH_PARENT
     linear1Param.height = LinearLayout.LayoutParams.WRAP_CONTENT
     linear1.layoutParams = linear1Param
     photo.scaleType = ImageView.ScaleType.CENTER_CROP
     photo.adjustViewBounds = true
     val photoParams = photo.layoutParams as LinearLayout.LayoutParams
     photoParams.apply {
         width = LinearLayout.LayoutParams.MATCH_PARENT
         height = dpToPx(180, view)
         topMargin = dpToPx(-10, view)
         bottomMargin = dpToPx(-10, view)
     }
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
         photoParams.marginStart = dpToPx(-10, view)
         photoParams.marginEnd = dpToPx(-10, view)
     }
     linear1.addView(photo)
      val title = TextView(view.context) 
       title.apply {
           ellipsize = TextUtils.TruncateAt.END
           maxLines = 1
           text = titleText
       }
       val titleTextParams = title.layoutParams as LinearLayout.LayoutParams
       titleTextParams.apply {
           width = LinearLayout.LayoutParams.MATCH_PARENT
           height = LinearLayout.LayoutParams.WRAP_CONTENT
           topMargin = dpToPx(16, view)
       }
      linear1.addView(title)
     val desc = TextView(view.context)
      desc.apply {
          ellipsize = TextUtils.TruncateAt.END
          maxLines = 2
          text = descText
          setTextColor(Color.parseColor("#626567"))
      }
      val descTextParams = desc.layoutParams as LinearLayout.LayoutParams
      descTextParams.apply {
          width = LinearLayout.LayoutParams.MATCH_PARENT
          height = LinearLayout.LayoutParams.WRAP_CONTENT
          topMargin = dpToPx(8, view)

      }
     linear1.addView(desc)
    cardView.addView(linear1)

    return cardView
}

When I am using these codes my app is crashing. I tried to debug my codes and came to know that the first error is in the layoutParams of CardView. In short, I want to know how can I set attributes in the Card View Also, Please Tell is this the only way to create dynamic layout or there is a more efficient way. I am new in Android Developing.

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Pratham Vaidya
  • 85
  • 4
  • 13

2 Answers2

1

I would like to suggest one thing, if your requirement is to create view dynamically then you just try one thing that is :

1) Make a separate layout file for your dymanic view 2) Inflate that layout using :

val layoutInflater = getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
    layoutInflater!!.inflate(R.layout.your_layout_file)

3) Now you will have view, then you just have to access the layour views using something like :

view.findViewById(you view id)

4) now you will be able to create and access your view dynamically easily

Note:

getContent() : will come according to your usage on fragment or in activity, so need to change it accordingly
same as inflate method, use parameter according to your requirement
Mitesh Machhoya
  • 404
  • 2
  • 8
  • You are right! I think this is the better way of adding dynamically created layouts. I was not knowing this concept before .Thanks for answering. Also, can you tell me which of my mistake lead to downvotes on this question – Pratham Vaidya Jun 14 '19 at 12:23
  • @PrathamVaidya it may be possible your question title is not related to your problem that you are looking for an answer, you have only written setAttribute in CardView but your problem is not related to this, so it may be possible for that reason. – Mitesh Machhoya Jun 14 '19 at 12:35
  • Ok, I'll try to improve in upcoming questions – Pratham Vaidya Jun 14 '19 at 12:37
1

You are casting the LayoutParams as CoordinatorLayout.LayoutParams whereas you are creating a view dynamically that doesn't have a parent view, and that's I think is the issue.

If you are creating the view dynamically than you should create new LayoutParams as well, according to its parent container.

For e.g., if you want to add CardView in a LinearLayout than, the LayoutParams should be as below:

val cardView = CardView(view.context)
val cardViewParams = LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT).also {
  it.setMargins(dpToPx(5, view), dpToPx(5, view), dpToPx(5, view), dpToPx(5, view))
}

cardView.apply {
        radius = dpToPx(10, view).toFloat()
            this.layoutParams = cardViewParam

        }
...
...

val linear1 = LinearLayout(view.context)
val linear1Param = FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT)
...
...
cardView.addView(linear1)

For linear1, we have taken FrameLayout.LayoutParams as in our case we are going to add it as a child of CardView, which is an extended FrameLayout.

Prashant Patel
  • 1,087
  • 11
  • 18
  • Yes you pointed the right mistake. I tried your codes and it worked but for some reason the margins which are negative were not applied on the View that's why my dynamic layout was not looking like the xml created layout and even that was lengthy process so I used Inflators instead. Thanks for answering even your answer is correct – Pratham Vaidya Jun 14 '19 at 12:30