Android开发之--标签选择


实现结果就是类似标签流

首先 自定义的类

public class FlowLayout extends ViewGroup {
    private static final String TAG = "FlowLayout";

    /**
     * 存储所有的View,按行记录
     */
    private List> mAllViews = new ArrayList>();

    /**
     * 记录每一行的最大高度
     */
    private List mLineHeight = new ArrayList();
    private Context mContext;

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


    public FlowLayout(Context context) {
        super(context);
        mContext = context;
    }

    /**
     * 负责设置子控件的测量模式和大小 根据所有子控件设置自己的宽和高
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获得它的父容器为它设置的测量模式和大小
        int sizeWidth = View.MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = View.MeasureSpec.getSize(heightMeasureSpec);
        int modeWidth = View.MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = View.MeasureSpec.getMode(heightMeasureSpec);

        Log.e(TAG, sizeWidth + "," + sizeHeight);

        // 如果是warp_content情况下,记录宽和高
        int width = 0;
        int height = 0;
        /**
         * 记录每一行的宽度,width不断取最大宽度
         */
        int lineWidth = 0;
        /**
         * 每一行的高度,累加至height
         */
        int lineHeight = 0;

        int cCount = getChildCount();

        // 遍历每个子元素
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            View childs = getChildAt(i);
            // 测量每一个child的宽和高
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            // 得到child的lp
            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child
                    .getLayoutParams();
            // 当前子空间实际占据的宽度
            int childWidth = child.getMeasuredWidth() + lp.leftMargin
                    + lp.rightMargin;
            // 当前子空间实际占据的高度
            int childHeight = child.getMeasuredHeight() + lp.topMargin
                    + lp.bottomMargin;
            /**
             * 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行
             */
            if (lineWidth + childWidth > sizeWidth) {
                width = Math.max(lineWidth, childWidth);// 取最大的
                lineWidth = childWidth; // 重新开启新行,开始记录
                // 叠加当前高度,
                height += lineHeight;
                // 开启记录下一行的高度
                lineHeight = childHeight;
            } else
            // 否则累加值lineWidth,lineHeight取最大高度
            {
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
            }
            // 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较
            if (i == cCount - 1) {
                width = Math.max(width, lineWidth);
                height += lineHeight;
            }

        }
        setMeasuredDimension((modeWidth == View.MeasureSpec.EXACTLY) ? sizeWidth
                : width, (modeHeight == View.MeasureSpec.EXACTLY) ? sizeHeight
                : height);

    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        mAllViews.clear();
        mLineHeight.clear();

        int width = getWidth();

        int lineWidth = 0;
        int lineHeight = 0;
        // 存储每一行所有的childView
        List lineViews = new ArrayList();
        int cCount = getChildCount();
        // 遍历所有的孩子
        for (int i = 0; i < cCount; i++) {
            View child = getChildAt(i);
            ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child
                    .getLayoutParams();
            int childWidth = child.getMeasuredWidth();
            int childHeight = child.getMeasuredHeight();

            // 如果已经需要换行
            if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width) {
                // 记录这一行所有的View以及最大高度
                mLineHeight.add(lineHeight);
                // 将当前行的childView保存,然后开启新的ArrayList保存下一行的childView
                mAllViews.add(lineViews);
                lineWidth = 0;// 重置行宽
                lineViews = new ArrayList();
            }
            /**
             * 如果不需要换行,则累加
             */
            lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
            lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
                    + lp.bottomMargin);
            lineViews.add(child);
        }
        // 记录最后一行
        mLineHeight.add(lineHeight);
        mAllViews.add(lineViews);

        int left = 0;
        int top = 0;
        // 得到总行数
        int lineNums = mAllViews.size();
        for (int i = 0; i < lineNums; i++) {
            // 每一行的所有的views
            lineViews = mAllViews.get(i);
            // 当前行的最大高度
            lineHeight = mLineHeight.get(i);

            Log.e(TAG, "第" + i + "行 :" + lineViews.size() + " , " + lineViews);
            Log.e(TAG, "第" + i + "行, :" + lineHeight);

            // 遍历当前行所有的View
            for (int j = 0; j < lineViews.size(); j++) {
                View child = lineViews.get(j);
                if (child.getVisibility() == View.GONE) {
                    continue;
                }
                ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams) child
                        .getLayoutParams();

                //计算childView的left,top,right,bottom
                int lc = left + lp.leftMargin;
                int tc = top + lp.topMargin;
                int rc = lc + child.getMeasuredWidth();
                int bc = tc + child.getMeasuredHeight();

                Log.e(TAG, child + " , l = " + lc + " , t = " + t + " , r ="
                        + rc + " , b = " + bc);

                child.layout(lc, tc, rc, bc);

                left += child.getMeasuredWidth() + lp.rightMargin
                        + lp.leftMargin;
            }
            left = 0;
            top += lineHeight;
        }

    }

    /**
     * 返回当前ViewGroup相关联的LayoutParams
     */
    @Override
    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new ViewGroup.MarginLayoutParams(getContext(), attrs);
    }

    public TextView addView(String tags, int bgcolor) {
        if (BussinessUtil.isValid(tags)) {
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            params.setMargins(0, 0, 20, 30);//左上右下
            TextView textView = new TextView(this.getContext());
            textView.setGravity(Gravity.CENTER);
            textView.setBackgroundResource(bgcolor);
            textView.setTextColor(getResources().getColor(R.color.search_flowlayout_textcolor));
            textView.setSelected(false);
            textView.setTextSize(13);
            textView.setPadding(50, 20, 50, 20);
            textView.setSingleLine();
            textView.setEllipsize(TextUtils.TruncateAt.valueOf("END"));
            textView.setText(tags);
            this.addView(textView, params);
            return textView;
        }
        return null;
    }

    public View addHitoryView(String tags, int bgcolor) {
        View view = null;
        if (!TextUtils.isEmpty(tags)) {
            LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
            params.setMargins(0, 0, 20, 30);//左上右下
            view = LayoutInflater.from(mContext).inflate(R.layout.item_custom_search_key, null);
            ((TextView) view.findViewById(R.id.tvSearchKey)).setText(tags);
            this.addView(view, params);
        }
        return view;
    }
}

