2

I am trying to replace my existing GridLayout with flexbox layout. I have a layout that requires me to have exactly 4 columns and two rows.

Only way I have found this to work is by code

        val rootFlexboxLayout = binding.moreActionLayout
        rootFlexboxLayout.flexDirection = FlexDirection.ROW
        rootFlexboxLayout.justifyContent = JustifyContent.FLEX_START
        rootFlexboxLayout.alignContent = AlignContent.FLEX_START
        rootFlexboxLayout.alignItems = AlignItems.STRETCH
        rootFlexboxLayout.flexWrap = FlexWrap.WRAP

        val flexboxLayoutParams: FlexboxLayout.LayoutParams = FlexboxLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)
        flexboxLayoutParams.flexBasisPercent = 0.23f
        // Manually create views to be added to flexbox layout
        tabs.forEachIndexed { index, tabViewState ->
            // Add the tab to the layout
            val tabView = BottomBarTabView(requireContext())
            tabView.apply {
                id = View.generateViewId()
                layoutParams = flexboxLayoutParams
            }
            binding.moreActionLayout.addView(tabView, index)
       }

Thing that is bothering me is magic number of 0.23f is the only thing that gets me 4 columns, if I set to 0.25 (25%) it gives me 3 columns.

My layout definition for moreActionLayout looks like this:

    <com.google.android.flexbox.FlexboxLayout
        android:id="@+id/moreActionLayout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:alignContent="flex_start"
        app:alignItems="center"
        app:flexWrap="wrap"
        app:flexDirection="row"
        android:padding="8dp">
    </com.google.android.flexbox.FlexboxLayout>
4
  • by fixed number of columns, you mean that it always displays X amount of columns or is it a maximum amount of columns? Commented Aug 14, 2022 at 19:30
  • 1
    I want always display X amount of columns. That is why I tried to flexBasisPercent to 0.25, thinking that would give me 4 columns. But it gives me 3 columns. But if I change it to 0.23 it gives me 4 columns!! Commented Aug 14, 2022 at 19:52
  • How about calculating max Width of each children in flex layout with given x columns so that we wrap the children in flexlayout? If it helps I can post the calculation ! Commented Aug 15, 2022 at 9:39
  • Vivek, that will be super useful! Commented Aug 15, 2022 at 13:58

3 Answers 3

2
+300

As I am new to android, I had to study Flex layout but seeing attributes of flex layout with identical names I got confused. This is what I did.

Flex Direction = change axis direction (row or column)

flex wrap = single or multliline flex container (no_wrap or wrap)

justifyContent = alignment along x axis (left, right, center, space around/between/evenly)

alignItems = alignment along y axis(top, bottom, center, stretch upto whole height)

alignContent = combination of justify + align (left + top, right+bottom, center + center,space around + stretch ,space between + stretch, )

I might be wrong in interpreting these attributes. I found two attributes applicable to your query i.e

layout_minWidth & layout_maxWidhth

From documentation , layout_minWidth

These attributes impose minimum size constraints for the children of FlexboxLayout. A child view won't shrink less than the value of these attributes (varies based on the flexDirection attribute as to which attribute imposes the size constraint along the main axis) regardless of the layout_flexShrink attribute

layout_maxWidth

These attributes impose maximum size constraints for the children of FlexboxLayout. A child view won't be expanded more than the value of these attributes (varies based on the flexDirection attribute as to which attribute imposes the size constraint along the main axis) regardless of the layout_flexGrow attribute.

So,I guess, just applying flexiWrap attribute to wrap in flexlayout and for children's applying maxWidth or minWidth to a value , you can achieve solution to your query. To get the value of maxWidth in particular orientation, calculation is

 private fun FlexboxLayout.getMaximumWidthForChild(columns: Int): Int {
    val displayMetrics = this.resources.displayMetrics
    val widthInPixels = displayMetrics.widthPixels - marginStart - marginEnd
    val maxWidthForChildInPixels = widthInPixels / columns
    val childWidthInDp =  (maxWidthForChildInPixels * DisplayMetrics.DENSITY_DEFAULT)/displayMetrics.densityDpi
    Log.d("myTag","Width in Pixels = $widthInPixels Max child Pixels = $maxWidthForChildInPixels ")
    Log.d("myTag","Child Width in Dp = $childWidthInDp")
    //        px = dp * (dpi / 160)
    return childWidthInDp
    }

This method returns maxWidth a child can have for given x columns. As you are adding views programmatically, you can set the layout parameters on the child view to have this maxWidth or just set the width. For different orientation, you ought to call this method in onResume() and load the views again which is kind of bad but it depends upon the no. of views to be load.

Sign up to request clarification or add additional context in comments.

1 Comment

Forgot to mention flexDirection to Row.
0

Thanks Vivek for your suggestion above. That didn't really work. But since I am using flex_start I was able to obtain desired results using the following.

private fun flexPercent(): Float {
    val padding: Float = binding.moreActionLayout.paddingStart.toFloat() / resources.displayMetrics.widthPixels.toFloat()
    return FLEXBOX_PERCENT - padding
}

And then I used this method to set flexBasisPercent value, with FLEXBOX_PERCENT set to 0.25

flexboxLayoutParams.flexBasisPercent = flexPercent()

Comments

0

There's actually a much... MUCH simpler way to do this. (And you don't need to do it in the code...)

All you have to do is set your Flexbox parameters as you normally would in the xml:

<com.google.android.flexbox.FlexboxLayout
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/moreActionLayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:scaleType="centerCrop"
        app:flexWrap="wrap"
        app:alignItems="baseline"
        app:alignContent="flex_start" >

Then set the flexbasis for each element. (Whether it's a button or text or whatever...) In your case you would set that to 25% for each element.

    <Button
        android:id="@+id/btn_photos"
        android:layout_width="200dp"
        android:layout_height="200dp"
        app:layout_flexBasisPercent="25%"
        android:background="@color/white"
        android:textColor="@android:color/black"
        android:text="PHOTOS"
        android:textSize="30sp"
        app:layout_alignSelf="flex_start"
        />

I don't think it even matters what you set the layout_width and layout_height to at that point. It will automatically use 25% and VOILA... you've got your four columns and two rows.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.