版权声明:本文为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;
}
}
效果图
混淆配置
无
参考资料
Android可伸缩布局-FlexboxLayout(支持RecyclerView集成)
Google 开源的 Android 排版库:FlexboxLayout
项目demo下载地址
https://github.com/haiyuKing/RecyclerFlexboxLayoutManagerDemo