Crafting an Instagram-inspired UI with Jetpack Compose — Android Studio

Fahad Habib
7 min readApr 28, 2024

--

Create Instagram UI With Jetpack Compose

In this tutorial, we’ll guide you through the process of creating an Instagram-like user interface using Jetpack Compose. By leveraging the power of Jetpack Compose, we’ll build a visually appealing and interactive UI that mimics the layout and functionality of the popular social media platform.

Prerequisites Before we begin, ensure you have:

  • Basic knowledge of the Kotlin programming language.
  • Familiarity with Jetpack Compose fundamentals.
  • Android Studio Arctic Fox (2020.3.1) or higher installed.

Step 1: Main UI Class First, let’s set up the main UI class to display our Instagram UI.

class InstagramUiJpc : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
ProfileScreen()
}
}
}

Step 2: Data Class

We’ll define a data class for handling images with associated text.

data class ImageWithText(
val image: Painter,
val text : String
)

Step 3: Profile Screen Now, let’s create the profile screen, which includes the top bar, profile section, button section, highlight section, post tab view, and post section.

@Composable
fun ProfileScreen() {
// Content of the Profile Screen
}

Step 4: Profile Screen Components Let’s break down the profile screen components:

  1. Top Bar: Displays user information and navigation icons.
@Composable
fun TopBar(
name : String,
modifier: Modifier = Modifier
){
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceAround,
modifier = modifier
.fillMaxWidth()
) {
Icon(
imageVector = Icons.AutoMirrored.Filled.ArrowBack,
contentDescription = "Top Bar",
tint = Color.Black,
modifier = Modifier.size(24.dp))
Text(name,
overflow = TextOverflow.Ellipsis,
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
color = Color.Black)
Icon(
painter = painterResource(id = R.drawable.ic_bell),
contentDescription = "Top Bar",
tint = Color.Black,
modifier = Modifier.size(24.dp))
Icon(
painter = painterResource(id = R.drawable.ic_dotmenu),
contentDescription = "Top Bar",
tint = Color.Black,
modifier = Modifier.size(20.dp))

}
}
Top Bar In Jetpack Compose
Top Bar

2. Profile Section: Shows user profile image, stats, and description.

@Composable
fun ProfileSection(
modifier: Modifier = Modifier
){
Column(modifier = modifier.fillMaxWidth()) {
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 20.dp)
) {
RoundImage(image = painterResource(id = R.drawable.profileimg), modifier = Modifier
.size(100.dp)
.weight(3f)
)
Spacer(modifier = Modifier.width(16.dp))
StatSection(modifier = Modifier.weight(7f))
}
Spacer(modifier = Modifier.width(10.dp))
ProfileDescription(
displayName = "Coding Beast",
description = "10 years of coding experience \n" +
"Want me to make your app. Just email me \n" +
"Do subscribe to my youtube channel \n" +
"Link Below",
url = "https://www.youtube.com/codingbeast",
followedBy = listOf("Phillip","coding in flow"),
otherCount = 17
)

}
}

@Composable
fun RoundImage(
image: Painter,
modifier: Modifier = Modifier
){
Image(painter = image,
contentDescription = null,
modifier = modifier
.aspectRatio(1f, matchHeightConstraintsFirst = true)
.border(
1.dp, Color.LightGray, CircleShape
)
.padding(3.dp)
.clip(CircleShape)
)
}

@Composable
fun StatSection(modifier: Modifier = Modifier){
Row(
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceAround,
modifier = modifier
) {
ProfileStat(numberText = "601", text = "Posts")
ProfileStat(numberText = "99.8K", text = "Followers")
ProfileStat(numberText = "72", text = "Following")
}
}

@Composable
fun ProfileStat(
numberText: String,
text: String,
modifier: Modifier = Modifier
){
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
) {
Text(
text = numberText,
fontWeight = FontWeight.Bold,
fontSize = 20.sp,
)
Spacer(modifier = Modifier.height(4.dp))
Text(
text = text,
)
}
}

