使用FlexboxLayout构建灵活的布局

WCUMarisol 7年前
   <p>去年的 Google I/O大会上我们宣布了 <a href="/misc/goto?guid=4959739280310014617" rel="nofollow,noindex">ConstraintLayout</a> , 一个用简单的视图结构就能构建复杂布局的控件。另外,它还完全支持Android Studio的 <a href="/misc/goto?guid=4959739280310014617" rel="nofollow,noindex">可视化布局编辑器</a> 。</p>    <p>与此同时,我们开源了 <a href="/misc/goto?guid=4959672737205884462" rel="nofollow,noindex">FlexboxLayout</a> ,把css中的  <a href="/misc/goto?guid=4958996763339972676" rel="nofollow,noindex">Flexbox布局(Flexible Box)模块</a> 带到了安卓中。这里就是一些FlexboxLayout特别有用的情形。</p>    <p>FlexboxLayout可以理解成一个高级版的LinearLayout,因为两个布局都把子view按顺序排列。两者之间最大的差别在于FlexboxLayout具有换行的特性。</p>    <p>也就是说如果你添加了flexWrap="wrap"属性,在当前行空间不足的情况下FlexboxLayout将把view放在下一行,就如下图这样:</p>    <p><img src="https://simg.open-open.com/show/3301a827570126d023a285f30b91039c.png"></p>    <h3>一个布局使用不同屏幕尺寸</h3>    <p>在这个特性的基础上,让我们考虑一个按序排列视图,但是在空间发生变化的时候可以让view移到新的一行的情况(可能因为设备因素,横竖屏变化,或者多窗口模式下的窗口调整)。</p>    <p><img src="https://simg.open-open.com/show/4659d44e2b8695bbdba0ec713559476c.png"></p>    <p>Nexus5X 竖屏</p>    <p><img src="https://simg.open-open.com/show/41157fc88412b219215cf811ab773a21.png"></p>    <p>Nexus5X 横屏</p>    <p><img src="https://simg.open-open.com/show/95cb97a6709614ec84658a1aa115a466.png"></p>    <p>启用多窗口模式,分割线在左边的的Pixel C</p>    <p><img src="https://simg.open-open.com/show/1b78a7a605094579bcaadf54f58b06ef.png"></p>    <p>启用多窗口模式,分割线在中间的的Pixel C</p>    <p><img src="https://simg.open-open.com/show/5f173750e2589e0aae2e4f09d8c05ee3.png"></p>    <p>启用多窗口模式,分割线在右边的的Pixel C</p>    <p>如果使用传统的布局,比如 LinearLayout或者RelativeLayout,你需要定义多个DP分类的布局(layout-600dp, layout-720dp, layout-1020dp)来处理屏幕尺寸的问题。但是上面的对话框其实是用一个FlexboxLayout构建的。</p>    <p>这个例子中使用到的技术就是前面提到的flexWrap="wrap",</p>    <pre>  <code class="language-java"><com .google.android.flexbox.flexboxlayout        android:layout_width="match_parent"        android:layout_height="wrap_content"        app:flexwrap="wrap"></code></pre>    <p>然后你就可以得到下面这种能换行的布局,而不是视图从它的父布局益出。</p>    <p><img src="https://simg.open-open.com/show/386aa53bfc3255d30294c910db50137f.png"></p>    <p>另一个要强调的技术就是为单个子view设置layout_flexGrow 。在空间有剩余的情况下,这可以帮助改善布局的最终外观。layout_flexGrow属性类似于LinearLayout中的layout_weight。也就是说,FlexboxLayout将根据同一行中每个子view的layout_flexGrow的值来分配剩余的空间。</p>    <p>在下面的例子中,假设每个子view的layout_flexGrow属性为1,那么剩余空间将平均分配到每个子view。</p>    <pre>  <code class="language-java"> <android .support.design.widget.TextInputLayout       android:layout_width="100dp"       android:layout_height="wrap_content"        app:layout_flexgrow="1"></code></pre>    <p><img src="https://simg.open-open.com/show/36d8dbd9d91568f864fb048bce13534b.png"></p>    <p>你可以在GitHub仓库上找到完整的 <a href="/misc/goto?guid=4959739280462122042" rel="nofollow,noindex">layout xml</a> 文件。</p>    <h3>RecyclerView集成</h3>    <p>FlexboxLayout的另一个好处是可以和 <a href="/misc/goto?guid=4959739280544432877" rel="nofollow,noindex">RecyclerView</a> 集成。最新的 <a href="/misc/goto?guid=4959739280628902966" rel="nofollow,noindex">alpha 版本</a> 中, Flexbox可以作为一个 LayoutManager(FlexboxLayoutManager)用在RecyclerView中。现在你可以以更内存友好的方式在滚动容器中使用Flexbox的功能了。</p>    <p>不过你仍然可以把FlexboxLayout放在ScrollView中来实现滚动。但是这样的话如果item过多很可能会造成卡顿和内存益处的错误,因为FlexboxLayout并不会回收那些滚动出屏幕的view。</p>    <p>(如果你想了解RecyclerView的更多细节,可以看看来自ndroid UI toolkit团队的视频,比如 <a href="/misc/goto?guid=4959739280711201881" rel="nofollow,noindex">1</a> ,  <a href="/misc/goto?guid=4959739280786664927" rel="nofollow,noindex">2</a> )</p>    <p>集成RecyclerView能带来好处的真实的例子是 Google Photo app或者新闻app,两者都具有大量的宽度各异的item。</p>    <p>FlexboxLayout仓库的 <a href="/misc/goto?guid=4959739280858904070" rel="nofollow,noindex">demo application</a> 中有一个这样的例子,RecyclerView中的每个image宽度不同。但是通过把flexWrap设置为wrap,</p>    <pre>  <code class="language-java">FlexboxLayoutManager layoutManager = new FlexboxLayoutManager();  layoutManager.setFlexWrap(FlexWrap.WRAP);</code></pre>    <p>并把每个子view的flexGrow设置为一个正数,(就如你看到的,我们可以通过FlexboxLayoutManager和FlexboxLayoutManager.LayoutParam设置这个属性,而不通过xml)</p>    <pre>  <code class="language-java">void bindTo(Drawable drawable) {    mImageView.setImageDrawable(drawable);    ViewGroup.LayoutParams lp = mImageView.getLayoutParams();    if (lp instanceof FlexboxLayoutManager.LayoutParams) {      FlexboxLayoutManager.LayoutParams flexboxLp =           (FlexboxLayoutManager.LayoutParams) mImageView.getLayoutParams();      flexboxLp.setFlexGrow(1.0f);    }  }</code></pre>    <p>你可以看到不管屏幕方向如何,布局中的每一个image都排列得都很合适。</p>    <p>要看看完整的FlexboxLayout,请到:</p>    <ul>     <li> <p><a href="/misc/goto?guid=4959739280948146886" rel="nofollow,noindex">Playground demo app</a> - 使用 FlexboxLayout 和 FlexboxLayoutManager.</p> </li>     <li> <p><a href="/misc/goto?guid=4959739280858904070" rel="nofollow,noindex">Cat gallery demo app</a> - 使用 FlexboxLayoutManager</p> </li>    </ul>    <h3>接下来是什么?</h3>    <p>需要其它属性构建量为自己身定做的布局请看完整的 <a href="/misc/goto?guid=4959672737205884462" rel="nofollow,noindex">文档</a> 。我们非常欢迎来自你的反馈,如果发现什么问题或者有新的功能需求,请在  <a href="/misc/goto?guid=4959739281059794616" rel="nofollow,noindex">GitHub repository</a> 上提交issue。</p>    <p> </p>    <p>来自:http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2017/0228/7174.html</p>    <p> </p>