[Part 4] Jetpack Compose — Implementing a Compose View in a ViewGroup

Veronica Putri Anggraini
4 min readFeb 21, 2023

--

Hi Folks, this is the last part of the existing view to compose migration series. Reading the previous series is highly recommended, if you haven’t read the previous series visit the following link:

Part 1: Jetpack Compose — Introduction
Part 2:
Jetpack Compose — Preparing to Migrate Existing Layout to Compose
Part 3 :
Jetpack Compose — Migration of Component View (Input Text) on Existing Layout
Part 4: Jetpack Compose — Implementing a Compose View in a ViewGroup

Previously, don’t forget to clone the starter code, which can be downloaded at the following link, and select branch before-migrate as starter code. In the previous article, already explained how to make custom widgets using compose.

In this article, we only need to add a custom widget component to the compose view. There are 2 custom widget components that have been made, namely input text and image buttons, so we need to replace the input text and button views in the xml view with the custom widgets that have been made.

For more details, consider the following steps:

  1. Open activity_main.xml then delete the following text input field view component.
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/el_username"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginStart="30dp"
android:layout_marginTop="30dp"
android:layout_marginEnd="30dp"
android:background="@color/backgroundColor"
app:boxCornerRadiusBottomEnd="15dp"
app:boxCornerRadiusBottomStart="15dp"
app:boxCornerRadiusTopEnd="15dp"
app:boxCornerRadiusTopStart="15dp"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_subtitle">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_username"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="@color/white"
android:hint="@string/enter_username" />
</com.google.android.material.textfield.TextInputLayout>

<com.google.android.material.textfield.TextInputLayout
android:id="@+id/el_password"
android:layout_width="0dp"
android:layout_height="60dp"
android:layout_marginTop="15dp"
android:background="@color/backgroundColor"
app:boxCornerRadiusBottomEnd="15dp"
app:boxCornerRadiusBottomStart="15dp"
app:boxCornerRadiusTopEnd="15dp"
app:boxCornerRadiusTopStart="15dp"
app:boxStrokeWidth="0dp"
app:boxStrokeWidthFocused="0dp"
app:layout_constraintEnd_toEndOf="@+id/el_username"
app:layout_constraintStart_toStartOf="@+id/el_username"
app:layout_constraintTop_toBottomOf="@+id/el_username"
app:passwordToggleEnabled="true"
app:passwordToggleTint="@color/backgroundColor">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/et_password"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:backgroundTint="@color/white"
android:hint="@string/password"
android:inputType="textPassword" />

</com.google.android.material.textfield.TextInputLayout>

Then add the compose view component with the following code instead of the input text view component.

<androidx.compose.ui.platform.ComposeView
android:id="@+id/input_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
app:layout_constraintBottom_toTopOf="@id/tv_recovery"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tv_subtitle" />

2. Apart from the text input components, remove the code for the following Image Button components.

<FrameLayout
android:id="@+id/fl_google"
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginStart="20dp"
android:layout_marginTop="20dp"
android:background="@drawable/image_background"
app:layout_constraintStart_toStartOf="@+id/btn_signin"
app:layout_constraintTop_toBottomOf="@+id/tv_continue">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:src="@drawable/google" />
</FrameLayout>

<FrameLayout
android:id="@+id/fl_facebook"
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="20dp"
android:background="@drawable/image_background"
app:layout_constraintEnd_toEndOf="@+id/btn_signin"
app:layout_constraintTop_toBottomOf="@+id/tv_continue">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:scaleType="centerCrop"
android:src="@drawable/fb" />
</FrameLayout>

<FrameLayout
android:id="@+id/fl_apple"
android:layout_width="70dp"
android:layout_height="50dp"
android:layout_marginTop="20dp"
android:background="@drawable/image_background"
app:layout_constraintEnd_toStartOf="@+id/fl_facebook"
app:layout_constraintStart_toEndOf="@+id/fl_google"
app:layout_constraintTop_toBottomOf="@+id/tv_continue">

<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="15dp"
android:scaleType="centerCrop"
android:src="@drawable/apple" />
</FrameLayout>

Then add the compose view component with the following code instead of the image button view component.

<androidx.compose.ui.platform.ComposeView
android:id="@+id/button_image"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="@id/btn_signin"
app:layout_constraintStart_toStartOf="@id/btn_signin"
app:layout_constraintTop_toBottomOf="@id/tv_continue" />

So the complete code will be as follows.

3. Add viewBinding support to initialize the compose view I, that embedded in the xml file of the activity class. Open the .gradle file then add the following code then sync.

buildFeatures {
viewBinding true
}

4. Initialize the activity_main.xml layout in the activity class as shown below.

  • Create the mainBinding variable
private lateinit var mainBinding: ActivityMainBinding
  • Add a value to the Binding engine in the onCreate function
mainBinding = ActivityMainBinding.inflate(layoutInflater)
  • Then add a value to setContentView as below
setContentView(mainBinding.root)

5. For the next step, call compose view with the inputText id that was previously embedded in the xml file. Then add setContent to add the compose component to the compose view like the code below.

mainBinding.inputText.setContent {}

Because InputText is arranged vertically, use columns to arrange the layout in compose view. Then call the InputTextField widget and add parameters according to the input type with some important parameters as follows.

  • hint, to add hint text.
  • type, to add the type of input text.
  • color, to set the color of the container in the input text.
mainBinding.inputText.setContent {
Column(modifier = Modifier) {
InputTextField(
modifier = Modifier,
hint = "Username",
type = KeyboardType.Text,
capitalization = KeyboardCapitalization.None,
color = White
)
InputTextField(
modifier = Modifier,
hint = "Enter Password",
type = KeyboardType.Password,
capitalization = KeyboardCapitalization.None,
color = White
)

}
}

7. Do the same for the compose view component with id buttonImage, call id and add setContent. Since Image buttons are arranged horizontally use the Row component to arrange the layout in compose view. Call the ImageSignIn widget and add a value to the image parameter. Besides that, to make each button have a balanced spacing, add the attribute arrangement horizontally with the ScapeEvenly value.

mainBinding.buttonImage.setContent {
Row(horizontalArrangement = Arrangement.SpaceEvenly) {
ImageSignIn(modifier = Modifier, image = R.drawable.google)
ImageSignIn(modifier = Modifier, image = R.drawable.apple)
ImageSignIn(modifier = Modifier, image = R.drawable.fb)

}
}

So the whole code will be like below.

Then if the compiled UI has been migrated it will give the same appearance as before it was migrated but the input text and image button components are built using compose. Easy isn’t it :) Full code on Github.

--

--