版权声明:本文为HaiyuKing原创文章,转载请注明出处!

前言

FlexboxLayout是一个Google 开源的库项目,它将CSS Flexible Box Layout Module的类似功能 引入Android。

这里只记录FlexboxLayoutManager搭配RecyclerView实现流式布局的实现方式,至于FlexboxLayout的独立使用以及相关资料,请阅读《参考资料》。

效果图

代码分析

将FlexboxLayoutManager理解为RecyclerView的一种manager,比如LinearLayoutManager等。

        //设置布局管理器
FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager(MainActivity.this);
//flexDirection 属性决定主轴的方向(即项目的排列方向)。类似 LinearLayout 的 vertical 和 horizontal。
flexboxLayoutManager.setFlexDirection(FlexDirection.ROW);//主轴为水平方向,起点在左端。
//flexWrap 默认情况下 Flex 跟 LinearLayout 一样,都是不带换行排列的,但是flexWrap属性可以支持换行排列。
flexboxLayoutManager.setFlexWrap(FlexWrap.WRAP);//按正常方向换行
//justifyContent 属性定义了项目在主轴上的对齐方式。
flexboxLayoutManager.setJustifyContent(JustifyContent.FLEX_START);//交叉轴的起点对齐。 mRecyclerView.setLayoutManager(flexboxLayoutManager);

使用步骤

一、项目组织结构图

注意事项:

1、  导入类文件后需要change包名以及重新import R文件路径

2、  Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖

二、导入步骤

(1)在build.gradle中引用recyclerview【版本号和appcompat保持一致】和Flexboxlayout

apply plugin: 'com.android.application'

android {
compileSdkVersion 27
defaultConfig {
applicationId "com.why.project.recyclerflexboxlayoutmanagerdemo"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
} dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.2'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' //RecyclerView
compile "com.android.support:recyclerview-v7:27.1.1"
//FlexboxLayout
implementation 'com.google.android:flexbox:1.0.0'
}

(2)在项目中实现Recyclerview基本数据展现

1、创建Bean类

package com.why.project.recyclerflexboxlayoutmanagerdemo.bean;

import java.util.Date;

/**
* Created by HaiyuKing
* Used 搜索历史记录bean
*/ public class SearchHistoryBean {
private String searchTitle;//搜索的标题
private Date searchDate;//搜索的时间(如果重新搜索了的话,只需要更新搜索时间即可,不需要添加) public String getSearchTitle() {
return searchTitle;
} public void setSearchTitle(String searchTitle) {
this.searchTitle = searchTitle;
} public Date getSearchDate() {
return searchDate;
} public void setSearchDate(Date searchDate) {
this.searchDate = searchDate;
}
}

SearchHistoryBean.java

2、创建Adapter以及item的布局文件

package com.why.project.recyclerflexboxlayoutmanagerdemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView; import com.why.project.recyclerflexboxlayoutmanagerdemo.R;
import com.why.project.recyclerflexboxlayoutmanagerdemo.bean.SearchHistoryBean; import java.util.ArrayList; /**
* Created by HaiyuKing
* Used 搜索记录列表适配器
*/ public class SearchHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
/**上下文*/
private Context myContext;
/**频道集合*/
private ArrayList<SearchHistoryBean> listitemList; /**
* 构造函数
*/
public SearchHistoryAdapter(Context context, ArrayList<SearchHistoryBean> itemlist) {
myContext = context;
listitemList = itemlist;
} /**
* 获取总的条目数
*/
@Override
public int getItemCount() {
return listitemList.size();
} /**
* 创建ViewHolder
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(myContext).inflate(R.layout.searchhistory_list_item, parent, false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
} /**
* 声明grid列表项ViewHolder*/
static class ItemViewHolder extends RecyclerView.ViewHolder
{
public ItemViewHolder(View view)
{
super(view); listItemLayout = (LinearLayout) view.findViewById(R.id.listitem_layout);
mTitle = (TextView) view.findViewById(R.id.tv_title);
} LinearLayout listItemLayout;
TextView mTitle;
} /**
* 将数据绑定至ViewHolder
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int index) { //判断属于列表项还是上拉加载区域
if(viewHolder instanceof ItemViewHolder){
SearchHistoryBean searchHistoryBean = listitemList.get(index);
final ItemViewHolder itemViewHold = ((ItemViewHolder)viewHolder); itemViewHold.mTitle.setText(searchHistoryBean.getSearchTitle()); //如果设置了回调,则设置点击事件
if (mOnItemClickLitener != null)
{
itemViewHold.listItemLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = itemViewHold.getLayoutPosition();//在增加数据或者减少数据时候,position和index就不一样了
mOnItemClickLitener.onItemClick(itemViewHold.listItemLayout, position);
}
});
} }
} /**
* 添加Item--用于动画的展现*/
public void addItem(int position,SearchHistoryBean listitemBean) {
listitemList.add(position,listitemBean);
notifyItemInserted(position);
}
/**
* 删除Item--用于动画的展现*/
public void removeItem(int position) {
listitemList.remove(position);
notifyItemRemoved(position);
} /*=====================添加OnItemClickListener回调================================*/
public interface OnItemClickLitener
{
void onItemClick(View view, int position);
} private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
{
this.mOnItemClickLitener = mOnItemClickLitener;
}
}