@Composable
fun ProfileDescription(
displayName: String,
description: String,
url: String,
followedBy: List<String>,
otherCount: Int
){
val letterSpacing = 0.5.sp
val lineHeight = 20.sp

Column(
modifier = Modifier
.fillMaxWidth()
.padding(20.dp)
) {
Text(
text = displayName,
fontWeight = FontWeight.Bold,
fontSize = 16.sp,
letterSpacing = letterSpacing,
lineHeight = lineHeight
)
Text(
text = description,
fontSize = 16.sp,
letterSpacing = letterSpacing,
lineHeight = lineHeight
)
Text(
text = url,
fontSize = 16.sp,
color = Color(0xFF4D61CF),
letterSpacing = letterSpacing,
lineHeight = lineHeight
)
if(followedBy.isNotEmpty()){
Text(
text = buildAnnotatedString {
val boldStyle = SpanStyle(
color = Color.Black,
fontWeight = FontWeight.Bold
)
append("Followed By ")
followedBy.forEachIndexed{index, name ->
pushStyle(boldStyle)
append(name)
pop()
if (index < followedBy.size -1){
append(", ")
}
}
if (otherCount>2){
append(" and ")
pushStyle(boldStyle)
append("$otherCount others")
}
},
letterSpacing = letterSpacing,
lineHeight = lineHeight

)
}
}
}
Instagram Profile Section With Jetpack Compose
Profile Section

3. Button Section: Buttons for actions like Following, Message, Email, etc.

@Composable
fun ButtonSection(modifier: Modifier = Modifier){
val minWith = 95.dp
val height = 30.dp
Row(
horizontalArrangement = Arrangement.SpaceEvenly,
modifier = modifier
) {
ActionButton(text = "Following", icon = Icons.Default.KeyboardArrowDown, modifier = Modifier
.defaultMinSize(minWidth = minWith)
.height(height))
ActionButton(text = "Message",modifier = Modifier
.defaultMinSize(minWidth = minWith)
.height(height))
ActionButton(text = "Email",modifier = Modifier
.defaultMinSize(minWidth = minWith)
.height(height))
ActionButton(icon = Icons.Default.KeyboardArrowDown,modifier = Modifier
.height(height))
}
}

@Composable
fun ActionButton(
modifier: Modifier = Modifier,
text: String? = null,
icon: ImageVector? = null
){
Row(
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically,
modifier = modifier
.border(
width = 1.dp,
color = Color.Black,
shape = RoundedCornerShape(5.dp)
)
.padding(6.dp)
) {
if (text != null) {
Text(
text = text,
fontWeight = FontWeight.SemiBold,
fontSize = 14.sp
)
}
if(icon != null){
Icon(
imageVector = icon,
contentDescription = "DropDown",
tint = Color.Black
)
}

}
}
Button Section

4. Highlight Section: Displays highlighted content with images and text.

@Composable
fun HighlightSection(
modifier: Modifier = Modifier,
highlights: List<ImageWithText>,
){
LazyRow(modifier = modifier){
items(highlights.size){
Column(
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.padding(end = 15.dp)
) {
RoundImage(
image = highlights[it].image, modifier = Modifier.size(70.dp))
Spacer(modifier = Modifier.height(4.dp))
Text(
text = highlights[it].text,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)
}
}
}
}
Highlights Section

5. Post Tab View: Tabs for switching between different types of posts.

@Composable
fun PostTabView(
modifier: Modifier = Modifier,
imageWithTexts: List<ImageWithText>,
onTabSelected: (selectedIndex: Int) -> Unit
) {
var selectedTabIndex by remember {
mutableIntStateOf(0)
}
val inactiveColor = Color(0xFF777777)
TabRow(
selectedTabIndex = selectedTabIndex,
contentColor = Color.Black,
modifier = modifier
) {
imageWithTexts.forEachIndexed { index, item ->
Tab(
selected = selectedTabIndex == index,
selectedContentColor = Color.Black,
unselectedContentColor = inactiveColor,
onClick = {
selectedTabIndex = index
onTabSelected(index)
}
) {
Icon(
painter = item.image,
contentDescription = item.text,
tint = if(selectedTabIndex == index) Color.Black else inactiveColor,
modifier = Modifier
.padding(10.dp)
.size(20.dp)
)
}
}
}
}
Tabs

6. Post Section: Displays posts based on the selected tab.

