自定义控件:流式布局
来源:互联网 发布:张艺谋奥运会知乎 编辑:程序博客网 时间:2024/04/19 18:56
实现代码
public class FlowLayout extends ViewGroup { private List<Line> mLines = new ArrayList<Line>(); // 用来记录描述有多少行View private Line mCurrrenLine; // 用来记录当前已经添加到了哪一行 private int mHorizontalSpace = 10; private int mVerticalSpace = 10; 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; } @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 { // 不可以添加,装不下去 // 换行 // 新建行 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) { // 改变宽度,View的长度改变了,需要重新measure int newWidth = (int) (viewWidth + widthAvg + 0.5f); 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; } } }}
public class FlowActivity extends AppCompatActivity { private ScrollView mScrollView; private FlowLayout mFlowLayout; private List<String> mData; private Gson mGson; private String appname = "['QQ','视频','京东','youni有你','万年历-农历黄历','支付宝钱包']"; @Override protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); initData(); initView(); } private void initData() { mGson = new Gson(); mData = mGson.fromJson(appname,new TypeToken<List<String>>(){}.getType()); } private void initView() { setContentView(mScrollView = new ScrollView(this)); SpannableString title = new SpannableString("流式布局,热门标签"); title.setSpan(new ForegroundColorSpan(Color.WHITE),0,title.length(), Spannable.SPAN_INCLUSIVE_EXCLUSIVE); ActionBar actionBar = getSupportActionBar(); actionBar.setTitle(title); mScrollView.setBackgroundColor(Color.parseColor("#eaeaea")); mScrollView.setVerticalScrollBarEnabled(false); mFlowLayout = new FlowLayout(this); int padding = UIUtil.dip2px(15); mFlowLayout.setPadding(UIUtil.dip2px(10), padding, UIUtil.dip2px(10), padding); mFlowLayout.setSpace(UIUtil.dip2px(10), UIUtil.dip2px(15)); for (final String data : mData) { TextView textView = new TextView(this); int tvPadding = UIUtil.dip2px(10); textView.setPadding(UIUtil.dip2px(15), tvPadding, UIUtil.dip2px(15), tvPadding); textView.setGravity(Gravity.CENTER); textView.setTextSize(16); textView.setText(data); textView.setTextColor(Color.WHITE); Random random = new Random();//Math.random() int alpha = 255; int green = random.nextInt(190) + 30; int red = random.nextInt(190) + 30; int blue = random.nextInt(190) + 30; int argb = Color.argb(alpha, red, green, blue); //设置shape GradientDrawable normalDrawable = new GradientDrawable(); normalDrawable.setCornerRadius(UIUtil.dip2px(6)); normalDrawable.setColor(argb); GradientDrawable pressedDrawable = new GradientDrawable(); pressedDrawable.setColor(Color.DKGRAY); pressedDrawable.setCornerRadius(UIUtil.dip2px(5)); //设置选择器selector StateListDrawable stateListDrawable = new StateListDrawable(); stateListDrawable.addState(new int[]{android.R.attr.state_pressed}, pressedDrawable); stateListDrawable.addState(new int[]{}, normalDrawable); textView.setBackgroundDrawable(stateListDrawable); textView.setClickable(true); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { ToastUtil.toast(data); } }); mFlowLayout.addView(textView); } mScrollView.addView(mFlowLayout); }}
0 0
- 自定义流式布局控件
- 自定义控件:流式布局
- 流式布局(自定义控件)
- 自定义流式布局控件FlowLayout
- 流式布局 自定义控件 特别热
- android 自定义控件实现流式布局
- 自定义控件之-流式布局FlowLayout
- Android自定义控件--流式布局(FlowLayout)
- 自定义控件之流式布局
- 自定义控件实践——流式布局
- Android自定义控件--流式布局(FlowLayout)--自动适配
- Android流式标签布局,自定义标签控件tagView
- android 自定义控件--用viewGroup实现流式布局
- Android自定义控件之流式布局
- 自定义控件之流式布局FlowLayout
- 自定义布局控件
- 自定义布局控件
- 自定义流式布局
- 开发过程遇到的一些问题(三)
- 算法提高 数字黑洞
- opencl _高斯核卷积
- 安卓OkHttp封装
- poj_1961 Period(KMP)
- 自定义控件:流式布局
- Spring Boot 入门
- ISO8583报文中的编、解码总结
- 【数据结构】-线性表-链表 熟练度max=3(不建立新节点,使链表L倒序)
- android7.1 保存图片到系统图库
- windows环境下编译skia
- 多线程情况下如何捕获线程中的异常?
- 抽象类(abstract)和接口(interface)的区别
- 利用Jenkins+Phantomas进行前端性能自动化测试