Search code examples
androidflexboxandroid-flexboxlayout

Use FlexboxLayout programmatically


I'm facing some problems trying to create a simple interface using FlexboxLayout. I create the view in .xml file and all works as expected, but when I try to create the same view programmatically, I'm not be able to set the layout_flexBasisPercent. I'm trying to achive something like this: enter image description here

Here it is the xml code:

<com.google.android.flexbox.FlexboxLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:flexDirection="row"
    tools:context=".MainActivity">

    <com.google.android.flexbox.FlexboxLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:flexDirection="row"
        app:layout_flexBasisPercent="30%"
        app:layout_order="2">

        <TextView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:text="@string/lorem"/>

    </com.google.android.flexbox.FlexboxLayout>

    <com.google.android.flexbox.FlexboxLayout
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:flexDirection="row"
        app:layout_flexBasisPercent="70%"
        app:layout_order="1" >

        <ImageView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:scaleType="centerCrop"
            android:src="@drawable/random"/>

    </com.google.android.flexbox.FlexboxLayout>

And I'm trying to reproduce the same view programmatically with this code, but doesn't work:

    FlexboxLayout fb = findViewById(R.id.fb_main);
    fb.setLayoutDirection(FlexDirection.ROW);

    // Create right subregion on main layout
    FlexboxLayout right = new FlexboxLayout(this);
    FlexboxLayout.LayoutParams lpRight =
            new FlexboxLayout.LayoutParams(
                    FlexboxLayout.LayoutParams.MATCH_PARENT,
                    FlexboxLayout.LayoutParams.MATCH_PARENT);
    lpRight.setFlexBasisPercent(30f);
    lpRight.setOrder(2);
    lpRight.setLayoutDirection(FlexDirection.ROW);
    // Right subregions contains a Textview
    TextView tv = new TextView(this);
    tv.setLayoutParams(lpRight);
    tv.setText(getResources().getString(R.string.lorem));
    right.addView(tv);

    // Create left subregion on main layout
    FlexboxLayout left = new FlexboxLayout(this);
    FlexboxLayout.LayoutParams lpLeft =
            new FlexboxLayout.LayoutParams(
                    FlexboxLayout.LayoutParams.MATCH_PARENT,
                    FlexboxLayout.LayoutParams.MATCH_PARENT);
    lpLeft.setFlexBasisPercent(70f);
    lpLeft.setOrder(1);
    lpLeft.setLayoutDirection(FlexDirection.ROW);
    // Left subregion contains an Imageview
    ImageView iv = new ImageView(this);
    iv.setLayoutParams(lpLeft);
    iv.setImageResource(R.drawable.random);
    iv.setScaleType(ImageView.ScaleType.CENTER_CROP);
    left.addView(iv);

    fb.addView(left);
    fb.addView(right);

Can anyone find the error ? Or what I'm doing wrong?

Thank you.


Solution

  • Reading through your code is somewhat difficult; I recommend refactoring it into smaller methods to make reasoning about things easier. That being said, I see some problems:

    fb.setLayoutDirection(FlexDirection.ROW);
    

    This should be a call to fb.setFlexDirection() instead.

    FlexboxLayout.LayoutParams lpRight =
            new FlexboxLayout.LayoutParams(
                    FlexboxLayout.LayoutParams.MATCH_PARENT,
                    FlexboxLayout.LayoutParams.MATCH_PARENT);
    lpRight.setFlexBasisPercent(30f);
    lpRight.setOrder(2);
    lpRight.setLayoutDirection(FlexDirection.ROW);
    // Right subregions contains a Textview
    TextView tv = new TextView(this);
    tv.setLayoutParams(lpRight);
    

    Here you are creating a LayoutParams object with the flex basis and order values that you originally had on your "right" child FlexboxLayout, but you're then setting these LayoutParams to the TextView instead.

    Additionally, you are accidentally calling setLayoutDirection() instead of setFlexDirection() again.

    FlexboxLayout.LayoutParams lpLeft =
            new FlexboxLayout.LayoutParams(
                    FlexboxLayout.LayoutParams.MATCH_PARENT,
                    FlexboxLayout.LayoutParams.MATCH_PARENT);
    lpLeft.setFlexBasisPercent(70f);
    lpLeft.setOrder(1);
    lpLeft.setLayoutDirection(FlexDirection.ROW);
    // Left subregion contains an Imageview
    ImageView iv = new ImageView(this);
    iv.setLayoutParams(lpLeft);
    

    Same problem here.

    Here's a working activity that does what you posted in your image:

    public class MainActivity extends AppCompatActivity {
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
    
            FlexboxLayout root = createRootView();
            setContentView(root);
    
            FlexboxLayout right = createRightFlexbox();
            TextView rightText = createTextView();
            right.addView(rightText);
            root.addView(right);
    
            FlexboxLayout left = createLeftFlexbox();
            ImageView leftImage = createImageView();
            left.addView(leftImage);
            root.addView(left);
        }
    
        private FlexboxLayout createRootView() {
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);
    
            FlexboxLayout flexbox = new FlexboxLayout(this);
            flexbox.setLayoutParams(params);
            flexbox.setFlexDirection(FlexDirection.ROW);
    
            return flexbox;
        }
    
        private FlexboxLayout createRightFlexbox() {
            FlexboxLayout.LayoutParams params = new FlexboxLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
            params.setFlexBasisPercent(0.3f);
            params.setOrder(2);
    
            FlexboxLayout flexbox = new FlexboxLayout(this);
            flexbox.setLayoutParams(params);
            flexbox.setFlexDirection(FlexDirection.ROW);
    
            return flexbox;
        }
    
        private TextView createTextView() {
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);
    
            TextView textView = new TextView(this);
            textView.setLayoutParams(params);
            textView.setText(R.string.lorem);
    
            return textView;
        }
    
        private FlexboxLayout createLeftFlexbox() {
            FlexboxLayout.LayoutParams params = new FlexboxLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT);
            params.setFlexBasisPercent(0.7f);
            params.setOrder(1);
    
            FlexboxLayout flexbox = new FlexboxLayout(this);
            flexbox.setLayoutParams(params);
            flexbox.setFlexDirection(FlexDirection.ROW);
    
            return flexbox;
        }
    
        private ImageView createImageView() {
            ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT);
    
            ImageView imageView = new ImageView(this);
            imageView.setLayoutParams(params);
            imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
            imageView.setImageResource(R.drawable.random);
    
            return imageView;
        }
    }
    

    By splitting the code into methods, it becomes a lot easier to see which layout params you're applying to which views. Plus you get to see the overall structure of the screen at the top level.