SearchHistoryAdapter.java

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/listitem_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp"
android:layout_marginTop="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="@drawable/searchhistory_item_bg"> <TextView
android:id="@+id/tv_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="标题"
android:textSize="14sp"
android:textColor="#333333"
android:layout_gravity="center"/> </LinearLayout>

searchhistory_list_item.xml

列表项布局文件中用到了背景drawable文件

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
<!-- 填充-->
<solid android:color="#00000000"/>
<!-- 描边 -->
<stroke
android:width="1dp"
android:color="#7F7F7F" />
<!-- 圆角 -->
<corners
android:radius="2dp" />
</shape>

searchhistory_item_bg.xml

3、在Activity布局文件中引用Recyclerview控件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#ffffff"> <TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="历史记录"/> <!-- RecyclerView列表 -->
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:cacheColorHint="#00000000"
android:divider="@null"
android:listSelector="#00000000"
android:scrollbars="none"
/>
</LinearLayout>

三、使用方法

(1)Activity中使用如下

package com.why.project.recyclerflexboxlayoutmanagerdemo;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.RecyclerView;
import android.view.View;
import android.widget.Toast; import com.google.android.flexbox.FlexDirection;
import com.google.android.flexbox.FlexWrap;
import com.google.android.flexbox.FlexboxLayoutManager;
import com.google.android.flexbox.JustifyContent;
import com.why.project.recyclerflexboxlayoutmanagerdemo.adapter.SearchHistoryAdapter;
import com.why.project.recyclerflexboxlayoutmanagerdemo.bean.SearchHistoryBean; import java.util.ArrayList;
import java.util.Calendar; public class MainActivity extends AppCompatActivity { private RecyclerView mRecyclerView;
private ArrayList<SearchHistoryBean> mSearchHistoryBeanArrayList;
private SearchHistoryAdapter mSearchHistoryAdapter; @Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main); initViews();
initDatas();
initEvents();
} private void initViews() {
mRecyclerView = findViewById(R.id.recycler_view);
} private void initDatas() {
//初始化集合
mSearchHistoryBeanArrayList = new ArrayList<SearchHistoryBean>();
String[] testDatas = new String[]{"牙刷","灭蚊器","移动空调","吸尘器","布衣柜","收纳箱 书箱","暑期美食满99减15","挂烫机","吸水拖把","反季特惠"};
for(int i=0; i<testDatas.length;i++){
SearchHistoryBean channelBean = new SearchHistoryBean();
channelBean.setSearchTitle(testDatas[i]);
//获取当前日期
Calendar calendar = Calendar.getInstance();
channelBean.setSearchDate(calendar.getTime()); mSearchHistoryBeanArrayList.add(channelBean);
} //设置布局管理器
FlexboxLayoutManager flexboxLayoutManager = new FlexboxLayoutManager(MainActivity.this);
//flexDirection 属性决定主轴的方向(即项目的排列方向)。类似 LinearLayout 的 vertical 和 horizontal。
flexboxLayoutManager.setFlexDirection(FlexDirection.ROW);//主轴为水平方向,起点在左端。
//flexWrap 默认情况下 Flex 跟 LinearLayout 一样,都是不带换行排列的,但是flexWrap属性可以支持换行排列。
flexboxLayoutManager.setFlexWrap(FlexWrap.WRAP);//按正常方向换行
//justifyContent 属性定义了项目在主轴上的对齐方式。
flexboxLayoutManager.setJustifyContent(JustifyContent.FLEX_START);//交叉轴的起点对齐。 mRecyclerView.setLayoutManager(flexboxLayoutManager); //设置适配器
if(mSearchHistoryAdapter == null){
//设置适配器
mSearchHistoryAdapter = new SearchHistoryAdapter(this, mSearchHistoryBeanArrayList);
mRecyclerView.setAdapter(mSearchHistoryAdapter);
//添加分割线
//设置添加删除动画
//调用ListView的setSelected(!ListView.isSelected())方法,这样就能及时刷新布局
mRecyclerView.setSelected(true);
}else{
mSearchHistoryAdapter.notifyDataSetChanged();
}
}private void initEvents() {
//列表适配器的点击监听事件
mSearchHistoryAdapter.setOnItemClickLitener(new SearchHistoryAdapter.OnItemClickLitener() {
@Override
public void onItemClick(View view, int position) {
Toast.makeText(MainActivity.this, mSearchHistoryBeanArrayList.get(position).getSearchTitle(), Toast.LENGTH_SHORT).show();
}
});
}
}

