美文网首页工作生活
android 实现标签流,动态添加标签并获取

android 实现标签流,动态添加标签并获取

作者: 一个冬季 | 来源:发表于2019-06-30 15:45 被阅读0次
Screenrecorder-2019-07-08-21-38-09-988[00-00-00--00-00-13].gif
文章知识了解

你的自定义View是否真的支持Margin
setBackgroundResource,setBackgroundDrawable以及android:background

学习到的知识点

1、measureChild 减去了 ViewGroup的padding 保证child最大可用空间
2、measureChildWithMargins 减去了ViewGroup的padding和子View的margin 保证child最大可用空间
3、measureChild 后,子View.getMeasuredWidth 是包含子View的padding的
4、自定义VIewGroup中,通过循环遍历调用addView的方法,不会每次都调用onMeasure或onLayout
5、为了优化,父容器建议考虑使用FrameLayout或者Linlayout
6、onMeasure中第二次setMeasuredDimension的参数如果与第一次一致,将不触发onLayout
7、TextView需要设置默认的背景色,如果不设置获取的宽高将会是0,这一点可以通过getDefaulSize的源码知道
8、软键盘的弹出/收缩,也会重新调用onLayout、onmeasure
9、TextView使用setBackground会导致背景有些部分会显示不出来,所以需要使用setBackgroundResource,它是使用的是资源ID,setBackground()和setBackgroundDrawable()的使用是一样的

可以自定义哪些参数?

1、定义选中/未选中的背景色,文字选中/未选中的颜色
2、定义TextView padding 文字左右距离
3、定义文字的大小
4、定义TextView之间水平方向的距离
5、定义TextView之间竖直平方向的距离
6、TextView的高度
7、是否添加新增按钮
8、新增按钮宽度大小
9、可以回调新增的数据
10、按下Enter键可以拿到数据

使用方法
 public class MainActivity extends AppCompatActivity implements LabelLayoutView.OnInputValueListener{
    private String TAG =MainActivity.class.getSimpleName();
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final LabelLayoutView labelLayoutView = findViewById(R.id.lablayout);
        final  List<LabelModel> labelModelArrayList = new ArrayList<>();
        for (int i=0;i<10;i++){
            LabelModel model = new LabelModel();
            if (i % 2 == 0){
                model.setTextValue("sd");
            }else {
                model.setTextValue("一周热门话题");
            }
            labelModelArrayList.add(model);
        }
        labelLayoutView.setStringList(labelModelArrayList);
        labelLayoutView.setOnInputValueListener(this);
        findViewById(R.id.bt_main_cleanfocus).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                labelLayoutView.cleanEditFocus();
            }
        });
    }

    @Override
    public void onInoutItem(String value) {
        Log.i(TAG,value);
    }
}
<?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.example.gao.myapplication.LabelLayoutView
        android:id="@+id/lablayout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/bt_main_cleanfocus"
        android:text="失去焦点"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</LinearLayout>
全部代码展示

xml展示
rectanger_co50_solid_grayf7f7f7.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:radius="50dp"/>
    <solid
        android:color="@color/gray_F7F7F7" />

</shape>

rectanger_co50_solid_zie9e1f6.xml

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle">
    <corners
        android:radius="50dp"/>
    <solid
        android:color="@color/zi_E9E1F6" />

</shape>

attrs.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="LabelLayoutView">
        <!--定义选中的背景色,文字的颜色,文字默认的颜色,背景默认的颜色-->
        <attr name="tVViewDefuBackColor" format="reference"/>
        <attr name="tVViewDefuTextColor" format="reference"/>
        <attr name="tVViewClickBackColor" format="reference"/>
        <attr name="tVViewClickTextColor" format="reference"/>

        <!--定义TextView padding 文字左右距离-->
        <attr name="tViewPaddingLeft" format="dimension"/>
        <attr name="tVViewPaddingRight" format="dimension"/>

        <!--定义文字的大小-->
        <attr name="tVViewTextSize" format="dimension"></attr>

        <!--定义TextView之间水平方向的距离-->
        <attr name="tVHorizontalSpace" format="dimension"></attr>
        <!--定义TextView之间竖直平方向的距离-->
        <attr name="tVVerticalSpace" format="dimension"></attr>
        <!--TextView的高度-->
        <attr name="tVViewTextHeight" format="dimension"></attr>

   <!--可输入的宽度-->
        <attr name="edTextWidth" format="dimension"></attr>
        <!--可输入的最大长度-->
        <attr name="edTextMaxInputLength" format="integer"></attr>
        <!--是否由添加按钮-->
        <attr name="isNewAdd" format="boolean"></attr>
        <!--添加按的宽度-->
        <attr name="tvAddTextWidth" format="dimension"></attr>
    </declare-styleable>
