My Application.rar Android 实现FlowLayout流式布局(热门标签),并且封装Adapter来通知更新FlowLayout。详细介绍可以查看我的博客:https://blog.csdn.net/wjr1949/article/details/70242570 先上效果图: 接着看代码实现: 查看上述代码得知:在构造函数中初始化一些必要的对象,这个后面再讲。 然后在 onMeasure(int widthMeasureSpec, int heightMeasureSpec) 函数中利用 MeasureSpec 获取Xml中设置的数值模式,进行测量并根据 MeasureSpec 的数值模式决定使用测量数值还是计算数值。 测量完成后重写 onLayout(boolean changed, int l, int t, int r, int b) 函数,布局子 View。 重写 generateLayoutParams(AttributeSet attrs) 函数。 关于 generateLayoutParams(AttributeSet attrs) 有不了解的请看我另一篇博客:generateLayoutParams() 方法的作用 前面说了,在构造函数中初始化一些必要的对象: 这两个是用来通知 FlowLayout 控件数据更新相关的对象。 FlowLayout Adapter封装: FlowLayout 讲到这里就完结了,如果对你有帮助,那就帮我点个赞吧。
public class FlowLayout extends ViewGroup { protected DataSetObserver mDataSetObserver; private FlowBaseAdapter mAdapter; /** * 所有的子view按行存储 */ private final List<List<View>> mAllChildViews; /** * 所有行高 */ private final List<Integer> mLineHeights; public FlowLayout(Context context) { this(context, null); } public FlowLayout(Context context, AttributeSet attrs) { this(context, attrs, 0); } public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mAllChildViews = new ArrayList<>(); mLineHeights = new ArrayList<>(); mDataSetObserver = new DataSetObserver() { @Override public void onChanged() { resetLayout(); } }; } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 获取XML设置的大小和测量模式 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); if (modeWidth == MeasureSpec.AT_MOST) { throw new RuntimeException("FlowLayout: layout_width must not be set to wrap_content !!!"); } int height = getPaddingTop() + getPaddingBottom(); // 行宽 int lineWidth = 0; // 行高 int lineHeight = 0; int childCount = getChildCount(); mAllChildViews.clear(); mLineHeights.clear(); List<View> lineViews = new ArrayList<>(); for (int i = 0; i < childCount; i++) { View childView = getChildAt(i); measureChild(childView, widthMeasureSpec, heightMeasureSpec); MarginLayoutParams lp = (MarginLayoutParams) childView .getLayoutParams(); int childLineWidth = childView.getMeasuredWidth() + lp.leftMargin + lp.rightMargin; int childLineHeight = childView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin; // 考虑padding if (childLineWidth + lineWidth > (widthSize - getPaddingRight() - getPaddingLeft())) { // 换行 height += lineHeight; lineWidth = childLineWidth; // 添加子View到集合 mAllChildViews.add(lineViews); mLineHeights.add(lineHeight); lineViews = new ArrayList<View>(); lineViews.add(childView); } else { // 不换行 lineHeight = Math.max(childLineHeight, lineHeight); lineWidth += childLineWidth; lineViews.add(childView); } //添加最后一行 if (i == childCount - 1) { height += lineHeight; mLineHeights.add(lineHeight); mAllChildViews.add(lineViews); } } setMeasuredDimension(widthSize, modeHeight == MeasureSpec.AT_MOST ? height : heightSize); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 设置子View的位置 int left = getPaddingLeft(); int top = getPaddingTop(); // 行数 int lineNumber = mAllChildViews.size(); for (int i = 0; i < lineNumber; i++) { List<View> lineViews = mAllChildViews.get(i); int lineHeight = mLineHeights.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); 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(); child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin; } left = getPaddingLeft(); top += lineHeight; } } /** * 重写generateLayoutParams() * * @param attrs attrs * @return MarginLayoutParams */ @Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); } public void setAdapter(FlowBaseAdapter adapter) { if (mAdapter != null && mDataSetObserver != null) { mAdapter.unregisterDataSetObserver(mDataSetObserver); mAdapter = null; } if (adapter == null) { throw new NullPointerException("adapter is null"); } this.mAdapter = adapter; mAdapter.registerDataSetObserver(mDataSetObserver); resetLayout(); } /** * 重新Layout子View */ protected final void resetLayout() { this.removeAllViews(); int counts = mAdapter.getCounts(); mAdapter.addViewToList(this); ArrayList<View> views = mAdapter.getViewList(); for (int i = 0; i < counts; i++) { this.addView(views.get(i)); } } }
@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 获取XML设置的大小和测量模式 int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); int modeWidth = MeasureSpec.getMode(widthMeasureSpec); int modeHeight = MeasureSpec.getMode(heightMeasureSpec); //省略部分代码 setMeasuredDimension(widthSize, modeHeight == MeasureSpec.AT_MOST ? height : heightSize); }
@Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 设置子View的位置 int left = getPaddingLeft(); int top = getPaddingTop(); // 行数 int lineNumber = mAllChildViews.size(); for (int i = 0; i < lineNumber; i++) { List<View> lineViews = mAllChildViews.get(i); int lineHeight = mLineHeights.get(i); for (int j = 0; j < lineViews.size(); j++) { View child = lineViews.get(j); 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(); child.layout(lc, tc, rc, bc); left += child.getMeasuredWidth() + lp.rightMargin + lp.leftMargin; } left = getPaddingLeft(); top += lineHeight; } }
那么 FlowLayout 中子View 的 MarginLayoutParams 是如何获取的呢?
@Override public LayoutParams generateLayoutParams(AttributeSet attrs) { return new MarginLayoutParams(getContext(), attrs); }
protected DataSetObserver mDataSetObserver; private FlowBaseAdapter mAdapter;
public abstract class CommonFlowAdapter<T> extends FlowBaseAdapter { private List<T> mDatas; private int mLayoutId; private Context mContext; public CommonFlowAdapter(Context context, List<T> datas, int layoutId) { this.mContext = context; this.mDatas = datas; this.mLayoutId = layoutId; } @Override public int getCounts() { return mDatas.size(); } @Override public View getView(int position, ViewGroup parent) { FlowHolder holder = new FlowHolder(mContext, parent, mLayoutId); convert(holder, mDatas.get(position), position); return holder.getConvertView(); } public abstract void convert(FlowHolder holder, T item, int position); public class FlowHolder { private SparseArray<View> mViews; private View mConvertView; public FlowHolder(Context context, ViewGroup parent, int layoutId) { this.mViews = new SparseArray<View>(); mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false); } public FlowHolder setText(int viewId, CharSequence text) { TextView tv = getView(viewId); tv.setText(text); return this; } public <T extends View> T getView(int viewId) { View view = mViews.get(viewId); if (view == null) { view = mConvertView.findViewById(viewId); mViews.put(viewId, view); } return (T) view; } /** * 设置点击事件 * * @return */ public FlowHolder setOnClickListener(int viewId, OnClickListener clickListener) { getView(viewId).setOnClickListener(clickListener); return this; } /** * 设置条目的点击事件 * * @return */ public FlowHolder setItemClick(OnClickListener clickListener) { mConvertView.setOnClickListener(clickListener); return this; } public View getConvertView() { return mConvertView; } } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算