其次是自定义控件使用的布局

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content">

            android:id="@+id/tvSearchKey"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@color/search_flowlayout_textcolor"
        android:text="护肤"
        android:background="@drawable/history_tag_bg_selector"
        android:paddingLeft="@dimen/margin_fifteen"
        android:paddingRight="@dimen/margin_fifteen"
        android:paddingTop="@dimen/margin_five"
        android:paddingBottom="@dimen/margin_five" />

            android:id="@+id/ivDelHotkey"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/icon_search_delete"
        android:layout_alignRight="@+id/tvSearchKey"
        android:visibility="gone"/>


然后 在需要的地方直接使用

    android:id="@+id/rlCaizhuangKeywordLayout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@color/white"
    android:paddingBottom="-5dp">

            android:id="@+id/flCaizhuangSearchTag"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_marginLeft="@dimen/margin_eight"
        android:layout_marginRight="@dimen/margin_eight"
        android:layout_marginTop="@dimen/margin_twenty" />

java代码中使用,和普通控件一样,首先 通过finfviewbyid 找到这个控件

然后,为他初始化数据,这里模拟创建了几个数据,然后通过for循环依次添加进去,并且可以为他设置点击时候的颜色变化

private void initKeyWordData() {
    caizhuangKeywords = new ArrayList<>();
    caizhuangKeywords.add("春");
    caizhuangKeywords.add("学院风");
    caizhuangKeywords.add("时尚");
    caizhuangKeywords.add("原宿style");
    caizhuangKeywords.add("清新");
    caizhuangKeywords.add("约会装");
    for (String caizhuangKeyword : caizhuangKeywords) {
        final TextView tvCaizhuangKeyword = flCaizhuangSearchTag.addView(caizhuangKeyword, R.drawable.caizhuang_keyword_tag_bg_selector);
        tvCaizhuangKeyword.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ToastUtil.showToast(tvCaizhuangKeyword.getText().toString() + "");
            }
        });
    }
}

其中的caizhuang_keyword_tag_bg_selector就是为标签设计的点击颜色改变的drawable 具体如下:

xml version="1.0" encoding="utf-8"?>
xmlns:android="http://schemas.android.com/apk/res/android">
    android:state_pressed="true">
        android:shape="rectangle">

            android:color="@color/basic_pink_color" />
            android:width="1px" android:color="@color/mess_notify_titlecolor" />

            android:radius="@dimen/margin_five" />
        
    
    android:state_pressed="false">
        android:shape="rectangle">
            android:color="@color/caizhuang_keyword_defaule_bgcolor" />
            android:width="1px" android:color="@color/login_line_color" />

            android:radius="@dimen/margin_five" />
        
    


需要注意的是,如果仅仅添加上了这个drawable,但是并未在java代码中为其添加点击事件,那么这个drawable的press选择器是不会起作用的,所以,只有添加了onClicklistener等点击事件,这个drawable才会出效果,这是本人开发过程时没有注意到的细节被困扰了一下,特整理出来提醒小伙伴们。


你可能感兴趣的:(Android)