</resources>

model类展示

public class LabelModel {
    private String textValue;
    private boolean isClick;

    public String getTextValue() {
        return textValue;
    }

    public void setTextValue(String textValue) {
        this.textValue = textValue;
    }

    public boolean isClick() {
        return isClick;
    }

    public void setClick(boolean click) {
        isClick = click;
    }
}

自定义标签流代码展示

/**
* @date: 2019/7/1 0001
* @author: gaoxiaoxiong
* @description:自定义标签流
**/
public class LabelLayoutView extends ViewGroup {
    private String TAG = LabelLayoutView.class.getSimpleName();
    private List<LabelModel> modelArrayList = new ArrayList<>();
    private List<TextView> textViewList = new ArrayList<>();
    private int tVHorizontalSpace = 10;//TextView之间的水平间距
    private int tVVerticalSpace = 20;//竖直方向的间距
    private int tViewPaddingLeft = 0;
    private int tVViewPaddingRight = 0;
    private int tVViewTextSize = 0;//文字大小
    private int tVViewTextHeight = 0;//TextView的高度

    private int tVViewClickTextColor;//文字点中的颜色
    private int tVViewDefuTextColor;//文字默认的颜色

    private int tVViewDefuBackColor;//默认的颜色
    private int tVViewClickBackColor;//点中,背景色的修改

    private int edTextMaxInputLength = 6;//最大输入个数
    private int edTextWidth = 0;//输入框的宽度
    private boolean isNewAdd = false;//是否要含有+号
    private int tvAddTextWidth = 0;//定义加号的长度

    private Context mContext;

    private OnInputValueListener onInputValueListener;

    public void setOnInputValueListener(OnInputValueListener onInputValueListener) {
        this.onInputValueListener = onInputValueListener;
    }

    public interface OnInputValueListener {
        void onInoutItem(String value);
    }


    //获取点击中的
    public List<LabelModel> getChoiceModelList() {
        List<LabelModel> list = new ArrayList<>();
        for (LabelModel model : modelArrayList) {
            if (model.isClick()) {
                list.add(model);
            }
        }
        return list;
    }

    /**
     * @date: 2019/7/1 0001
     * @author: gaoxiaoxiong
     * @description:获取所有的 TextView
     **/
    public List<TextView> getTextViewList() {
        return textViewList;
    }

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

