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

本文介绍了一个在Android中实现自适应换行的标签列表控件,通过LinearLayout和TextView结合,判断新增标签是否超出边界来实现自动换行。控件包含添加标签的方法,并支持设置标签样式和监听标签点击事件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在我刚学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.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
            if (item.getIcon() != null && item.isShowIcon()) {
                currentLength = dp2px(iconPadding) + 2 * dp2px(item.getTextPaddingLeftRight()) + dp2px(paint.measureText(item.getText())) + dp2px(item.getIconSize());
            } else {
                currentLength = 2 * dp2px(item.getTextPaddingLeftRight()) + dp2px(paint.measureText(item.getText()));
            }
        } else {
            LinearLayout parent = (LinearLayout) getChildAt(getChildCount() - 1);
            boolean isNeedWrap;
            if (item.getIcon() != null && item.isShowIcon()) {
                isNeedWrap = currentLength + dp2px(columnMargin) + dp2px(iconPadding) + 2 * dp2px(item.getTextPaddingLeftRight())
                        + dp2px(paint.measureText(item.getText())) + dp2px(item.getIconSize()) + getPaddingRight() > layoutWidth;
            } else {
                isNeedWrap = currentLength + dp2px(columnMargin) + 2 * dp2px(item.getTextPaddingLeftRight())
                        + dp2px(paint.measureText(item.getText())) + getPaddingRight() > layoutWidth;
            }
            if (isNeedWrap) {
                parent = new LinearLayout(context);
                parent.setGravity(Gravity.CENTER_VERTICAL);
                parent.setOrientation(HORIZONTAL);
                textview.setText(item.getText());
                textview.setGravity(Gravity.CENTER);
                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.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
                ((LinearLayout.LayoutParams) parent.getLayoutParams()).setMargins(0, dp2px(lineMargin), 0, 0);
                if (item.getIcon() != null && item.isShowIcon()) {
                    currentLength = dp2px(iconPadding) + 2 * dp2px(item.getTextPaddingLeftRight()) + dp2px(paint.measureText(item.getText())) + dp2px(item.getIconSize());
                } else {
                    currentLength = 2 * dp2px(item.getTextPaddingLeftRight()) + dp2px(paint.measureText(item.getText()));
                }
            } else {
                textview.setText(item.getText());
                textview.setGravity(Gravity.CENTER);
                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));
                ((LinearLayout.LayoutParams) textview.getLayoutParams()).setMargins(dp2px(columnMargin), 0, 0, 0);
                if (item.getIcon() != null && item.isShowIcon()) {
                    currentLength += dp2px(columnMargin) + dp2px(iconPadding) + 2 * dp2px(item.getTextPaddingLeftRight()) + dp2px(paint.measureText(item.getText())) + dp2px(item.getIconSize());
                } else {
                    currentLength += dp2px(columnMargin) + 2 * dp2px(item.getTextPaddingLeftRight()) + dp2px(paint.measureText(item.getText()));
                }
            }
        }
    }

    /**
     * 添加一个标签
     * 添加后必须调用notifyDataSetChanged()方法才会生效
     *
     * @param text 标签文字
     */
    public void addItem(@NonNull String text) {
        HashMap temp = new HashMap();
        temp.put(KEY_TEXTVIEW, new TextView(context));
        temp.put(KEY_TEXTITEM, new TextItem(text));
        list.add(temp);
    }

    /**
     * 添加一个标签
     * 添加后必须调用notifyDataSetChanged()方法才会生效
     *
     * @param text                 标签文字
     * @param textSize             标签文字大小,单位sp
     * @param textColor            标签文字颜色
     * @param textPaddingTopBottom 标签文字距离上下边的距离,单位dp
     * @param textPaddingLeftRight 标签文字距离左右边的距离,单位dp
     * @param textBackground       标签背景
     */
    public void addItem(@NonNull String text, int textSize, int textColor, int textPaddingTopBottom, int textPaddingLeftRight, Drawable textBackground) {
        HashMap temp = new HashMap();
        temp.put(KEY_TEXTVIEW, new TextView(context));
        temp.put(KEY_TEXTITEM, new TextItem(text, textSize, textColor, textPaddingTopBottom, textPaddingLeftRight, textBackground));
        list.add(temp);
    }

    /**
     * 添加一个标签
     * 添加后必须调用notifyDataSetChanged()方法才会生效
     *
     * @param icon                 标签图标
     * @param iconSize             标签图标大小,即正方形图标的边长,单位dp
     * @param isShowIcon           标签图标是否显示
     * @param text                 标签文字
     * @param textSize             标签文字大小,单位sp
     * @param textColor            标签文字颜色
     * @param textPaddingTopBottom 标签文字距离上下边的距离,单位dp
     * @param textPaddingLeftRight 标签文字距离左右边的距离,单位dp
     * @param textBackground       标签背景
     */
    public void addItem(Drawable icon, int iconSize, boolean isShowIcon, @NonNull String text, int textSize, int textColor, int textPaddingTopBottom, int textPaddingLeftRight, Drawable textBackground) {
        HashMap temp = new HashMap();
        temp.put(KEY_TEXTVIEW, new TextView(context));
        temp.put(KEY_TEXTITEM, new TextItem(icon, iconSize, isShowIcon, text, textSize, textColor, textPaddingTopBottom, textPaddingLeftRight, textBackground));
        list.add(temp);
    }

    /**
     * 删除指定指定标签
     * 删除后必须调用notifyDataSetChanged()方法才会生效
     *
     * @param position 标签坐标
     */
    public void removeItem(int position) {
        list.remove(position);
    }

    /**
     * 获取指定标签实体
     *
     * @param position 标签序号
     * @return 标签实体
     */
    public TextItem getItem(int position) {
        return (TextItem) list.get(position).get(KEY_TEXTITEM);
    }

    /**
     * 修改指定标签
     * 修改后必须调用notifyDataSetChanged()方法才会生效
     *
     * @param position 标签序号
     * @param item     标签实体
     */
    public void setItem(int position, TextItem item) {
        list.get(position).put(KEY_TEXTITEM, item);
    }

    /**
     * 清除所有标签
     * 清除后必须调用notifyDataSetChanged()方法才会生效
     */
    public void clearAllItem() {
        list.clear();
    }

    /**
     * 获取标签总数
     *
     * @return 标签总数
     */
    public int getItemCount() {
        return list.size();
    }

    /**
     * 设置行间距
     *
     * @param lineMargin 行间距,单位dp
     */
    public void setLineMargin(int lineMargin) {
        this.lineMargin = lineMargin;
    }

    /**
     * 设置列间距,即同一行相邻标签之间的距离
     *
     * @param columnMargin 列间距,单位dp
     */
    public void setColumnMargin(int columnMargin) {
        this.columnMargin = columnMargin;
    }

    /**
     * 设置默认标签文字颜色
     *
     * @param defaultColor,颜色值
     */
    public void setDefaultColor(int defaultColor) {
        this.defaultColor = defaultColor;
    }

    /**
     * 设置默认标签文字大小
     *
     * @param defaultSize,大小值,单位sp
     */
    public void setDefaultSize(int defaultSize) {
        this.defaultSize = defaultSize;
    }

    /**
     * 设置标签内的图标位置
     *
     * @param iconGravity 图标位置,可选项:ICON_LEFT、ICON_RIGHT
     */
    public void setIconGravity(int iconGravity) {
        this.iconGravity = iconGravity;
    }

    /**
     * 标签内图标距离文字的距离
     *
     * @param iconPadding 距离值,单位dp
     */
    public void setIconPadding(int iconPadding) {
        this.iconPadding = iconPadding;
    }

    /**
     * 更新视图
     * 在对标签增、删、改操作后必须调用此方法才会生效
     */
    public void notifyDataSetChanged() {
        if (layoutWidth != 0) {
            currentLength = 0;
            removeAllViews();
            for (int i = 0; i < list.size(); i++) {
                drawText(i, (TextView) list.get(i).get(KEY_TEXTVIEW), (TextItem) list.get(i).get(KEY_TEXTITEM));
            }
        }
    }

    /**
     * 标签实体
     */
    class TextItem {
        // 标签内图标
        private Drawable icon;

        // 标签内图标的大小,即正方形图标的边长,单位dp
        private int iconSize;

        // 标签内图标是否显示
        private boolean isShowIcon;

        // 标签文字
        private String text;

        // 标签文字大小,单位sp
        private int textSize;

        // 标签文字颜色
        private int textColor;

        // 标签文字距离上下边的距离,单位dp
        private int textPaddingTopBottom;

        // 标签文字距离左右边的距离,单位dp
        private int textPaddingLeftRight;

        // 标签背景
        private Drawable textBackground;

        public TextItem(@NonNull String text) {
            this.text = text;
        }

        public TextItem(@NonNull String text, int textSize, int textColor, int textPaddingTopBottom, int textPaddingLeftRight, Drawable textBackground) {
            this.text = text;
            this.textSize = textSize;
            this.textColor = textColor;
            this.textPaddingTopBottom = textPaddingTopBottom;
            this.textPaddingLeftRight = textPaddingLeftRight;
            this.textBackground = textBackground;
        }

        public TextItem(Drawable icon, int iconSize, boolean isShowIcon, @NonNull String text, int textSize, int textColor, int textPaddingTopBottom, int textPaddingLeftRight, Drawable textBackground) {
            this.icon = icon;
            this.iconSize = iconSize;
            this.text = text;
            this.isShowIcon = isShowIcon;
            this.textSize = textSize;
            this.textColor = textColor;
            this.textPaddingTopBottom = textPaddingTopBottom;
            this.textPaddingLeftRight = textPaddingLeftRight;
            this.textBackground = textBackground;
        }

        public Drawable getIcon() {
            return icon;
        }

        public void setIcon(Drawable icon) {
            this.icon = icon;
        }

        public int getIconSize() {
            return iconSize;
        }

        public void setIconSize(int iconSize) {
            this.iconSize = iconSize;
        }

        public String getText() {
            return text;
        }

        public void setText(String text) {
            this.text = text;
        }

        public boolean isShowIcon() {
            return isShowIcon;
        }

        public void setIsShowIcon(boolean isShowIcon) {
            this.isShowIcon = isShowIcon;
        }

        public int getTextSize() {
            return textSize;
        }

        public void setTextSize(int textSize) {
            this.textSize = textSize;
        }

        public int getTextColor() {
            return textColor;
        }

        public int getTextPaddingTopBottom() {
            return textPaddingTopBottom;
        }

        public void setTextPaddingTopBottom(int textPaddingTopBottom) {
            this.textPaddingTopBottom = textPaddingTopBottom;
        }

        public int getTextPaddingLeftRight() {
            return textPaddingLeftRight;
        }

        public void setTextPaddingLeftRight(int textPaddingLeftRight) {
            this.textPaddingLeftRight = textPaddingLeftRight;
        }

        public void setTextColor(int textColor) {
            this.textColor = textColor;
        }

        public Drawable getTextBackground() {
            return textBackground;
        }

        public void setTextBackground(Drawable textBackground) {
            this.textBackground = textBackground;
        }
    }

    private int sp2px(float spValue) {
        float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
        return (int) (spValue * fontScale + 0.5f);
    }

    private int dp2px(float dipValue) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    public interface OnItemClickListener {
        void onItemClick(int position, String text);
    }

    public void setOnItemClickListener(OnItemClickListener listener) {
        this.listener = listener;
    }
}