效果图:

(2)如果在Adapter中添加以下代码,效果图则会发生变化(原理请阅读《参考资料》)【这段代码更适合用于图片展示,这里是搜索记录文本展现,不太合适】

package com.why.project.recyclerflexboxlayoutmanagerdemo.adapter;

import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView; import com.google.android.flexbox.AlignSelf;
import com.google.android.flexbox.FlexboxLayoutManager;
import com.why.project.recyclerflexboxlayoutmanagerdemo.R;
import com.why.project.recyclerflexboxlayoutmanagerdemo.bean.SearchHistoryBean; import java.util.ArrayList; /**
* Created by HaiyuKing
* Used 搜索记录列表适配器
*/ public class SearchHistoryAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{
/**上下文*/
private Context myContext;
/**频道集合*/
private ArrayList<SearchHistoryBean> listitemList; /**
* 构造函数
*/
public SearchHistoryAdapter(Context context, ArrayList<SearchHistoryBean> itemlist) {
myContext = context;
listitemList = itemlist;
} /**
* 获取总的条目数
*/
@Override
public int getItemCount() {
return listitemList.size();
} /**
* 创建ViewHolder
*/
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(myContext).inflate(R.layout.searchhistory_list_item, parent, false);
ItemViewHolder itemViewHolder = new ItemViewHolder(view);
return itemViewHolder;
} /**
* 声明grid列表项ViewHolder*/
static class ItemViewHolder extends RecyclerView.ViewHolder
{
public ItemViewHolder(View view)
{
super(view); listItemLayout = (LinearLayout) view.findViewById(R.id.listitem_layout);
mTitle = (TextView) view.findViewById(R.id.tv_title);
} LinearLayout listItemLayout;
TextView mTitle;
} /**
* 将数据绑定至ViewHolder
*/
@Override
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int index) { //判断属于列表项还是上拉加载区域
if(viewHolder instanceof ItemViewHolder){
SearchHistoryBean searchHistoryBean = listitemList.get(index);
final ItemViewHolder itemViewHold = ((ItemViewHolder)viewHolder); itemViewHold.mTitle.setText(searchHistoryBean.getSearchTitle()); ViewGroup.LayoutParams lp = itemViewHold.listItemLayout.getLayoutParams();
if (lp instanceof FlexboxLayoutManager.LayoutParams) {
FlexboxLayoutManager.LayoutParams flexboxLp =
(FlexboxLayoutManager.LayoutParams) itemViewHold.listItemLayout.getLayoutParams();
flexboxLp.setFlexGrow(1.0f);
flexboxLp.setAlignSelf(AlignSelf.FLEX_END);
} //如果设置了回调,则设置点击事件
if (mOnItemClickLitener != null)
{
itemViewHold.listItemLayout.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
int position = itemViewHold.getLayoutPosition();//在增加数据或者减少数据时候,position和index就不一样了
mOnItemClickLitener.onItemClick(itemViewHold.listItemLayout, position);
}
});
} }
} /**
* 添加Item--用于动画的展现*/
public void addItem(int position,SearchHistoryBean listitemBean) {
listitemList.add(position,listitemBean);
notifyItemInserted(position);
}
/**
* 删除Item--用于动画的展现*/
public void removeItem(int position) {
listitemList.remove(position);
notifyItemRemoved(position);
} /*=====================添加OnItemClickListener回调================================*/
public interface OnItemClickLitener
{
void onItemClick(View view, int position);
} private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener)
{
this.mOnItemClickLitener = mOnItemClickLitener;
}
}

效果图

混淆配置

参考资料

google/flexbox-layout

Android FlexboxLayout 聪明的UI布局

Android可伸缩布局-FlexboxLayout(支持RecyclerView集成)

Google 开源的 Android 排版库:FlexboxLayout

项目demo下载地址

https://github.com/haiyuKing/RecyclerFlexboxLayoutManagerDemo