    public LabelLayoutView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public LabelLayoutView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        this.mContext = context;
        TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.LabelLayoutView);
        //定义默认的颜色
        tVViewDefuBackColor = mTypedArray.getResourceId(R.styleable.LabelLayoutView_tVViewDefuBackColor, R.drawable.rectanger_co50_solid_grayf7f7f7);
        tVViewClickBackColor = mTypedArray.getResourceId(R.styleable.LabelLayoutView_tVViewClickBackColor, R.drawable.rectanger_co50_solid_zie9e1f6);

        tVHorizontalSpace = mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_tVHorizontalSpace, dip2px(14));
        tVVerticalSpace = mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_tVVerticalSpace, dip2px(12));

        //定义默认的文字颜色
        tVViewDefuTextColor = mTypedArray.getColor(R.styleable.LabelLayoutView_tVViewDefuTextColor, getResources().getColor(R.color.gray_A8A8A8));
        //定义选中后的文字颜色
        tVViewClickTextColor = mTypedArray.getColor(R.styleable.LabelLayoutView_tVViewDefuTextColor, getResources().getColor(R.color.zi_8C75B3));

        tViewPaddingLeft = mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_tViewPaddingLeft, dip2px(12));
        tVViewPaddingRight = mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_tVViewPaddingRight, dip2px(12));

        tVViewTextSize = mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_tVViewTextSize, 12);
        tVViewTextHeight = mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_tVViewTextHeight, dip2px(25));


        edTextWidth =mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_edTextWidth,dip2px(87)) ;
        edTextMaxInputLength =mTypedArray.getInt(R.styleable.LabelLayoutView_edTextMaxInputLength,6);
        isNewAdd = mTypedArray.getBoolean(R.styleable.LabelLayoutView_isNewAdd,false);
        tvAddTextWidth =mTypedArray.getDimensionPixelOffset(R.styleable.LabelLayoutView_edTextWidth,dip2px(87)) ;
        mTypedArray.recycle();
    }

    public void setStringList(List<LabelModel> list) {
        if (list.size() > 0) {
            removeAllViews();
            this.textViewList.clear();
            this.modelArrayList.clear();
            this.modelArrayList.addAll(list);
            for (int i = 0; i < list.size(); i++) {
                LabelModel model = list.get(i);
                TextView textView = createTextView(i, model.getTextValue());
                addView(textView);
            }
            if (isNewAdd) {
                addView(createAddTextView());
            }
        }
    }

    //创建TextView
    private TextView createTextView(int position, String string) {
        TextView textView = new TextView(mContext);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, tVViewTextHeight);
        textView.setLayoutParams(lp);
        textView.setPadding(tViewPaddingLeft, 0, tVViewPaddingRight, 0);
        textView.setText(string);
        textView.setTextColor(tVViewDefuTextColor);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, tVViewTextSize);
        textView.setGravity(Gravity.CENTER);
        textView.setBackgroundResource(R.drawable.rectanger_co50_solid_grayf7f7f7);//设置的是最底层的颜色
        textView.setTag(position);
        textView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                int i = (int) v.getTag();
                LabelModel model = modelArrayList.get(i);
                if (model.isClick()) {
                    model.setClick(false);
                    textViewList.get(i).setBackgroundResource(tVViewDefuBackColor);
                    textViewList.get(i).setTextColor(tVViewDefuTextColor);
                } else {
                    model.setClick(true);
                    textViewList.get(i).setBackgroundResource(tVViewClickBackColor);
                    textViewList.get(i).setTextColor(tVViewClickTextColor);
                }
            }
        });
        textViewList.add(textView);
        return textView;
    }

    //创建一个含有+号的TextView
    private TextView createAddTextView() {
        final TextView textView = new TextView(mContext);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(tvAddTextWidth, tVViewTextHeight);
        textView.setLayoutParams(lp);
        textView.setPadding(tViewPaddingLeft, 0, tVViewPaddingRight, 0);
        textView.setText("+");
        textView.setTextColor(tVViewDefuTextColor);
        textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, tVViewTextSize);
        textView.setGravity(Gravity.CENTER);
        textView.setBackgroundResource(R.drawable.rectanger_co50_solid_grayf7f7f7);//设置的是最底层的颜色
        textView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                createEditText(textView);
            }
        });
        textViewList.add(textView);
        return textView;
    }

    private EditText editText = null;
    //创建EditText
    private void createEditText(TextView textView) {
        this.removeView(textView);
        textViewList.remove(textView);
        editText = new EditText(mContext);
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(edTextWidth, tVViewTextHeight);
        editText.setLayoutParams(lp);
        editText.setHint("请输入");
        editText.setMaxLines(1);
        editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(edTextMaxInputLength)});
        editText.setPadding(tViewPaddingLeft, 0, tVViewPaddingRight, 0);
        editText.setTextColor(tVViewDefuTextColor);
        editText.setTextSize(TypedValue.COMPLEX_UNIT_SP, tVViewTextSize);
        editText.setGravity(Gravity.CENTER);
        editText.setImeOptions(EditorInfo.IME_ACTION_DONE);
        editText.setSingleLine();
        editText.setInputType(EditorInfo.TYPE_CLASS_TEXT);
        editText.setBackgroundResource(R.drawable.rectanger_co50_solid_grayf7f7f7);//设置的是最底层的颜色
        //失去焦点,就要保存数据
        editText.setOnFocusChangeListener(new OnFocusChangeListener() {
            @Override
            public void onFocusChange(View v, boolean hasFocus) {
                if (editText.getText().toString().length() <=0){
                    return;
                }
                if (!hasFocus){//失去焦点
                    if (onInputValueListener!=null){
                        LabelModel model = new LabelModel();
                        model.setTextValue(editText.getText().toString());
                        model.setClick(false);
                        modelArrayList.add(model);
                        LabelLayoutView.this.addView(createTextView(modelArrayList.size()-1,editText.getText().toString()));
                        onInputValueListener.onInoutItem(editText.toString());
                    }
                    editText.setText("");
                    //移除本EditTextView
                    LabelLayoutView.this.removeView(editText);
                    LabelLayoutView.this.addView(createAddTextView());
                }
            }
        });

        editText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_DONE){
                    cleanEditFocus();
                }
                return false;
            }
        });

        addView(editText);
    }

    //清除焦点事件
    public void cleanEditFocus(){
        if (editText!=null)
            editText.clearFocus();
    }

    public int dip2px(float dipValue) {
        final float scale = Resources.getSystem().getDisplayMetrics().density;
        return (int) (dipValue * scale + 0.5f);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        if (getChildCount() <= 0) {
            setMeasuredDimension(0, 0);
            return;
        }
        int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
        int line = 1;
        int currentWidth = 0;
        int currentHeight = 0;
        for (int i = 0; i < getChildCount(); i++) {
            View textView = getChildAt(i);
            measureChild(textView, widthMeasureSpec, heightMeasureSpec);
            //这里要算出,高度的最大的那个,后面多加一个tVVerticalSpace,是希望底部与TextView有一定的距离
            currentHeight = Math.max(currentHeight, textView.getMeasuredHeight() + tVVerticalSpace);
            int textViewWidth = textView.getMeasuredWidth();

            //一行的最后一个 & 无法放下一个textView和一个间隔
            if (parentWidth - currentWidth < textViewWidth + tVHorizontalSpace) {
                if (parentWidth - currentWidth >= textViewWidth) {//去掉间隔,判断是否可以放的下
                    currentWidth = currentWidth + textViewWidth;
                } else {//放不下,就要去下一行进行存放
                    currentWidth = 0;
                    currentWidth = currentWidth + textViewWidth + tVHorizontalSpace;
                    line = line + 1;
                }
            } else {
                if (parentWidth - currentWidth >= textViewWidth + tVHorizontalSpace) {
                    currentWidth = currentWidth + textViewWidth + tVHorizontalSpace;
                }
            }
        }
        setMeasuredDimension(parentWidth, line * currentHeight);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int left = 0;
        int top = 0;
        int parentWidth = this.getMeasuredWidth();
        for (int i = 0; i < getChildCount(); i++) {
            View textView = getChildAt(i);
            int childWidth = textView.getMeasuredWidth();
            int childHeight = textView.getMeasuredHeight();
            //一行的最后一个 & 无法放下一个textView和一个间隔
            if (parentWidth - left < childWidth + tVHorizontalSpace) {
                if (parentWidth - left >= childWidth) {//去掉间隔,判断是否可以放的下
                    textView.layout(left, top, left + childWidth, childHeight + top);
                    left = left + childWidth + tVHorizontalSpace;
                } else {
                    left = 0;
                    top = top + childHeight + tVVerticalSpace;
                    textView.layout(left, top, left + childWidth, childHeight + top);//从0位置开始绘制,绘制完后就会占位置,所以需要再加上绘制过的
                    left = left + childWidth + tVHorizontalSpace;
                }
            } else {
                textView.layout(left, top, left + childWidth, childHeight + top);
                left = left + childWidth + tVHorizontalSpace;
            }
        }
    }
}

相关文章

网友评论

    本文标题:android 实现标签流,动态添加标签并获取

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