I have two different xml files in an Android project that are very similar -- they both specify an ImageView and a TextView -- the only difference is that they have a different text and image source specified in each one.
frog.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/frog">
</ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Frog"
/>
</LinearLayout>
penguin.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/penguin">
</ImageView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Penguin"
/>
</LinearLayout>
How can I refactor these two files into a single reusable component, such that I can use them like this?
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<CustomLayout imageSrc="@drawable/penguin" text="Penguin">
<CustomLayout imageSrc="@drawable/frog" text="Frog">
</LinearLayout>
I hate having to copy and paste code everywhere in my app so refactoring here would be great. I've tried using ChatGPT, looking at conversations here on StackOverflow, and looking on the official documentation for Android, but haven't been able to find a simple answer that works. Can anyone help?
Thank you in advance!
custom_animal_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</ImageView>
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
</TextView>
</LinearLayout>
CustomAnimalView.kt
class CustomAnimalView(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var imageView: ImageView
private var textView: TextView
init {
LayoutInflater.from(context).inflate(R.layout.custom_animal_view, this, true)
imageView = findViewById(R.id.imageView)
textView = findViewById(R.id.textView)
}
fun setValues(drawableRes: Int, text: String) {
imageView.setImageResource(drawableRes)
textView.setText(text)
}
}
Usage
<com.yourpackage.name.CustomAnimalView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/customAnimalLayout"/>
You can also use it this way in Activity
and Fragment
.
customAnimalLayout.setValues(R.drawable.frog, "Frog")
customAnimalLayout.setValues(R.drawable.penguin, "Penguin")
Sample Your UseCase
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
>
<com.yourpackage.name.CustomAnimalView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/penguinView"/>
<com.yourpackage.name.CustomAnimalView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/frogView"/>
</LinearLayout>
If you want to do it using attr
.
attr.xml
<resources>
<declare-styleable name="CustomView">
<attr name="imageSrc" format="reference"/>
<attr name="text" format="string"/>
</declare-styleable>
</resources>
CustomAnimalV2View.kt
class CustomAnimalV2View(context: Context, attrs: AttributeSet) : LinearLayout(context, attrs) {
private var imageView: ImageView
private var textView: TextView
init {
LayoutInflater.from(context).inflate(R.layout.custom_animal_view., this, true)
imageView = findViewById(R.id.imageView)
textView = findViewById(R.id.textView)
val attributes = context.obtainStyledAttributes(attrs, R.styleable.CustomView)
imageView.setImageResource(attributes.getResourceId(R.styleable.CustomView_imageSrc, 0))
textView.text = attributes.getString(R.styleable.CustomView_text)
attributes.recycle()
}
}
Usage
<com.yourpackage.name.CustomAnimalV2View
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:imageSrc="@drawable/penguin"
app:text="Penguin" />