Overview
While developing my Android app, iTransit, a time schedule application for bus and metro, it hits a wrapping issue. The application has to display a list of bus numbers for the users to choose. The problem is, there are more than 400 bus numbers in Montreal. Currently, TableLayout is being used but it has a limitation. You have to predefine the number of columns. When users change from portrait mode to landscape mode, there is a big empty blank space on the right side. That is bad! Obviously, you can solve this by calculating yourself how much columns you can put in the portrait mode and in landscape mode. Then, switch accordingly. This is getting complicated and I don't want to do all these hard work.
Why do the heavy lifting, when there is FlexboxLayout, an external library made by Google. It is designed specifically to handle wrapping. Now, let's use it.
Include FlexboxLayout library
In app/build.gradle
, add the following dependency:
dependencies { implementation 'com.google.android:flexbox:1.0.0' }
Define FlexboxLayout
In res/layout/activity_main.xml
, add the following:
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:scrollbars="vertical"> <com.google.android.flexbox.FlexboxLayout android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/flexbox_view" app:flexWrap="wrap" app:justifyContent="space_evenly" /> </ScrollView>
Note: It is important to add app:flexWrap="wrap"
attribute. Otherwise, wrapping is not going to be activated.
The code
There is no special coding to be done with FlexboxLayout. You treat it the same way as the other layouts. In your MainActivity class, simply add your views to the FlexboxLayout. That's it.
import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.TypedValue; import android.widget.Button; import com.google.android.flexbox.FlexboxLayout; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); FlexboxLayout flexboxLayout = this.findViewById(R.id.flexbox_view); // Add a lot of buttons. for(int i=0; i<70; i++) { Button button = new Button(this); int btnHeight = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 40, this.getResources().getDisplayMetrics()); int btnWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 70, this.getResources().getDisplayMetrics()); button.setWidth(btnWidth); button.setHeight(btnHeight); button.setText(String.valueOf(i)); flexboxLayout.addView(button); } } }
The end results
Github
- https://github.com/xuanngo2001/android-flexbox-wrap
Reference
- https://github.com/google/flexbox-layout