自定义控件:流式布局

来源:互联网 发布:张艺谋奥运会知乎 编辑:程序博客网 时间: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
原创粉丝点击