RecyclerFlexboxLayoutManagerDemo【使用FlexboxLayoutManager实现流式布局】的更多相关文章

  1. 流式布局&固定宽度&响应式&rem

    我们现在在切页面布局的使用常用的单位是px,这是一个绝对单位,web app的屏幕适配有很多中做法,例如:流式布局.限死宽度,还有就是通过响应式来做,但是这些方案都不是最佳的解决方法. 1.流式布局: ...

  2. webapp,liveapp: 流式布局和rem布局

    liveapp场景应用,一般针对的是移动端,近来也是很火,颇有一些感受,拿来分享一下. 页面宽度范围: 一般移动端页面我们的像素范围是320px-640px,最大640px,最小320px,所以设计稿 ...

  3. JAVA 流式布局管理器

    //流式布局管理器 import java.awt.*; import javax.swing.*; public class Jiemian2 extends JFrame{ //定义组件 JBut ...

  4. 自定义View(三)--实现一个简单地流式布局

    Android中的流式布局也就是常说的瀑布流很是常见,不仅在很多项目中都能见到,而且面试中也有很多面试官问道,那么什么是流式布局呢?简单来说就是如果当前行的剩余宽度不足以摆放下一个控件的时候,则自动将 ...

  5. Android 自动换行流式布局的RadioGroup

    效果图 用法 使用FlowRadioGroup代替RadioGroup 代码 import android.content.Context; import android.util.Attribute ...

  6. Android 自定义View修炼-Android中常见的热门标签的流式布局的实现

    一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出哈) 类似的 ...

  7. 转:Java图形化界面设计——布局管理器之FlowLayout(流式布局)其他请参考转载出处网址

    http://blog.csdn.net/liujun13579/article/details/7771191 前文讲解了JFrame.JPanel,其中已经涉及到了空布局的使用.Java虽然可以以 ...

  8. 自定义ViewGroup 流式布局

    使用 public class MainActivity extends Activity {     @Override     protected void onCreate(Bundle sav ...

  9. Android流式布局实现

    查看我的所有开源项目[开源实验室] 欢迎增加我的QQ群:[201055521],本博客client下载[请点击] 摘要 新项目用到了一种全新布局----Android标签流式布局的功能,正好一直说给大 ...

随机推荐

  1. stack的empty()

    public static void main(String[] args) { Stack stack=null; System.out.println("1."+stack.e ...

  2. NOI前的考试日志

    4.14 网络流专项测试 先看T1,不会,看T2,仙人掌???wtf??弃疗.看T3,貌似最可做了,然后开始刚,刚了30min无果,打了50分暴力,然后接着去看T1,把序列差分了一下,推了会式子,发现 ...

  3. BZOJ_2212_[Poi2011]Tree Rotations_线段树合并

    BZOJ_2212_[Poi2011]Tree Rotations_线段树合并 Description Byteasar the gardener is growing a rare tree cal ...

  4. BZOJ_2058_[Usaco2010 Nov]Cow Photographs_逆序对

    BZOJ_2058_[Usaco2010 Nov]Cow Photographs_逆序对 题意: 奶牛的图片 Farmer John希望给他的N(1<=N<=100,000)只奶牛拍照片, ...

  5. appium 元素定位find_element_by_android_uiautomator方法使用

    若appium中给定的方法无法满足你的需求,刚好uiautomator中的方法可以满足你的需求时,你可使用find_element_by_android_uiautomator来调用uiautomat ...

  6. python——几种截图对比方式!

    本次记录的几种截图对比方式,主要是为了在进行手机自动化测试时,通过截图对比来判断测试的正确性,方式如下: # -*- coding: utf- -*- ''' 用途:利用python实现多种方法来实现 ...

  7. 离线安装mysql数据库

    开源数据库mysql,目前使用很广泛.作为程序员开发项目时,与关系型数据库打交道最多的估计也是mysql了.那么本文首先讲解如何离线安装mysql数据库,毕竟有很多项目部署在内网. 1.离线安装 本人 ...

  8. 作为一个零基础的新手,如何系统的自学Java和JavaEE开发技术?

    其实这个问题很简单,我用最简单的语言给大家描述一下,学习一样东西就要了解这样东西学完了要干什么事情,有什么作用.然后就是应该学习哪些必要的内容,该如何运用得当的方法进行有效率的学习不至于自己摸不着头脑 ...

  9. 一致性 Hash 算法的实际应用

    前言 记得一年前分享过一篇<一致性 Hash 算法分析>,当时只是分析了这个算法的实现原理.解决了什么问题等. 但没有实际实现一个这样的算法,毕竟要加深印象还得自己撸一遍,于是本次就当前的 ...

  10. 浏览器插件使用socks5代理

    服务端测试,经常会遇到需要通过代理访问的情景,比如公司内网不能访问测试环境,这时可以通过socks5代理来解决. 一.使用Chrome浏览器访问   1. 下载并安装SwitchyOmega插件   ...