自定义控件-存储搜索历史记录

目录

1.效果

2.分析

1)attr属性提取

2)自定义类代码

3)添加控件至viewGroup


1.效果

有搜索框的地方经常可以看到这样的自定义控件,来保存搜索历史。

https://img-blog.csdnimg.cn/20190107111657331.png

2.分析

1)attr属性提取

自定义容器Viewgroup,通过容器的addView,将历史搜索记录的textview传入,容器通过layout,决定textview的摆放位置。除了需要在自定义Viewgroup中处理子控件的与Viewgroup的padding,以及处理子控件距离Viewgroup的margin,还需要处理子控件与子控件之间的间距,为了易维护,可以将其设置为自定义属性

<declare-styleable name="TagsLayout">
        <attr name="tagVerticalSpace" format="dimension" />
        <attr name="tagHorizontalSpace" format="dimension" />
</declare-styleable>

2)自定义类代码

public class RecoderViewGroup extends ViewGroup {

    private int childHorizontalSpace;
    private int childVerticalSpace;

    public RecoderViewGroup(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray attrArray = context.obtainStyledAttributes(attrs, R.styleable.TagsLayout);
        if (attrArray != null) {
            childHorizontalSpace = attrArray.getDimensionPixelSize(R.styleable.TagsLayout_tagHorizontalSpace, 0);
            childVerticalSpace = attrArray.getDimensionPixelSize(R.styleable.TagsLayout_tagVerticalSpace, 0);
            //回收
            attrArray.recycle();
        }
    }

    //这个方法主要是用于父容器添加子View时调用,用于生成和此容器类型相匹配的布局参数类。
    @Override
    protected LayoutParams generateDefaultLayoutParams() {
        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
    }

    //设置view的测量模式和大小
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        // 获得测量模式和大小
        int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
        int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
        int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
        int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

        int width = 0;
        int height = 0;//容器的总体高度

        int lineWidth = 0;//记录每一行的宽度,width不断取最大宽度
        int lineHeight = 0;//每一行的高度,会累加至height

        //额外值获取
        int count = getChildCount();
        int left = getPaddingLeft();
        int right = getPaddingRight();
        int top = getPaddingTop();

        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            // 测量child
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            // child宽度+自定义间隔=实际占宽
            int childWidth = child.getMeasuredWidth() + childHorizontalSpace;
            // child高度+自定义间隔=实际占高(还要考虑child自身设置margin影响)
            int childHeight = child.getMeasuredHeight() + childVerticalSpace;
            // child实际宽高+左右margin
            LayoutParams lp = child.getLayoutParams();
            if (lp != null && lp instanceof MarginLayoutParams) {
                MarginLayoutParams params = (MarginLayoutParams) lp;
                childWidth += params.leftMargin + params.rightMargin;
                childHeight += params.topMargin + params.bottomMargin;
            }
            //当前行宽+child宽小于容器宽
            if (lineWidth + childWidth <= sizeWidth - left - right) {
                //将位置信息绑定到child的tag上
                child.setTag(new Location(lineWidth + left, top + height,
                        lineWidth + childWidth + left - childHorizontalSpace,
                        height + childHeight + top - childVerticalSpace));
                lineWidth += childWidth;
                lineHeight = Math.max(lineHeight, childHeight);
            }
            //加入当前child,如果超出最大宽度,将没加入前的宽度给width,类加height 然后开启新行
            else {
                lineWidth = childWidth; // 记录新行的宽度
                width = Math.max(lineWidth, childWidth); // 取最大的
                height += lineHeight;//总体高度叠加
                lineHeight = childHeight;// 记录新行的高度
                child.setTag(new Location(left, top + height,
                        childWidth + left - childHorizontalSpace, 
                        height + childHeight + top - childVerticalSpace));
            }
        }
        width = Math.max(width, lineWidth) + getPaddingLeft() + getPaddingRight();
        sizeHeight += getPaddingTop() + getPaddingBottom();
        height += lineHeight + getPaddingTop() + getPaddingBottom();
//EXACTLY模式用自身测量值  否则将自己的测量值作为最终值
        setMeasuredDimension(
(modeWidth == MeasureSpec.EXACTLY) ? sizeWidth : width, 
(modeHeight == MeasureSpec.EXACTLY) ? sizeHeight : height);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int count = getChildCount();
        for (int i = 0; i < count; i++) {
            View child = getChildAt(i);
            if (child.getVisibility() == GONE)
                continue;
            Location location = (Location) child.getTag();
            child.layout(location.left, location.top, location.right, location.bottom);
        }
    }

    //记录位置
    public class Location {
        public Location(int left, int top, int right, int bottom) {
            this.left = left;
            this.top = top;
            this.right = right;
            this.bottom = bottom;
        }
        public int left;
        public int top;
        public int right;
        public int bottom;
    }
}

3)添加控件至viewGroup

            final TextView textView = new TextView(SearchActivity.this);
            textView.setText(list.get(i));
            textView.setMaxLines(1);
            textView.setGravity(Gravity.CENTER);
            textView.setPadding(DensityUtil.dip2px(AppUtils.getAppContext(), 10),
                    DensityUtil.dip2px(AppUtils.getAppContext(), 2),
                    DensityUtil.dip2px(AppUtils.getAppContext(), 10),
                    DensityUtil.dip2px(AppUtils.getAppContext(), 2));
            textView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 13);
            textView.setEllipsize(TextUtils.TruncateAt.END);
            textView.setTextColor(getResources().getColor(R.color.tx_color_333333));
            textView.setBackgroundResource(R.drawable.bt_xml_15radiu_brownsolid);
            recoderVg.addView(textView, lp);

猜你喜欢

转载自blog.csdn.net/qq_37321098/article/details/88315411