只有一个文件,复制进项目就能用了,上MainActivity.java和activity_main.xml:

MainActivity.java:

public class MainActivity extends Activity {
    private EditText editText;
    private Button button;
    private SelfAdaptionColumnLayout layout;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initData();
        initView();
    }

    private void initData() {

    }

    private void initView() {
        editText = (EditText) findViewById(R.id.edittext);
        button = (Button) findViewById(R.id.add_button);
        layout = (SelfAdaptionColumnLayout) findViewById(R.id.layout);

        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                layout.addItem(editText.getText().toString());
                layout.notifyDataSetChanged();
                editText.setText("");
            }
        });

    }
}

activity_main.xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <com.min.selfadaptioncolumnlayout.SelfAdaptionColumnLayout
        android:id="@+id/layout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_margin="10dp"
        android:layout_weight="1"
        android:orientation="vertical" />

    <EditText
        android:id="@+id/edittext"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp" />

    <Button
        android:id="@+id/add_button"
        android:layout_width="match_parent"
        android:layout_height="40dp"
        android:layout_margin="10dp"
        android:text="add" />

</LinearLayout>

代码很简单,唯一需要注意的是在执行完addItem方法添加一个标签后,一定要执行notifyDataSetChanged刷新一下,添加才

会生效,这就跟ListView里改动数据后需要执行adapter. notifyDataSetChanged()一样。


