android流式布局控件

来源:互联网 发布:网络贷款系统 编辑:程序博客网 时间:2024/06/06 03:38

另外再说一个控件,先看效果图:




使用代码如下:


private void init() {FlowLayout flow = (FlowLayout) findViewById(R.id.flow);for(String s : data){TextView tv = new TextView(this);tv.setText(s);int padding = dip2Px(5);tv.setPadding(padding, padding, padding, padding);tv.setGravity(Gravity.CENTER);tv.setTextColor(Color.WHITE);GradientDrawable bg = new GradientDrawable();bg.setCornerRadius(dip2Px(6));Random random = new Random();int alpha = 255;int red = random.nextInt(190)+30;int green = random.nextInt(190)+30;int blue = random.nextInt(190)+30;int argb = Color.argb(alpha, red, green, blue);bg.setColor(argb);tv.setClickable(true);tv.setBackgroundDrawable(bg);int dip = dip2Px(5);flow.setSpace(dip, dip);flow.addView(tv);}}

很简单,FlowLayout继承ViewGroup,用addView将View添加进去就行,有兴趣的童鞋可以写一个Adapter方便使用,老规矩,本人一向喜欢直入主题,看源码实现:


public FlowLayout(Context context, AttributeSet attrs) {super(context, attrs);}public FlowLayout(Context context) {super(context);}

可见构造方法没有改变。


@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// 清空记录mLines.clear();mCurrentLine = null;// 获得layout的宽度int widthSize = MeasureSpec.getSize(widthMeasureSpec);int childMaxWidth = widthSize - getPaddingLeft() - getPaddingRight();// 子控件个数int count = getChildCount();// 测量孩子for (int i = 0; i < count; i++) {// 具体孩子View child = getChildAt(i);// 判断是否显示if (child.getVisibility() == View.GONE) {continue;}// 测量每一个孩子measureChild(child, widthMeasureSpec, heightMeasureSpec);// 记录孩子到行中if (mCurrentLine == null) {// 新建一行mCurrentLine = new Line(childMaxWidth, mHorizontalSpace);// 将这一行记录到listmLines.add(mCurrentLine);}if (mCurrentLine.canAdd(child)) {// 可以添加mCurrentLine.addView(child);} else {// 不可以添加// 新建一行mCurrentLine = new Line(childMaxWidth, mHorizontalSpace);// 将这一行记录到listmLines.add(mCurrentLine);// 将child加到linemCurrentLine.addView(child);}}// 行的高度的累加int heightSize = getPaddingTop() + getPaddingBottom();for (int i = 0; i < mLines.size(); i++) {Line line = mLines.get(i);heightSize += line.mHeight;if (i != 0) {// 垂直的间隙heightSize += mVerticalSpace;}}// setMeasuredDimension:设置自己宽度和高度setMeasuredDimension(widthSize, heightSize);}

自定义View中的三方法之一,onMeasure中先是计算出了自身的宽度,再通知子View测量,这是为了得到子View的具体大小,在通过行容器判断能否添加,如果不能新建一行,最后计算出自身的宽高设定。


@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// 获取上边距int top = getPaddingTop();// 遍历行for (int i = 0; i < mLines.size(); i++) {Line line = mLines.get(i);// 让行布局line.layout(getPaddingLeft(), top);// 高度计算top += line.mHeight;// 加上间隙if (i != mLines.size() - 1) {top += mVerticalSpace;}}}

自定义View中的三方法之一,onLayout用于计算View放置的位置,left值交由Line内部计算,这里主要计算每个Line的Top。


Line是FlowLayout内部的封装类,用来记录描述 layout中的行的信息,它只有一个构造方法。


// 构造public Line(int maxWidth, int space) {this.mMaxWidth = maxWidth;this.mSpace = space;}

mMaxWidth代表最大宽度,mSpace代表间隙。


/** 布局 */public void layout(int pLeft, int pTop) {// 多余的宽度int extraWidth = mMaxWidth - mCurrentWidth;// 获得平均值int avgWidth = (int) (extraWidth * 1f / mViews.size() + .5f);// 给View布局for (int i = 0; i < mViews.size(); i++) {View view = mViews.get(i);// 测量宽int width = view.getMeasuredWidth();// 测量高int height = view.getMeasuredHeight();// 平均值大于0if (avgWidth > 0) {// 指定孩子具体的大小view.measure(MeasureSpec.makeMeasureSpec(width + avgWidth,MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY));// 重新获取宽高width = view.getMeasuredWidth();height = view.getMeasuredHeight();}// 多余的高度int extraHeight = mHeight - height;// 指定左边距int l = pLeft;// 指定上边距int t = (int) (pTop + extraHeight / 2f + .5f);// 右边据int r = l + width;// 下边据int b = t + height;// 设置控件大小view.layout(l, t, r, b);// 左值计算pLeft += width + mSpace;}}

这里的主要方法就是这个onLayout,计算行内View所要安置的位置,具体的都写了注释,不多讲。


最后同样附上Demo以供参考。

0 0
原创粉丝点击