@Composable
fun PostSection(
post: List<Painter>,
modifier: Modifier = Modifier
){
LazyVerticalGrid(columns = GridCells.Fixed(3),
modifier = modifier.scale(1.01f)
){
items(post.size){
Image(
painter =post[it],
contentDescription ="posts",
contentScale = ContentScale.Crop,
modifier = Modifier
.aspectRatio(1f)
.border(
width = 1.dp,
color = Color.White,
)
)
}
}
}
post section using grid in jetpack compose
Post Section

The PostSection composable function utilizes LazyVerticalGrid to display posts in a grid layout. Each item in the grid is an Image composable representing a post.

In this final step, we bring together all the composables we’ve created so far to compose the complete Instagram-inspired UI using Jetpack Compose.

We start with the ProfileScreen() composable, which serves as the main entry point for our UI. Inside this composable, we organize various sections of the UI using Column and Spacer composables to add spacing between them.

  • Top Bar: We display the user’s name and navigation icons using the TopBar() composable.
  • Profile Section: This section showcases the user’s profile image, stats, and description. We use the ProfileSection() composable to achieve this.
  • Button Section: Here, we provide buttons for actions like Following, Message, and Email. The ButtonSection() composable handles the layout of these buttons.
  • Highlight Section: Displays highlighted content with images and text. We utilize the HighlightSection() composable to present this content.
  • Post Tab View: Tabs for switching between different types of posts. We use the PostTabView() composable to create this functionality.
  • Post Section: Displays posts based on the selected tab. We use the PostSection() composable to render the posts.

By combining these composables within the ProfileScreen() composable, we create a cohesive and visually appealing Instagram-like UI using Jetpack Compose.

@Composable
fun ProfileScreen(
){
var selectedTabIndex by remember {
mutableIntStateOf(0)
}
Column(modifier = Modifier.fillMaxSize()) {
Spacer(modifier = Modifier.height(10.dp))
TopBar("Fahad Habib")
Spacer(modifier = Modifier.height(10.dp))
ProfileSection()
Spacer(modifier = Modifier.height(25.dp))
ButtonSection(modifier = Modifier.fillMaxWidth())
Spacer(modifier = Modifier.height(25.dp))
HighlightSection(
highlights = listOf(
ImageWithText(
image = painterResource(id = R.drawable.youtube),
text = "Youtube"
),
ImageWithText(
image = painterResource(id = R.drawable.qa),
text = "Q&A"
),
ImageWithText(
image = painterResource(id = R.drawable.discord),
text = "Discord"
),
ImageWithText(
image = painterResource(id = R.drawable.telegram),
text = "Telegram"
),
ImageWithText(
image = painterResource(id = R.drawable.youtube),
text = "Youtube"
),
ImageWithText(
image = painterResource(id = R.drawable.qa),
text = "Q&A"
),
ImageWithText(
image = painterResource(id = R.drawable.discord),
text = "Discord"
),
ImageWithText(
image = painterResource(id = R.drawable.telegram),
text = "Telegram"
),
),
modifier = Modifier
.fillMaxWidth()
.padding(start = 5.dp)
)
Spacer(modifier = Modifier.height(10.dp))
PostTabView(
imageWithTexts = listOf(
ImageWithText(
image = painterResource(id = R.drawable.ic_grid),
text = "Posts"
),
ImageWithText(
image = painterResource(id = R.drawable.ic_reels),
text = "Reels"
),
ImageWithText(
image = painterResource(id = R.drawable.ic_igtv),
text = "IGTV"
),
ImageWithText(
image = painterResource(id = R.drawable.profile),
text = "Profile"
),
)
) {
selectedTabIndex = it
}
when(selectedTabIndex){
0 -> PostSection(
post = listOf(
painterResource(id = R.drawable.kmm),
painterResource(id = R.drawable.intermediate_dev),
painterResource(id = R.drawable.master_logical_thinking),
painterResource(id = R.drawable.bad_habits),
painterResource(id = R.drawable.multiple_languages),
painterResource(id = R.drawable.learn_coding_fast)
),
modifier = Modifier.fillMaxWidth()
)
}
}
}

Conclusion

In this tutorial, we learned how to create an Instagram-inspired UI using Jetpack Compose. By breaking down the profile screen into smaller components and utilizing Jetpack Compose’s declarative UI approach, we were able to build a visually appealing and interactive user interface.

By mastering these concepts, you’ll be well-equipped to design and develop complex user interfaces with Jetpack Compose for your Android applications.

Happy coding!

--

--