android流式布局热门标签的实现
16lz
2021-01-23
在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天就为大家分享一种android流式布局的实现。
先看最终效果
自定义流式布局的实现
package com.sunny.flowlayout.view;import java.util.ArrayList;import java.util.List;import android.content.Context;import android.util.AttributeSet;import android.util.Log;import android.view.View;import android.view.ViewGroup;public class FlowLayout extends ViewGroup {public FlowLayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);}public FlowLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public FlowLayout(Context context) {this(context, null);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);// wrap_contentint width = 0;int height = 0;// 记录每一行的宽度与高度int lineWidth = 0;int lineHeight = 0;// 得到内部元素的个数int cCount = getChildCount();for (int i = 0; i < cCount; i++) {View child = getChildAt(i);// 测量子View的宽和高measureChild(child, widthMeasureSpec, heightMeasureSpec);// 得到LayoutParamsMarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();// 子View占据的宽度int childWidth = child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;// 子View占据的高度int childHeight = child.getMeasuredHeight() + lp.topMargin+ lp.bottomMargin;// 换行if (lineWidth + childWidth > sizeWidth - getPaddingLeft()- getPaddingRight()) {// 对比得到最大的宽度width = Math.max(width, lineWidth);// 重置lineWidthlineWidth = childWidth;// 记录行高height += lineHeight;lineHeight = childHeight;} else// 未换行{// 叠加行宽lineWidth += childWidth;// 得到当前行最大的高度lineHeight = Math.max(lineHeight, childHeight);}// 最后一个控件if (i == cCount - 1) {width = Math.max(lineWidth, width);height += lineHeight;}}setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width+ getPaddingLeft() + getPaddingRight(),modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height+ getPaddingTop() + getPaddingBottom()//);}/** * 存储所有的View */private List> mAllViews = new ArrayList
>();/** * 每一行的高度 */private List
mLineHeight = new ArrayList ();@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {mAllViews.clear();mLineHeight.clear();// 当前ViewGroup的宽度int width = getWidth();int lineWidth = 0;int lineHeight = 0;List lineViews = new ArrayList ();int cCount = getChildCount();for (int i = 0; i < cCount; i++) {View child = getChildAt(i);MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();// 如果需要换行 if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width- getPaddingLeft() - getPaddingRight()) {// 记录LineHeightmLineHeight.add(lineHeight);// 记录当前行的ViewsmAllViews.add(lineViews);// 重置我们的行宽和行高lineWidth = 0;lineHeight = childHeight + lp.topMargin + lp.bottomMargin;// 重置我们的View集合lineViews = new ArrayList ();}lineWidth += childWidth + lp.leftMargin + lp.rightMargin;lineHeight = Math.max(lineHeight, childHeight + lp.topMargin+ lp.bottomMargin);lineViews.add(child);}// for end// 处理最后一行mLineHeight.add(lineHeight);mAllViews.add(lineViews);// 设置子View的位置int left = getPaddingLeft();int top = getPaddingTop();// 行数int lineNum = mAllViews.size();for (int i = 0; i < lineNum; i++) {// 当前行的所有的ViewlineViews = mAllViews.get(i);lineHeight = mLineHeight.get(i);for (int j = 0; j < lineViews.size(); j++) {View child = lineViews.get(j);// 判断child的状态if (child.getVisibility() == View.GONE) {continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int lc = left + lp.leftMargin;int tc = top + lp.topMargin;int rc = lc + child.getMeasuredWidth();int bc = tc + child.getMeasuredHeight();// 为子View进行布局child.layout(lc, tc, rc, bc);left += child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;}left = getPaddingLeft();top += lineHeight;}}/** * 与当前ViewGroup对应的LayoutParams */@Overridepublic LayoutParams generateLayoutParams(AttributeSet attrs) {return new MarginLayoutParams(getContext(), attrs);}}
流式布局代码实现的注释还算比较详细,请参考具体代码及注释说明。
流式布局xml文件
主页面Activity的实现
package com.sunny.flowlayout;import com.sunny.flowlayout.view.FlowLayout;import android.R.mipmap;import android.os.Bundle;import android.app.ActionBar.LayoutParams;import android.app.Activity;import android.view.LayoutInflater;import android.view.Menu;import android.view.ViewGroup.MarginLayoutParams;import android.widget.Button;import android.widget.TextView;public class FlowLayoutActivity extends Activity {private FlowLayout mFlowLayout;private String[] mVals =new String[]{ "Hello","Android","Welcome","Music","Sport","Working","Game","Fishing","Shopping","Music Singing","Sport happy","Working Hard","Game Team","Fishing river","Shopping more"};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_flow_layout);mFlowLayout = (FlowLayout) findViewById(R.id.id_flowlayout);initData();}//初始化数据public void initData(){LayoutInflater mInflater = LayoutInflater.from(this);for (int i = 0; i < mVals.length; i++) { TextView tv = (TextView) mInflater.inflate(R.layout.tv, mFlowLayout, false);tv.setText(mVals[i]);mFlowLayout.addView(tv);}}}
TextView布局xml文件
<?xml version="1.0" encoding="utf-8"?>
为TextView设置背景样式
<?xml version="1.0" encoding="utf-8"?>
今天是第一次写博客,今天是开始,我会一直坚持下去,欢迎大家一块交流学习
更多相关文章
- Android 自定义View及其在布局文件中的使用示例(三):结合Android
- 关于相对布局RelativeLayout的各种属性介绍
- Android布局(相对布局)
- Android 众多的布局属性详解
- LinearLayout布局实现垂直水平居中
- Android RelativeLayout 相对布局解析
- Android学习笔记(11)---关于布局的一些小事
- Android布局中的常用属性小结