Android 流式布局FlowLayout
2015-03-25 13:57
621 查看
这个是在GitHub上看到的,GitHub地址:https://github.com/blazsolar/FlowLayout
用FlowLayout方便了很多,这是一个很强大的自定义控件,向原作者致敬,下面先放两张我项目中的两张效果图
第一张图在个性标签处用了FlowLayout,第二张图在添加头像处用到了FlowLayout,好了,进入正题
主要用到里边的FlowLayout.java类
转载请注明出处
用FlowLayout方便了很多,这是一个很强大的自定义控件,向原作者致敬,下面先放两张我项目中的两张效果图
第一张图在个性标签处用了FlowLayout,第二张图在添加头像处用到了FlowLayout,好了,进入正题
主要用到里边的FlowLayout.java类
package com.wanglai.widget; import java.util.ArrayList; import java.util.List; import android.annotation.TargetApi; import android.content.Context; import android.content.res.TypedArray; import android.os.Build; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import com.wanglai.main.R; /** * FlowLayout will arrange child elements horizontally one next to another. If there is not enough * space for next view new line will be added. * FlowLayout会水平排列子元素,当一行的空间不足时,将添加新行 * User: Blaz Solar * Date: 5/6/13 * Time: 8:17 PM */ @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public class FlowLayout extends ViewGroup { private int mGravity = (isIcs() ? Gravity.START : Gravity.LEFT) | Gravity.TOP; private final List<List<View>> mLines = new ArrayList<List<View>>(); private final List<Integer> mLineHeights = new ArrayList<Integer>(); private final List<Integer> mLineMargins = new ArrayList<Integer>(); public FlowLayout(Context context) { this(context, null); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); /* 绑定values/attrs.xml里面定义的属性*/ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout, defStyle, 0); try { int index = a.getInt(R.styleable.FlowLayout_android_gravity, -1); if(index > 0) { setGravity(index); } } finally { /*至此属性绑定成功*/ a.recycle(); } } /** * {@inheritDoc} */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); int sizeWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); int sizeHeight = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); int width = 0; int height = getPaddingTop() + getPaddingBottom(); int lineWidth = 0; int lineHeight = 0; int childCount = getChildCount(); for(int i = 0; i < childCount; i++) { View child = getChildAt(i); boolean lastChild = i == childCount - 1; if(child.getVisibility() == View.GONE) { if(lastChild) { width = Math.max(width, lineWidth); height += lineHeight; } continue; } measureChildWithMargins(child, widthMeasureSpec, lineWidth, heightMeasureSpec, height); LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childWidthMode = MeasureSpec.AT_MOST; int childWidthSize = sizeWidth; int childHeightMode = MeasureSpec.AT_MOST; int childHeightSize = sizeHeight; if(lp.width == LayoutParams.MATCH_PARENT) { childWidthMode = MeasureSpec.EXACTLY ; childWidthSize -= lp.leftMargin + lp.rightMargin; } else if(lp.width >= 0) { childWidthMode = MeasureSpec.EXACTLY; childWidthSize = lp.width; } if(lp.height >= 0) { childHeightMode = MeasureSpec.EXACTLY; childHeightSize = lp.height; } else if (modeHeight == MeasureSpec.UNSPECIFIED) { childHeightMode = MeasureSpec.UNSPECIFIED; childHeightSize = 0; } child.measure( MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode), MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode) ); int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; if(lineWidth + childWidth > sizeWidth) { width = Math.max(width, lineWidth); lineWidth = childWidth; height += lineHeight; lineHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; } else { lineWidth += childWidth; lineHeight = Math.max(lineHeight, child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin); } if(lastChild) { width = Math.max(width, lineWidth); height += lineHeight; } } width += getPaddingLeft() + getPaddingRight(); setMeasuredDimension( (modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height); } /** * {@inheritDoc} */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { mLines.clear(); mLineHeights.clear(); mLineMargins.clear(); int width = getWidth(); int height = getHeight(); int linesSum = getPaddingTop(); int lineWidth = 0; int lineHeight = 0; List<View> lineViews = new ArrayList<View>(); float horizontalGravityFactor; switch ((mGravity & Gravity.HORIZONTAL_GRAVITY_MASK)) { case Gravity.LEFT: default: horizontalGravityFactor = 0; break; case Gravity.CENTER_HORIZONTAL: horizontalGravityFactor = .5f; break; case Gravity.RIGHT: horizontalGravityFactor = 1; break; } for(int i = 0; i < getChildCount(); i++) { View child = getChildAt(i); if(child.getVisibility() == View.GONE) { continue; } LayoutParams lp = (LayoutParams) child.getLayoutParams(); int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childHeight = child.getMeasuredHeight() + lp.bottomMargin + lp.topMargin; if(lineWidth + childWidth > width) { mLineHeights.add(lineHeight); mLines.add(lineViews); mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft()); linesSum += lineHeight; lineHeight = 0; lineWidth = 0; lineViews = new ArrayList<View>(); } lineWidth += childWidth; lineHeight = Math.max(lineHeight, childHeight); lineViews.add(child); } mLineHeights.add(lineHeight); mLines.add(lineViews); mLineMargins.add((int) ((width - lineWidth) * horizontalGravityFactor) + getPaddingLeft()); linesSum += lineHeight; int verticalGravityMargin = 0; switch ((mGravity & Gravity.VERTICAL_GRAVITY_MASK) ) { case Gravity.TOP: default: break; case Gravity.CENTER_VERTICAL: verticalGravityMargin = (height - linesSum) / 2; break; case Gravity.BOTTOM: verticalGravityMargin = height - linesSum; break; } int numLines = mLines.size(); int left; int top = getPaddingTop(); for(int i = 0; i < numLines; i++) { lineHeight = mLineHeights.get(i); lineViews = mLines.get(i); left = mLineMargins.get(i); int children = lineViews.size(); for(int j = 0; j < children; j++) { View child = lineViews.get(j); if(child.getVisibility() == View.GONE) { continue; } LayoutParams lp = (LayoutParams) child.getLayoutParams(); // if height is match_parent we need to remeasure child to line height if(lp.height == LayoutParams.MATCH_PARENT) { int childWidthMode = MeasureSpec.AT_MOST; int childWidthSize = lineWidth; if(lp.width == LayoutParams.MATCH_PARENT) { childWidthMode = MeasureSpec.EXACTLY; } else if(lp.width >= 0) { childWidthMode = MeasureSpec.EXACTLY; childWidthSize = lp.width; } child.measure( MeasureSpec.makeMeasureSpec(childWidthSize, childWidthMode), MeasureSpec.makeMeasureSpec(lineHeight - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY) ); } int childWidth = child.getMeasuredWidth(); int childHeight = child.getMeasuredHeight(); int gravityMargin = 0; if(Gravity.isVertical(lp.gravity)) { switch (lp.gravity) { case Gravity.TOP: default: break; case Gravity.CENTER_VERTICAL: case Gravity.CENTER: gravityMargin = (lineHeight - childHeight - lp.topMargin - lp.bottomMargin) / 2 ; break; case Gravity.BOTTOM: gravityMargin = lineHeight - childHeight - lp.topMargin - lp.bottomMargin; break; } } child.layout(left + lp.leftMargin, top + lp.topMargin + gravityMargin + verticalGravityMargin, left + childWidth + lp.leftMargin, top + childHeight + lp.topMargin + gravityMargin + verticalGravityMargin); left += childWidth + lp.leftMargin + lp.rightMargin; } top += lineHeight; } } @Override protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) { return new LayoutParams(p); } /** * {@inheritDoc} */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new LayoutParams(getContext(), attrs); } /** * {@inheritDoc} */ @Override protected LayoutParams generateDefaultLayoutParams() { return new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); } @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) public void setGravity(int gravity) { if(mGravity != gravity) { if((gravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK) == 0) { gravity |= isIcs() ? Gravity.START : Gravity.LEFT; } if((gravity & Gravity.VERTICAL_GRAVITY_MASK) == 0) { gravity |= Gravity.TOP; } mGravity = gravity; requestLayout(); } } public int getGravity() { return mGravity; } /** * @return <code>true</code> if device is running ICS or grater version of Android. */ private static boolean isIcs() { return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH; } public static class LayoutParams extends MarginLayoutParams { public int gravity = -1; public LayoutParams(Context c, AttributeSet attrs) { super(c, attrs); TypedArray a = c.obtainStyledAttributes(attrs, R.styleable.FlowLayout_Layout); try { gravity = a.getInt(R.styleable.FlowLayout_Layout_android_layout_gravity, -1); } finally { a.recycle(); } } public LayoutParams(int width, int height) { super(width, height); } public LayoutParams(ViewGroup.LayoutParams source) { super(source); } } }接下来就是在attrs.xml中加入相应的属性代码:
<declare-styleable name="FlowLayout"> <attr name="android:gravity" /> </declare-styleable> <declare-styleable name="FlowLayout_Layout"> <attr name="android:layout_gravity" /> </declare-styleable>现在就可以用到你的项目中了:
<com.wanglai.widget.FlowLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/save_signature_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@drawable/baidi" android:gravity="start|top" > <LinearLayout style="@style/label_style" android:background="@drawable/text_shape_yellow" android:orientation="horizontal" > <TextView style="@style/label_text_style" android:text="这是标签" android:textColor="@color/listselect" /> <TextView style="@style/label_text_style" android:text="5" android:textColor="@color/listselect" /> </LinearLayout> <!-- 这里可以加入更多的子元素 --> </com.wanglai.widget.FlowLayout>当然,你也可以在java代码中动态添加子元素:
for(int k = 0;k<phonesUserDtos.size();k++){ PhonesUserDto pDto = phonesUserDtos.get(k); //初始化子布局 View view = LayoutInflater.from(this).inflate(R.layout.wishtop_item, null); FlowLayout.LayoutParams params = new FlowLayout.LayoutParams(150, 170); view.setLayoutParams(params); params.topMargin = 10; view.setPadding(14, 0, 14, 0); RoundImageView riView = (RoundImageView) view.findViewById(R.id.wishtop_headImage); TextView tView = (TextView) view.findViewById(R.id.wishtop_tv_price); riView.setVisibility(View.VISIBLE); tView.setVisibility(View.VISIBLE); String wishTopHead =pDto.getHeadImage(); if (wishTopHead != null && !"".equals(wishTopHead)) { bitmapUtils.configDefaultLoadingImage(R.drawable.touxiang1); bitmapUtils.configDefaultLoadFailedImage(R.drawable.touxiang1); bitmapUtils.display(riView, Constant.AUTO_IMAGE_PATH + wishTopHead); } tView.setText(pDto.getRealname() + ""); sb.append(",").append(pDto.getUsername()); square_save_img_layout_wai.addView(view,0); }ok!是不是很简单呢。自己也是正在学习中,如果有什么不对的地方,欢迎指正
转载请注明出处
相关文章推荐
- Android轻松实现流式布局之FlowLayout
- 解决:Android中常见的热门标签的流式布局flowlayout不能wrap_content
- Android 流式布局FlowLayout 实现关键字标签
- Android自定义流式布局-FlowLayout
- Android自定义流式布局-FlowLayout
- <android>自己写一个流式布局吧(FlowLayout)
- 100行Android代码自定义一个流式布局-FlowLayout
- Android开发流式布局FlowLayout
- Android自定义控件--流式布局(FlowLayout)
- 100行Android代码自定义一个流式布局-FlowLayout
- Android自定义控件--流式布局(FlowLayout)--自动适配
- android自定义view实现流式布局(FlowLayout)和热门标签
- Android FlowLayout 流式布局
- android 实现流式布局FlowLayout
- Android 流式布局实现方法
- Android 自动换行布局 FlowLayout
- Android中常见的热门标签的流式布局的实现
- Android笔记:热门标签,流式布局
- Java图形化界面设计——布局管理器之FlowLayout(流式布局)
- Android流式布局FlowLayout的实现,Android布局的内部机制onMeasure、onLayout