Joker
Joker

Reputation: 545

How to make Vertical TabLayout in Android

Hi i am trying to make vertical tab layout.tried using rotate view but it does not help its not recalculate views height and view.any help will be appreciated to achieve below result.

enter image description here

Upvotes: 0

Views: 5434

Answers (3)

Mohd Danish
Mohd Danish

Reputation: 204

Here is the Code For VerticalTabLayout! I am using Jetpack Compose. For the vertical Tab, I am using Modifier.onGloballyPositioned to calculate the Item Height and indicator Height. And I am Using a Vertical-Scroll Column For Item List.

enter image description here

@Composable
fun MDVerticalTabLayout(
    modifier: Modifier = Modifier,
    bottomPaddingDp: Dp = 0.dp,
    list: SnapshotStateList<CategoryItem>,
    gradientFirstColor: Color,
    gradientSecondColor: Color,
    indicatorColor: Color,
    indicatorHeightType: IndicatorHeightType = IndicatorHeightType.FIXED,
    indicatorHeight: Dp = 58.dp,
    textStyle: TextStyle = TextStyle.Default,
    onItemClick: (CategoryItem) -> Unit,
) {
    val context = LocalContext.current
    val globalOffsetYPosition = rememberSaveable {
        mutableIntStateOf(0)
    }
    val globalHeight = rememberSaveable {
        mutableIntStateOf(0)
    }

    val selectedPosition = rememberSaveable {
        mutableIntStateOf(0)
    }

    val movementThreshHold = remember {
        100
    }

    val offsetYPosition = rememberSaveable {
        mutableIntStateOf(0)
    }

    val heightOfItem = rememberSaveable {
        mutableIntStateOf(0)
    }
    val listState = rememberScrollState()
    val coroutineScope = rememberCoroutineScope()
    val map = remember {
        hashMapOf<Int, Int>()
    }

    val durationMillis = rememberSaveable {
        mutableStateOf(0)
    }

    // Define the animation spec
    val animationSpec by remember {
        derivedStateOf {
            tween<Offset>(
                durationMillis = durationMillis.value,
                easing = FastOutSlowInEasing,
            )
        }
    }

    val animationSpecForScroll by remember {
        derivedStateOf {
            tween<Float>(
                durationMillis = 600,
                easing = FastOutSlowInEasing,
            )
        }
    }

    // Create an animated offset
    val animatedOffset by animateOffsetAsState(
        targetValue = Offset(x = 0F, y = offsetYPosition.value.toFloat()),
        animationSpec = animationSpec,
        label = "",
    )

    val indicatorHeight by remember {
        derivedStateOf {
            when (indicatorHeightType) {
                IndicatorHeightType.FIXED -> {
                    indicatorHeight
                }
                IndicatorHeightType.FILL -> {
                    getDp(context, heightOfItem.intValue)
                }
            }
        }
    }

    Scaffold(
        modifier = modifier
            .background(Color.White)
            .fillMaxHeight()
            .width(78.dp)
            .onGloballyPositioned {
                globalOffsetYPosition.value = it.positionInRoot().y.toInt()
                globalHeight.value = it.size.height
            },
        content = { paddingValues ->
            Surface(modifier = Modifier.fillMaxHeight().padding(paddingValues), elevation = 10.dp) {
                Box(
                    contentAlignment = Alignment.TopEnd,
                ) {
                    Column(
                        modifier = Modifier
                            .verticalScroll(listState)
                            .width(78.dp),
                    ) {
                        list.forEachIndexed { position, item ->
                            map[position] = 0
                            var height: Int = 0

                            ItemSubCategory(
                                item = item,
                                onChecked = selectedPosition.value == position,
                                gradientFirstColor = gradientFirstColor,
                                gradientSecondColor = gradientSecondColor,
                                textStyle = textStyle,
                                modifier = Modifier
                                    .onGloballyPositioned {
                                        map[position] = it.positionInRoot().y.toInt()
                                        height = it.size.height
                                        if (selectedPosition.value == position) {
                                            height = it.size.height
                                            offsetYPosition.value =
                                                it.positionInRoot().y.toInt() - globalOffsetYPosition.value
                                            heightOfItem.value = height
                                        }
                                    }
                                    .fillMaxWidth(),
                            ) {
                                durationMillis.value = 600
                                offsetYPosition.intValue = map[position] ?: (0 - globalOffsetYPosition.intValue)
                                selectedPosition.intValue = position
                                heightOfItem.intValue = height
                                coroutineScope.launch {
                                    if (offsetYPosition.intValue <= height + movementThreshHold) {
                                        listState.animateScrollTo(animationSpec = animationSpecForScroll, value = listState.value - height / 2 - movementThreshHold)
                                    } else if (offsetYPosition.intValue >= globalHeight.intValue - height / 2 - movementThreshHold) {
                                        listState.animateScrollTo(animationSpec = animationSpecForScroll, value = (listState.value + height / 2 + movementThreshHold))
                                    }
                                    delay(600)
                                    durationMillis.value = 0
                                }
                                onItemClick(item)
                            }
                            if (position == list.size - 1) {
                                Spacer(
                                    modifier = Modifier
                                        .padding(bottom = bottomPaddingDp)
                                        .fillMaxWidth()
                                        .background(Color.White),
                                )
                            } else {
                                Spacer(
                                    modifier = Modifier
                                        .fillMaxWidth()
                                        .background(Color.White),
                                )
                            }
                        }
                    }

                    Box(
                        modifier = Modifier
                            .offset(
                                x = getDp(context, animatedOffset.x.toInt()),
                                y = getDp(context, animatedOffset.y.toInt()),
                            )
                            .padding(top = 24.dp)
                            .width(3.dp)
                            .height(indicatorHeight)
                            .background(
                                color = indicatorColor,
                                shape = RoundedCornerShape(2.dp),
                            ),

                    )
                }
            }
        },
    )
}


