请看效果图:
导航.png依赖:
粘性头部局:
在Module的build.gradle里面添加依赖:
implementation 'com.github.qdxxxx:StickyHeaderDecoration:1.0.1'
然后在项目的build.gradle中添加:
allprojects {
repositories {
google()
jcenter()
maven { url 'https://jitpack.io' }//添加这个
}
}
VerticalTabLayout垂直tab的依赖:
//垂直 VerticalTabLayout
implementation 'q.rorbin:VerticalTabLayout:1.2.5'
/RecyclerView的使用 依 赖 :/
implementation 'com.android.support:recyclerview-v7:29.0.1'
接下来看官请看XML文件:
导航页面xml布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#FFFFFF"
tools:context=".ui.wan.fragment.fragment.Wan_navigationFragment">
<q.rorbin.verticaltablayout.VerticalTabLayout
android:id="@+id/wan_navigation_vtab"
android:layout_width="@dimen/x200"
android:layout_height="match_parent"
android:background="#EDEDED"
app:indicator_color="#EDEDED"
app:indicator_width="@dimen/x10"
app:indicator_gravity="left"
app:tab_height="@dimen/x100"
android:visibility="visible"
app:tab_mode="scrollable"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/wan_navigation_rlv"
android:background="@color/cardview_light_background"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<ProgressBar
android:id="@+id/wan_navigation_pb"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"/>
</LinearLayout>
这是一个自定义view,RecyclerView的item布局:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:background="#FFFFFF"
android:layout_height="match_parent">
<com.long.wanandroids.ui.wan.Wan_navigation.view.FlowLayout
android:id="@+id/fl"
android:background="#FFFFFF"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp" />
</LinearLayout>
自定义viewFlowLayout:
public class FlowLayout extends ViewGroup {
private List<Line> mLines = new ArrayList<Line>(); // 用来记录描述有多少行View
private Line mCurrrenLine; // 用来记录当前已经添加到了哪一行
private int mHorizontalSpace = 40;
private int mVerticalSpace = mHorizontalSpace;
private int mMaxLines = -1;
public int getMaxLines() {
return mMaxLines;
}
public void setMaxLines(int maxLines) {
mMaxLines = maxLines;
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
public FlowLayout(Context context) {
super(context);
}
public void setSpace(int horizontalSpace, int verticalSpace) {
this.mHorizontalSpace = horizontalSpace;
this.mVerticalSpace = verticalSpace;
}
public void clearAll() {
mLines.clear();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// 清空
mLines.clear();
mCurrrenLine = null;
int layoutWidth = MeasureSpec.getSize(widthMeasureSpec);
// 获取行最大的宽度
int maxLineWidth = layoutWidth - getPaddingLeft() - getPaddingRight();
// 测量孩子
int count = getChildCount();
for (int i = 0; i < count; i++) {
View view = getChildAt(i);
// 如果子控件不可见
if (view.getVisibility() == View.GONE) {
continue;
}
// 测量子控件
measureChild(view, widthMeasureSpec, heightMeasureSpec);
// 往lines添加孩子
if (mCurrrenLine == null) {
// 说明还没有开始添加孩子
mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);
// 添加到 Lines中
mLines.add(mCurrrenLine);
// 行中一个孩子都没有
mCurrrenLine.addView(view);
} else {
// 行不为空,行中有孩子了
boolean canAdd = mCurrrenLine.canAdd(view);
if (canAdd) {
// 可以添加
mCurrrenLine.addView(view);
} else {
// 不可以添加,装不下去
// 换行
if (mMaxLines > 0) {
if (mLines.size() < mMaxLines) {
// 新建行
mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);
// 添加到lines中
mLines.add(mCurrrenLine);
// 将view添加到line
mCurrrenLine.addView(view);
}
} else {
// 新建行
mCurrrenLine = new Line(maxLineWidth, mHorizontalSpace);
// 添加到lines中
mLines.add(mCurrrenLine);
// 将view添加到line
mCurrrenLine.addView(view);
}
}
}
}
// 设置自己的宽度和高度
int measuredWidth = layoutWidth;
// paddingTop + paddingBottom + 所有的行间距 + 所有的行的高度
float allHeight = 0;
for (int i = 0; i < mLines.size(); i++) {
float mHeigth = mLines.get(i).mHeigth;
// 加行高
allHeight += mHeigth;
// 加间距
if (i != 0) {
allHeight += mVerticalSpace;
}
}
int measuredHeight = (int) (allHeight + getPaddingTop() + getPaddingBottom() + 0.5f);
setMeasuredDimension(measuredWidth, measuredHeight);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 给Child 布局---> 给Line布局
int paddingLeft = getPaddingLeft();
int offsetTop = getPaddingTop();
for (int i = 0; i < mLines.size(); i++) {
Line line = mLines.get(i);
// 给行布局
line.layout(paddingLeft, offsetTop);
offsetTop += line.mHeigth + mVerticalSpace;
}
}
class Line {
// 属性
private List<View> mViews = new ArrayList<View>(); // 用来记录每一行有几个View
private float mMaxWidth; // 行最大的宽度
private float mUsedWidth; // 已经使用了多少宽度
private float mHeigth; // 行的高度
private float mMarginLeft;
private float mMarginRight;
private float mMarginTop;
private float mMarginBottom;
private float mHorizontalSpace; // View和view之间的水平间距
// 构造
public Line(int maxWidth, int horizontalSpace) {
this.mMaxWidth = maxWidth;
this.mHorizontalSpace = horizontalSpace;
}
// 方法
/**
* 添加view,记录属性的变化
*
* @param view
*/
public void addView(View view) {
// 加载View的方法
int size = mViews.size();
int viewWidth = view.getMeasuredWidth();
int viewHeight = view.getMeasuredHeight();
// 计算宽和高
if (size == 0) {
// 说还没有添加View
if (viewWidth > mMaxWidth) {
mUsedWidth = mMaxWidth;
} else {
mUsedWidth = viewWidth;
}
mHeigth = viewHeight;
} else {
// 多个view的情况
mUsedWidth += viewWidth + mHorizontalSpace;
mHeigth = mHeigth < viewHeight ? viewHeight : mHeigth;
}
// 将View记录到集合中
mViews.add(view);
}
/**
* 用来判断是否可以将View添加到line中
*
* @param view
* @return
*/
public boolean canAdd(View view) {
// 判断是否能添加View
int size = mViews.size();
if (size == 0) {
return true;
}
int viewWidth = view.getMeasuredWidth();
// 预计使用的宽度
float planWidth = mUsedWidth + mHorizontalSpace + viewWidth;
if (planWidth > mMaxWidth) {
// 加不进去
return false;
}
return true;
}
/**
* 给孩子布局
*
* @param offsetLeft
* @param offsetTop
*/
public void layout(int offsetLeft, int offsetTop) {
// 给孩子布局
int currentLeft = offsetLeft;
int size = mViews.size();
// 判断已经使用的宽度是否小于最大的宽度
float extra = 0;
float widthAvg = 0;
if (mMaxWidth > mUsedWidth) {
extra = mMaxWidth - mUsedWidth;
widthAvg = extra / size;
}
for (int i = 0; i < size; i++) {
View view = mViews.get(i);
int viewWidth = view.getMeasuredWidth();
int viewHeight = view.getMeasuredHeight();
// 判断是否有富余
if (widthAvg != 0) {
// 改变宽度,变为不改变,避免最后一行因label不足,单个label变宽
//int newWidth = (int) (viewWidth + widthAvg + 0.5f);
int newWidth = viewWidth;
int widthMeasureSpec = MeasureSpec.makeMeasureSpec(newWidth, MeasureSpec.EXACTLY);
int heightMeasureSpec = MeasureSpec.makeMeasureSpec(viewHeight, MeasureSpec.EXACTLY);
view.measure(widthMeasureSpec, heightMeasureSpec);
viewWidth = view.getMeasuredWidth();
viewHeight = view.getMeasuredHeight();
}
// 布局
int left = currentLeft;
int top = (int) (offsetTop + (mHeigth - viewHeight) / 2 +
0.5f);
// int top = offsetTop;
int right = left + viewWidth;
int bottom = top + viewHeight;
view.layout(left, top, right, bottom);
currentLeft += viewWidth + mHorizontalSpace;
}
}
}
}
创建一个TextView的xml文件 item_laber:
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="123456"
android:maxLines="1"
android:ellipsize="end"
android:gravity="center"
android:paddingLeft="12dp"
android:paddingRight="12dp"
android:background="@drawable/shape"
android:paddingBottom="2dp"
android:paddingTop="2dp"
android:textColor="#0F0E0E"
android:textSize="14sp"/>
导航页面的Fragment:
/**
* A simple {@link Fragment} subclass.
*/
public class Wan_navigationFragment extends BaseFragment implements IView {
@BindView(R.id.wan_navigation_vtab)
VerticalTabLayout wanNavigationVtab;
@BindView(R.id.wan_navigation_pb)
ProgressBar wanNavigationPb;
@BindView(R.id.wan_navigation_rlv)
RecyclerView wanNavigationRlv;
private Wan_navigationPresenter wan_navigationPresenter;
private ArrayList<String> titles;
private List<WanNavigationinfo.DataBean> list;
private WanNavigationAdapter wanNavigationAdapter;
private LinearLayoutManager manager;
@Override
protected void initData(Bundle savedInstanceState) {
wan_navigationPresenter = new Wan_navigationPresenter(this);
wan_navigationPresenter.startLoadData();
titles = new ArrayList<>();
manager = new LinearLayoutManager(BaseApp.getContext());
wanNavigationRlv.setLayoutManager(manager);
list = new ArrayList<>();
wanNavigationAdapter = new WanNavigationAdapter(BaseApp.getContext(), list);
wanNavigationRlv.setAdapter(wanNavigationAdapter);
//RecyclerView和tab栏联动
wanNavigationRlv.addOnScrollListener(new RecyclerView.OnScrollListener() {
@Override
public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {
super.onScrollStateChanged(recyclerView, newState);
wanNavigationVtab.setTabSelected(manager.findFirstVisibleItemPosition());
}
});
//tab栏和RecyclerView联动
wanNavigationVtab.addOnTabSelectedListener(new VerticalTabLayout.OnTabSelectedListener() {
@Override
public void onTabSelected(TabView tab, int position) {
manager.scrollToPositionWithOffset(position,0);
}
@Override
public void onTabReselected(TabView tab, int position) {
}
});
}
//布局ID
@Override
protected int getFragmentResLayoutId() {
return R.layout.fragment_wan_navigation;
}
//显示加载中动画
@Override
public void showLoading() {
wanNavigationPb.setVisibility(View.VISIBLE);
}
//关闭加载中动画
@Override
public void hideLoading() {
wanNavigationPb.setVisibility(View.GONE);
}
//返回解析结果
@Override
public void loadDataHttpSucess(Object o) {
if (o instanceof WanNavigationinfo) {
WanNavigationinfo wn = (WanNavigationinfo) o;
final List<WanNavigationinfo.DataBean> data = wn.getData();
for (int i = 0; i < data.size(); i++) {
titles.add(data.get(i).getName());
}
//设置粘性头部局,返回对应的头布局
NormalDecoration normalDecoration = new NormalDecoration() {
@Override
public String getHeaderName(int i) {
return data.get(i).getName();
}
};
//设置item分割
wanNavigationRlv.addItemDecoration(normalDecoration);
//刷新数据
wanNavigationAdapter.addData(data);
}
//垂直Tab
wanNavigationVtab.setTabAdapter(new TabAdapter() {
@Override
public int getCount() {
return titles.size();
}
@Override
public ITabView.TabBadge getBadge(int position) {
return null;
}
@Override
public ITabView.TabIcon getIcon(int position) {
return null;
}
@Override
public ITabView.TabTitle getTitle(int position) {
return new ITabView.TabTitle.Builder()
.setContent(titles.get(position))//从集合中获取标题
.setTextColor(Color.RED, Color.BLACK)
.build();
}
@Override
public int getBackground(int position) {
return 0;
}
});
}
@Override
public void loadDataFaile(String errorMsg) {
showToast(errorMsg);
}
@Override
public void showToast(String msg) {
Toast.makeText(BaseApp.getContext(), msg, Toast.LENGTH_LONG).show();
}
}
导航页面的适配器Adapter:
public class WanNavigationAdapter extends RecyclerView.Adapter<WanNavigationAdapter.ViewHolder> {
private Context context;
private List<WanNavigationinfo.DataBean> list;
public WanNavigationAdapter(Context context, List<WanNavigationinfo.DataBean> list) {
this.context = context;
this.list = list;
}
public void addData(List<WanNavigationinfo.DataBean> dataBeans) {
list.addAll(dataBeans);
notifyDataSetChanged();
}
@NonNull
@Override
public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
View inflate = LayoutInflater.from(context).inflate(R.layout.wannavigationitem, null);
return new ViewHolder(inflate);
}
@Override
public void onBindViewHolder(@NonNull ViewHolder viewHolder, int i) {
WanNavigationinfo.DataBean dataBean = list.get(i);
final List<WanNavigationinfo.DataBean.ArticlesBean> articles = dataBean.getArticles();
if (articles != null && articles.size() > 0) {
for (int j = 0; j < articles.size(); j++) {
TextView label = (TextView) LayoutInflater.from(context).inflate(R.layout.item_laber, null);
label.setText(articles.get(j).getTitle());
final int finalI = j;
//标签点击事件
label.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// ToastUtil.showLong(articles.get(finalI).getTitle());
}
});
//将TextView标签添加到flowlayout
viewHolder.fl.addView(label);
}
}
}
@Override
public int getItemCount() {
return list.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public FlowLayout fl;
public ViewHolder(@NonNull View itemView) {
super(itemView);
fl = itemView.findViewById(R.id.fl);
}
}
}
写的不好,各位看官请多多包含!!! > - <
休息一下吧!
图1.jpg
网友评论