运行看一下效果:

                                                                 

这里说明一下,控件提供的添加标签方法addItem有三种调用方式,即:

public void addItem(@NonNull String text)

public void addItem(@NonNull String text, int textSize, int textColor, int textPaddingTopBottom, int textPaddingLeftRight, Drawable textBackground) 

public void addItem(Drawable icon, int iconSize, boolean isShowIcon, @NonNull String text, int textSize, int textColor, int textPaddingTopBottom, int textPaddingLeftRight, Drawable textBackground)

以上的例子只是调用了第一种也是最简单的一种,下面用第二种方法添加标签,先定义几个资源文件:

backgroud_up.xml:

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

    <corners android:radius="20dp" />

    <stroke
        android:width="1dp"
        android:color="#dddddd" />

    <solid android:color="#ffffff" />
</shape>

backgroud_down.xml:

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

    <corners android:radius="20dp" />

    <stroke
        android:width="1dp"
        android:color="#888888" />

    <solid android:color="#ffffff" />
</shape>
background_selector.xml:

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

    <item android:drawable="@drawable/backgroud_up" android:state_pressed="false"></item>
    <item android:drawable="@drawable/backgroud_down" android:state_pressed="true"></item>

</selector>

然后修改页面中按钮的点击事件:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        layout.addItem(editText.getText().toString(), 20, Color.parseColor("#333333"),
                5, 15, getResources().getDrawable(R.drawable.background_selector));
        layout.notifyDataSetChanged();
        editText.setText("");
    }
});

完成,看一下效果:

                                                                
      

第三种调用方法支持在标签左侧或右侧添加一个小图标,以下也做一个示范:


先添加一个图标:

hot.png:


然后继续修改按钮点击事件:

button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        if (layout.getItemCount() < 3) {
            layout.addItem(getResources().getDrawable(R.drawable.hot), 20, true, editText.getText().toString(),
                    20, Color.parseColor("#3F51B5"), 5, 15,                           getResources().getDrawable(R.drawable.background_selector));
        } else {
            layout.addItem(editText.getText().toString(), 16, Color.parseColor("#333333"),
                    3, 10, getResources().getDrawable(R.drawable.background_selector));
        }
        layout.notifyDataSetChanged();
        editText.setText("");
    }
});

再次运行:

                                                                 

如果需要监听标签的点击事件,只需要设置setOnItemClickListener即可,很简单,不再累述。控件提供的更多方法在源码里都

有注释,大家可以自己试一试。


最后附上源码地址:点击打开链接

 

这次的内容就到这里,我们下次再见。






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值