fun getDp(context: Context, offset: Int): Dp {
    val resources = context.resources
    val metrics = resources.displayMetrics
    val dpValue = offset / (metrics.densityDpi.toFloat() / DisplayMetrics.DENSITY_DEFAULT)
    return dpValue.dp
}

enum class IndicatorHeightType {
    FILL,
    FIXED,
}

Upvotes: 0

hemdroid
hemdroid

Reputation: 141

I made vertical tabLayout using following code. You can also try it:-

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:rotation="-90"
    android:transformPivotX="0dp"
    android:layout_marginTop="@dimen/tab_width"
    android:layout_marginLeft="-24dp">
    <com.google.android.material.tabs.TabLayout
        android:layout_width="@dimen/tab_width"
        android:layout_height="wrap_content"
        android:background="@color/black"
        app:tabTextColor="@color/light_grey"
        app:tabSelectedTextColor="@color/white"
        app:tabIndicatorHeight="2dp"
        app:tabIndicatorColor="@color/white"
        app:tabPaddingBottom="-10dp">
        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="ABC"/>
        <com.google.android.material.tabs.TabItem
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="XYZ"/>
    </com.google.android.material.tabs.TabLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

Upvotes: 1

Pradeep
Pradeep

Reputation: 31

This might help you.

<FrameLayout
    android:layout_width="300dp"
    android:layout_height="300dp"
    android:rotation="-90"
    android:layout_gravity="center_vertical">

    <com.google.android.material.tabs.TabLayout
        android:id="@+id/tabLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        app:tabIndicatorHeight="4dp"
        app:tabTextAppearance="@style/CDTabLayoutTextAppearance"
        app:tabInlineLabel="true"
        app:tabIconTint="@color/tab_tint_color_selector"
        app:tabIndicatorFullWidth="false"
        app:tabIndicator="@drawable/ic_community_tab_selected"
        app:tabIndicatorColor="@color/colorColoringDesk"
        android:background="@color/white" >

        <com.google.android.material.tabs.TabItem
            android:id="@+id/tabItemContacts"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Contacts" />

        <com.google.android.material.tabs.TabItem
            android:id="@+id/tabItemChat"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Chat" />

    </com.google.android.material.tabs.TabLayout>
</FrameLayout>

Use TabLayout with ViewPager2.

Rotate your FrameLayout

Upvotes: 2

Related Questions