美文网首页
Android - 实现流式标签

Android - 实现流式标签

作者: 穿越平行宇宙 | 来源:发表于2019-07-07 16:30 被阅读0次
    流式标签.gif

    1. 自定义View 实现该效果

    Flowlayout.java

    public class Flowlayout extends ViewGroup {
        private List<String> mData;
        private Context mContext;
        //每一行view
        protected List<List<View>> mAllViews = new ArrayList<List<View>>();
        protected List<Integer> mLineHeight = new ArrayList<Integer>();
        protected List<Integer> mLineWidth = new ArrayList<Integer>();
        private List<View> mLineViews = new ArrayList<>();
        private int mGravity = -1;
        private static final int LEFT = -1;
        private static final int CENTER = 0;
        private static final int RIGHT = 1;
    
        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);
            mContext = context;
        }
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
            int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
            int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
            int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
            //每行的宽高
            int lineWidth = 0;
            int lineHeight = 0;
            //测量子view后计算出的自身的宽高
            int width = 0;
            int height = 0;
    
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                //测量该子view
                measureChild(child, widthMeasureSpec, heightMeasureSpec);
                MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
                //获取子view宽高
                int childWidth = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
                int childHeight = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
                if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight()) {
                    //已经超出viewgroup宽度了,换行
                    width = Math.max(width, lineWidth);
                    lineWidth = childWidth;
                    lineHeight = childHeight;
                    //换行了,要加上高度
                    height += childHeight;
                } else {
                    //还未超出viewgroup宽度
                    lineWidth += childWidth;
                    //实时计算高度
                    if (childHeight > lineHeight) {
                        //如果同一行出现了更高的view,则重新计算高度
                        height = height - lineHeight;
                        lineHeight = childHeight;
                        height += lineHeight;
                    }
                }
            }
            //测量完后报告最终计算的宽高
            setMeasuredDimension(
                    modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),
                    modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()//
            );
        }
    
        @Override
        protected void onLayout(boolean changed, int l, int t, int r, int b) {
            mAllViews.clear();
            mLineHeight.clear();
            mLineWidth.clear();
            mLineViews.clear();
    
            int lineWidth = 0;
            int lineHeight = 0;
    
            for (int i = 0; i < getChildCount(); i++) {
                View child = getChildAt(i);
                if (child.getVisibility() == View.GONE) continue;
                MarginLayoutParams layoutParams = (MarginLayoutParams) child.getLayoutParams();
                int childWidth = child.getMeasuredWidth() + layoutParams.leftMargin + layoutParams.rightMargin;
                int childHeight = child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;;
                if (childWidth + lineWidth > getWidth() - getPaddingLeft() - getPaddingRight()) {
                    //换行
                    mLineHeight.add(lineHeight);
                    mLineWidth.add(lineWidth);
                    mAllViews.add(mLineViews);
                    //重置line相关参数
                    lineWidth = 0;
                    lineHeight = childHeight;
                    mLineViews = new ArrayList<>();
                }
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
                mLineViews.add(child);
            }
            mLineHeight.add(lineHeight);
            mLineWidth.add(lineWidth);
            mAllViews.add(mLineViews);
    
            int left = getPaddingLeft();
            int top = getPaddingTop();
    
            int lineNum = mAllViews.size();
    
            //为每一行的view排位
            for (int i = 0; i < lineNum; i++) {
                mLineViews = mAllViews.get(i);
                lineHeight = mLineHeight.get(i);
    
                //设置位置
                // set gravity
                int currentLineWidth = this.mLineWidth.get(i);
                switch (this.mGravity) {
                    case LEFT:
                        left = getPaddingLeft();
                        break;
                    case CENTER:
                        left = (getWidth() - currentLineWidth) / 2 + getPaddingLeft();
                        break;
                    case RIGHT:
                        left = getWidth() - currentLineWidth + getPaddingLeft();
                        break;
                }
    
                for (int j = 0; j < mLineViews.size(); j++) {
                    View child = mLineViews.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.leftMargin
                            + lp.rightMargin;
                }
                top += lineHeight;
            }
        }
    
        public void setData(List<String> data) {
            this.mData = data;
            if (data == null || data.isEmpty()) return;
            for (int i = 0; i < data.size(); i++) {
                TextView textView = new TextView(mContext);
                textView.setText(data.get(i));
                textView.setTextSize(20);
                LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
                layoutParams.setMargins(10, 10, 10, 10);
                textView.setLayoutParams(layoutParams);
                textView.setTextColor(Color.WHITE);
                textView.setPadding(10, 5,10, 5);
                textView.setBackgroundColor(getResources().getColor(R.color.blue));
                addView(textView);
            }
        }
    
        @Override
        public LayoutParams generateLayoutParams(AttributeSet attrs) {
            return new MarginLayoutParams(getContext(), attrs);
        }
    
        @Override
        protected LayoutParams generateDefaultLayoutParams() {
            return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
        }
    
        @Override
        protected LayoutParams generateLayoutParams(LayoutParams p) {
            return new MarginLayoutParams(p);
        }
    }
    

    2.UI页面布局

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:padding="20dp"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <com.example.administrator.flowlayoutdemo.Flowlayout
            android:id="@+id/flowlayout"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"/>
    
    </RelativeLayout>
    

    3.更新UI 界面

    MainActivity.java

    public class MainActivity extends AppCompatActivity {
    
        List<String> data = new ArrayList<>();
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            data.add("我要做远方的忠诚的儿子");
            data.add("和物质的");
            data.add("短暂情人");
            data.add("和所有以梦为马的");
            data.add("诗人一样");
            data.add("我");
            data.add("不得不和");
            data.add("烈士和小丑");
            data.add("走在同一道路上");
    
            Flowlayout flowLayout = (Flowlayout) findViewById(R.id.flowlayout);
            flowLayout.setData(data);
    
        }
    }
    

    源GitHub下载地址

    相关文章

      网友评论

          本文标题:Android - 实现流式标签

          本文链接:https://www.haomeiwen.com/subject/cazbhctx.html