
文章知识了解
你的自定义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;
}
}
}
}
网友评论