一个可以自适应换行的标签列表控件

在我刚学Android的时候,看到b站的手机端app里,在显示搜索热词的时候有这样一个效果:


                                                 

我当时觉得很神奇,直到后来某一天我突然想明白是怎么回事了。


这次就带来这样一个控件:可以自定义添加标签,并且新添加的标签可以根据其长度,如果当前行放不下的话自动换到下一行。


首先说一下实现思路:我们可以把整个东西看成是一个纵向排布的LinearLayout,里面的每一行内容就是一个横向排布的子

LinearLayout里装若干个TextView,所谓的”自动换行“事实上就是判断新增加的TextView在放入后是否会超出其右边界,如

超出则新建一个横向排布的子LinearLayout,即新的一行,把TextView放入其中。现在的问题就变成有没有办法知道一个已知内

容的TextView的宽度?当然有办法,Paint类下的measureText方法提供了这个功能。


原理讲完,下面上控件本体:

SelfAdaptionColunmLayout.java:

public class SelfAdaptionColumnLayout extends LinearLayout {
    // 图标位于标签左边
    public static final int ICON_LEFT = 0x001;

    // 图标位于标签右边
    public static final int ICON_RIGHT = 0x002;


    private static final String KEY_TEXTVIEW = "KAY_TEXTVIEW";
    private static final String KEY_TEXTITEM = "KEY_TEXTITEM";

    private Context context;
    private ArrayList<HashMap> list;

    private int layoutWidth;

    // 行间距
    private int lineMargin = 10;

    // 列间距,即同一行相邻标签之间的距离
    private int columnMargin = 10;

    // 默认标签文字颜色
    private int defaultColor = Color.parseColor("#000000");

    // 默认标签文字大小
    private int defaultSize = 16;

    // 标签内的图标位置
    private int iconGravity = ICON_LEFT;

    // 标签内的图标距离文字的距离
    private int iconPadding = 5;

    private int currentLength = 0;

    // 标签点击回调
    private OnItemClickListener listener;

    public SelfAdaptionColumnLayout(Context context) {
        this(context, null);
    }

    public SelfAdaptionColumnLayout(Context context, AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public SelfAdaptionColumnLayout(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    /**
     * 初始化方法
     *
     * @param context
     */
    private void init(Context context) {
        this.context = context;
        list = new ArrayList<>();
        setOrientation(VERTICAL);
        setGravity(Gravity.LEFT);
        getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                getViewTreeObserver().removeGlobalOnLayoutListener(this);
                layoutWidth = getWidth();
                notifyDataSetChanged();
            }
        });
    }

    @Override
    protected void onFinishInflate() {
        super.onFinishInflate();
        if (getChildCount() != 0) {
            throw new RuntimeException("layout should not have any child");
        }
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);
        layoutWidth = getMeasuredWidth();
    }

    /**
     * 绘制标签
     *
     * @param position
     * @param textview
     * @param item
     */
    private void drawText(final int position, TextView textview, TextItem item) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setTextSize(item.getTextSize() != 0 ? item.getTextSize() : defaultSize);
        if (item.getIcon() != null && item.isShowIcon()) {
            item.getIcon().setBounds(0, 0, dp2px(item.getIconSize()), dp2px(item.getIconSize()));
        }
        if (getChildCount() == 0) {
            LinearLayout parent = new LinearLayout(context);
            parent.setGravity(Gravity.CENTER_VERTICAL);
            parent.setOrientation(HORIZONTAL);
            textview.setText(item.getText());
            textview.setGravity(Gravity.CENTER_VERTICAL);
            textview.setSingleLine(true);
            textview.setTextSize(item.getTextSize() != 0 ? item.getTextSize() : defaultSize);
            textview.setTextColor(item.getTextColor() != 0 ? item.getTextColor() : defaultColor);
            textview.setPadding(dp2px(item.getTextPaddingLeftRight()), dp2px(item.getTextPaddingTopBottom()), dp2px(item.getTextPaddingLeftRight()), dp2px(item.getTextPaddingTopBottom()));
            textview.setCompoundDrawables(item.getIcon() != null && item.isShowIcon() && iconGravity == ICON_LEFT ? item.getIcon() : null, null,
                    item.getIcon() != null && item.isShowIcon() && iconGravity == ICON_RIGHT ? item.getIcon() : null, null);
            textview.setCompoundDrawablePadding(dp2px(iconPadding));
            textview.setBackgroundDrawable(item.getTextBackground());
            textview.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (listener != null) {
                        listener.onItemClick(position, ((TextItem) list.get(position).get(KEY_TEXTITEM)).getText());
                    }
                }
            });
            if (textview.getParent() != null) {
                ((LinearLayout) textview.getParent()).removeView(textview);
            }
            parent.addView(textview, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            addView(parent, new LinearLayout.LayoutParams(ViewGroup.Lay
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值