Android轻松搞定流动布局(FlexboxLayout)

以前我们要实现流动性布局,比较繁琐,Google开源了一个项目叫FlexboxLayout,相信大家都不陌生。下面我们来学习一下FlexboxLayout基础知识,并通过一个案例来加深理解。如果你对FlexboxLayout很熟悉,请忽略本文。

1. 什么是 Flexbox

简单来说 Flexbox 是属于web前端领域CSS的一种布局方案,是2009年W3C提出了一种新的布局方案,可以响应式地实现各种页面布局,并且 React Native 也是使用的 Flex 布局。

我们可以简单的理解为 Flexbox 是CSS领域类似 Linearlayout 的一种布局,但比 Linearlayout 要强大的多。

2. 什么是 FlexboxLayout?

我们在 Android 开发中使用 Linearlayout + RelativeLayout 基本可以实现大部分复杂的布局,但是Google就想了,有没有类似 Flexbox 的一个布局呢?这使用起来一个布局就可以搞定各种复杂的情况了,于是 FlexboxLayout 就应运而生了。

所以 FlexboxLayout 是针对 Android 平台的,实现类似 Flexbox 布局方案的一个开源项目,开源地址:https://github.com/google/flexbox-layout

3. 使用方式

使用方式很简单,只需要添加以下依赖:

compile 'com.google.android:flexbox:0.2.2'

在xml布局中我们可以这样使用

 <com.google.android.flexbox.FlexboxLayout
        android:id="@+id/flexbox_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:flexWrap="wrap">
      <TextView
        android:id="@+id/tv1"
        android:layout_width="120dp"
        android:layout_height="80dp"
        app:layout_flexBasisPercent="50%" />
       <TextView
        android:id="@+id/tv2"
        android:layout_width="80dp"
        android:layout_height="80dp"
        app:layout_alignSelf="center"/>
       <TextView
        android:id="@+id/tv3"
        android:layout_width="160dp"
        android:layout_height="80dp"
        app:layout_alignSelf="flex_end"/>
    </com.google.android.flexbox.FlexboxLayout>

代码中可以这样使用

FlexboxLayout flexboxLayout = (FlexboxLayout) findViewById(R.id.flexbox_layout);
flexboxLayout.setFlexDirection(FlexboxLayout.FLEX_DIRECTION_COLUMN);
View view = flexboxLayout.getChildAt(0);
FlexboxLayout.LayoutParams lp = (FlexboxLayout.LayoutParams) view.getLayoutParams();
lp.order = -1;
lp.flexGrow = 2;
view.setLayoutParams(lp);

我们来看简书平台热门专题的布局


下面我们来实现它,先来看最终实现的效果:

1. 新建activity_flow.xml布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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">
    <com.google.android.flexbox.FlexboxLayout
        android:id="@+id/flexbox_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        app:flexWrap="wrap" />
</RelativeLayout>

布局很简单,只有一个FlexboxLayout 因为我们需要动态创建它的item,所以就在这里固定写TextView了

2. 新建ActivityFlow Activity,填充数据源
String[] tags = {"婚姻育儿", "散文", "设计", "上班这点事儿", "影视天堂", "大学生活", "美人说", "运动和健身", "工具癖", "生活家", "程序员", "想法", "短篇小说", "美食", "教育", "心理", "奇思妙想", "美食", "摄影"};
        flexboxLayout = (FlexboxLayout) findViewById(R.id.flexbox_layout);
        for (int i = 0; i < tags.length; i++) {
            Book model = new Book();
            model.setId(i);
            model.setName(tags[i]);
            flexboxLayout.addView(createNewFlexItemTextView(model));
        }

其中Book为一个实体,这个不是关键,关键的是createNewFlexItemTextView方法

我们要动态加载FlexboxLayout其FlexItem 并且让FlexboxLayout中的item支持点击事件,因为我们需要知道用户点击了哪个专题跳转。

我们来看一下createNewFlexItemTextView方法

/**
     * 动态创建TextView
     * @param book
     * @return
     */
    private TextView createNewFlexItemTextView(final Book book) {
        TextView textView = new TextView(this);
        textView.setGravity(Gravity.CENTER);
        textView.setText(book.getName());
        textView.setTextSize(12);
        textView.setTextColor(getResources().getColor(R.color.colorAccent));
        textView.setBackgroundResource(R.drawable.tag_states);
        textView.setTag(book.getId());
        textView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.e(TAG, book.getName());
            }
        });
        int padding = Util.dpToPixel(this, 4);
        int paddingLeftAndRight = Util.dpToPixel(this, 8);
        ViewCompat.setPaddingRelative(textView, paddingLeftAndRight, padding, paddingLeftAndRight, padding);
        FlexboxLayout.LayoutParams layoutParams = new FlexboxLayout.LayoutParams(
                ViewGroup.LayoutParams.WRAP_CONTENT,
                ViewGroup.LayoutParams.WRAP_CONTENT);
        int margin = Util.dpToPixel(this, 6);
        int marginTop = Util.dpToPixel(this, 16);
        layoutParams.setMargins(margin, marginTop, margin, 0);
        textView.setLayoutParams(layoutParams);
        return textView;
    }

其他有关Book实体和Util类,也贴出来一下
Book实体

public class Book {
    private int id;
    private String name;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getId() {
        return id;
    }
    public void setId(int id) {
        this.id = id;
    }
    public Book() {
    }
}

Util工具类

public class Util {
    public static int pixelToDp(Context context, int pixel) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return pixel < 0 ? pixel : Math.round(pixel / displayMetrics.density);
    }
    public static int dpToPixel(Context context, int dp) {
        DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
        return dp < 0 ? dp : Math.round(dp * displayMetrics.density);
    }
}

这样关于流动布局[FlexboxLayout],我们就实现完成了,是不是很简单。

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 155,841评论 24 680
  • 最近的琐事特别多,又因为等工具到位,以至于第三次作业现在才交。 自己感觉在画横向线条时候手抖经常画不直,然后房子结...
    viviblue微蓝阅读 134评论 1 1
  • 【姓名】邵振 【派别】文魁派 【导师】袁文魁 【分舵】文魁派第一分舵 【舵主】刘丽琼 【导图解说】我的中心图是一个...
    邵振阅读 132评论 9 2
  • 公主大婚前三日離宮出走,雖然駙馬有才有貌還有一副絕世好嗓,但公主人生第一次的愛情剛剛萌芽,怎甘心就這樣輕易被一紙婚...
    桃之煉金術師阅读 93评论 1 2
  • 斯凯想结婚了,她开始不断的关注婚纱、钻戒的广告。但是她不愿意告诉海伦。 一方面她不想给他过多压力。海伦是一名公司小...
    一个人的秘密阅读 80评论 0 0