diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..1ebdb32 --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,251 @@ + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..aaba541 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..32fb988 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,19 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..7546a2d --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e3ba470..128683e 100644 --- a/README.md +++ b/README.md @@ -130,6 +130,15 @@ labelsView.setOnLabelSelectChangeListener(new LabelsView.OnLabelSelectChangeList        //label是被选中的标签,data是标签所对应的数据,isSelect是是否选中,position是标签的位置。 } }); + +//『+添加标签』的点击监听 + labelsView.setAddTextViewListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + label.add("测试"); + labelsView.setLabels(label); + } + }); ``` **5、常用方法** @@ -179,7 +188,11 @@ public void setLineMargin(int margin); //设置标签的间隔 public void setWordMargin(int margin); + +//尾部添加『+添加标签』项 +public void setAddLabel(boolean visible) ``` + 所有的set方法都有对应的get方法,这里就不说了。 ### 效果图: diff --git a/app/build.gradle b/app/build.gradle index 07a39e1..2c8d81d 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.application' android { - compileSdkVersion 23 - buildToolsVersion "23.0.3" + compileSdkVersion 26 + buildToolsVersion '27.0.3' defaultConfig { applicationId "com.donkingliang.labelsviewdemo" - minSdkVersion 9 - targetSdkVersion 23 + minSdkVersion 14 + targetSdkVersion 26 versionCode 1 versionName "1.0" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" @@ -20,12 +20,12 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + implementation fileTree(dir: 'libs', include: ['*.jar']) + androidTestImplementation('com.android.support.test.espresso:espresso-core:2.2.2', { exclude group: 'com.android.support', module: 'support-annotations' }) - compile 'com.android.support:appcompat-v7:23.4.0' - testCompile 'junit:junit:4.12' + implementation 'com.android.support:appcompat-v7:26.1.0' + testImplementation 'junit:junit:4.12' - compile project(":labels") + implementation project(":labels") } diff --git a/app/src/main/java/com/donkingliang/labelsviewdemo/MainActivity.java b/app/src/main/java/com/donkingliang/labelsviewdemo/MainActivity.java index 0275ded..8e2536a 100644 --- a/app/src/main/java/com/donkingliang/labelsviewdemo/MainActivity.java +++ b/app/src/main/java/com/donkingliang/labelsviewdemo/MainActivity.java @@ -2,7 +2,6 @@ import android.os.Bundle; import android.support.v7.app.AppCompatActivity; -import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; @@ -10,7 +9,6 @@ import com.donkingliang.labels.LabelsView; import java.util.ArrayList; -import java.util.List; import static com.donkingliang.labelsviewdemo.R.id.labels; @@ -26,40 +24,48 @@ protected void onCreate(Bundle savedInstanceState) { labelsView = (LabelsView) findViewById(labels); //测试的数据 -// ArrayList label = new ArrayList<>(); -// label.add("Android"); -// label.add("IOS"); -// label.add("前端"); -// label.add("后台"); -// label.add("微信开发"); -// label.add("游戏开发"); -// label.add("Java"); -// label.add("JavaScript"); -// label.add("C++"); -// label.add("PHP"); -// label.add("Python"); -// label.add("Swift"); -// labelsView.setLabels(label); - - ArrayList testList = new ArrayList<>(); - testList.add(new TestBean("Android",1)); - testList.add(new TestBean("IOS",2)); - testList.add(new TestBean("前端",3)); - testList.add(new TestBean("后台",4)); - testList.add(new TestBean("微信开发",5)); - testList.add(new TestBean("游戏开发",6)); - testList.add(new TestBean("Java",7)); - testList.add(new TestBean("JavaScript",8)); - testList.add(new TestBean("C++",9)); - testList.add(new TestBean("PHP",10)); - testList.add(new TestBean("Python",11)); - testList.add(new TestBean("Swift",12)); - labelsView.setLabels(testList, new LabelsView.LabelTextProvider() { + final ArrayList label = new ArrayList<>(); + label.add("Android"); + label.add("IOS"); + label.add("前端"); + label.add("后台"); + label.add("微信开发"); + label.add("游戏开发"); + label.add("Java"); + label.add("JavaScript"); + label.add("C++"); + label.add("PHP"); + label.add("Python"); + label.add("Swift"); + labelsView.setSelectType(LabelsView.SelectType.NONE); + labelsView.setAddTextViewListener(new View.OnClickListener() { @Override - public CharSequence getLabelText(TextView label, int position, TestBean data) { - return data.getName(); + public void onClick(View v) { + label.add("测试"); + labelsView.setLabels(label); } }); + labelsView.setLabels(label); + +// final ArrayList testList = new ArrayList<>(); +// testList.add(new TestBean("Android",1)); +// testList.add(new TestBean("IOS",2)); +// testList.add(new TestBean("前端",3)); +// testList.add(new TestBean("后台",4)); +// testList.add(new TestBean("微信开发",5)); +// testList.add(new TestBean("游戏开发",6)); +// testList.add(new TestBean("Java",7)); +// testList.add(new TestBean("JavaScript",8)); +// testList.add(new TestBean("C++",9)); +// testList.add(new TestBean("PHP",10)); +// testList.add(new TestBean("Python",11)); +// testList.add(new TestBean("Swift",12)); +// labelsView.setLabels(testList, new LabelsView.LabelTextProvider() { +// @Override +// public CharSequence getLabelText(TextView label, int position, TestBean data) { +// return data.getName(); +// } +// }); findViewById(R.id.btn_none).setOnClickListener(this); findViewById(R.id.btn_single).setOnClickListener(this); diff --git a/app/src/main/res/drawable/label_bg.xml b/app/src/main/res/drawable/label_bg.xml index fddde7c..49f55e5 100644 --- a/app/src/main/res/drawable/label_bg.xml +++ b/app/src/main/res/drawable/label_bg.xml @@ -1,19 +1,26 @@ - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/label_text_color.xml b/app/src/main/res/drawable/label_text_color.xml index 1d45234..d4c4037 100644 --- a/app/src/main/res/drawable/label_text_color.xml +++ b/app/src/main/res/drawable/label_text_color.xml @@ -2,6 +2,7 @@ + \ No newline at end of file diff --git a/build.gradle b/build.gradle index 169c8d2..d5f2a7a 100644 --- a/build.gradle +++ b/build.gradle @@ -3,11 +3,11 @@ buildscript { repositories { jcenter() + google() } dependencies { - classpath 'com.android.tools.build:gradle:2.1.0' - classpath 'com.github.dcendents:android-maven-gradle-plugin:1.3' - + classpath 'com.android.tools.build:gradle:3.1.3' + classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5' // NOTE: Do not place your application dependencies here; they belong // in the individual module build.gradle files } @@ -16,6 +16,7 @@ buildscript { allprojects { repositories { jcenter() + google() } } diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 122a0dc..d9cc84c 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ -#Mon Dec 28 10:00:20 PST 2015 +#Thu Jul 05 21:36:34 CST 2018 distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-2.10-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip diff --git a/labels/build.gradle b/labels/build.gradle index b3c64c6..4dde13a 100644 --- a/labels/build.gradle +++ b/labels/build.gradle @@ -4,12 +4,12 @@ apply plugin: 'com.github.dcendents.android-maven' group='com.github.donkingliang' // 指定group,com.github.<用户名> android { - compileSdkVersion 23 - buildToolsVersion "23.0.3" + compileSdkVersion 26 + buildToolsVersion '27.0.3' defaultConfig { - minSdkVersion 9 - targetSdkVersion 23 + minSdkVersion 14 + targetSdkVersion 26 versionCode 1 versionName "1.0" } @@ -22,9 +22,9 @@ android { } dependencies { - compile fileTree(dir: 'libs', include: ['*.jar']) - testCompile 'junit:junit:4.12' - compile 'com.android.support:appcompat-v7:23.4.0' + implementation fileTree(dir: 'libs', include: ['*.jar']) + testImplementation 'junit:junit:4.12' + implementation 'com.android.support:appcompat-v7:26.1.0' } //--------------------------------------------- diff --git a/labels/src/main/java/com/donkingliang/labels/LabelsView.java b/labels/src/main/java/com/donkingliang/labels/LabelsView.java index 9cd4b59..a594da6 100644 --- a/labels/src/main/java/com/donkingliang/labels/LabelsView.java +++ b/labels/src/main/java/com/donkingliang/labels/LabelsView.java @@ -18,851 +18,843 @@ public class LabelsView extends ViewGroup implements View.OnClickListener { - private Context mContext; - - private ColorStateList mTextColor; - private float mTextSize; - private Drawable mLabelBg; - private int mTextPaddingLeft; - private int mTextPaddingTop; - private int mTextPaddingRight; - private int mTextPaddingBottom; - private int mWordMargin; - private int mLineMargin; - private SelectType mSelectType; - private int mMaxSelect; - - //用于保存label数据的key - private static final int KEY_DATA = R.id.tag_key_data; - //用于保存label位置的key - private static final int KEY_POSITION = R.id.tag_key_position; - - private ArrayList mLabels = new ArrayList<>(); - //保存选中的label的位置 - private ArrayList mSelectLabels = new ArrayList<>(); - - //保存必选项。在多选模式下,可以设置必选项,必选项默认选中,不能反选 - private ArrayList mCompulsorys = new ArrayList<>(); - - private OnLabelClickListener mLabelClickListener; - private OnLabelSelectChangeListener mLabelSelectChangeListener; - - /** - * Label的选择类型 - */ - public enum SelectType { - //不可选中,也不响应选中事件回调。(默认) - NONE(1), - //单选,可以反选。 - SINGLE(2), - //单选,不可以反选。这种模式下,至少有一个是选中的,默认是第一个 - SINGLE_IRREVOCABLY(3), - //多选 - MULTI(4); - - int value; - - SelectType(int value) { - this.value = value; - } - - static SelectType get(int value) { - switch (value) { - case 1: - return NONE; - case 2: - return SINGLE; - case 3: - return SINGLE_IRREVOCABLY; - case 4: - return MULTI; - } - return NONE; - } - } - - public LabelsView(Context context) { - super(context); - mContext = context; - } - - public LabelsView(Context context, AttributeSet attrs) { - super(context, attrs); - mContext = context; - getAttrs(context, attrs); - } - - public LabelsView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - mContext = context; - getAttrs(context, attrs); - } - - private void getAttrs(Context context, AttributeSet attrs) { - if (attrs != null) { - TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.labels_view); - int type = mTypedArray.getInt(R.styleable.labels_view_selectType, 1); - mSelectType = SelectType.get(type); - - mMaxSelect = mTypedArray.getInteger(R.styleable.labels_view_maxSelect, 0); - mTextColor = mTypedArray.getColorStateList(R.styleable.labels_view_labelTextColor); - mTextSize = mTypedArray.getDimension(R.styleable.labels_view_labelTextSize, - sp2px(context, 14)); - mTextPaddingLeft = mTypedArray.getDimensionPixelOffset( - R.styleable.labels_view_labelTextPaddingLeft, 0); - mTextPaddingTop = mTypedArray.getDimensionPixelOffset( - R.styleable.labels_view_labelTextPaddingTop, 0); - mTextPaddingRight = mTypedArray.getDimensionPixelOffset( - R.styleable.labels_view_labelTextPaddingRight, 0); - mTextPaddingBottom = mTypedArray.getDimensionPixelOffset( - R.styleable.labels_view_labelTextPaddingBottom, 0); - mLineMargin = mTypedArray.getDimensionPixelOffset(R.styleable.labels_view_lineMargin, 0); - mWordMargin = mTypedArray.getDimensionPixelOffset(R.styleable.labels_view_wordMargin, 0); - int labelBgResId = mTypedArray.getResourceId(R.styleable.labels_view_labelBackground, 0); - mLabelBg = getResources().getDrawable(labelBgResId); - mTypedArray.recycle(); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - int count = getChildCount(); - int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); - - int contentHeight = 0; //记录内容的高度 - int lineWidth = 0; //记录行的宽度 - int maxLineWidth = 0; //记录最宽的行宽 - int maxItemHeight = 0; //记录一行中item高度最大的高度 - boolean begin = true; //是否是行的开头 - - for (int i = 0; i < count; i++) { - View view = getChildAt(i); - measureChild(view, widthMeasureSpec, heightMeasureSpec); - - if (!begin) { - lineWidth += mWordMargin; - } else { - begin = false; - } - - if (maxWidth <= lineWidth + view.getMeasuredWidth()) { - contentHeight += mLineMargin; - contentHeight += maxItemHeight; - maxItemHeight = 0; - maxLineWidth = Math.max(maxLineWidth, lineWidth); - lineWidth = 0; - begin = true; - } - maxItemHeight = Math.max(maxItemHeight, view.getMeasuredHeight()); - - lineWidth += view.getMeasuredWidth(); - } - + //用于保存label数据的key + private static final int KEY_DATA = R.id.tag_key_data; + //用于保存label位置的key + private static final int KEY_POSITION = R.id.tag_key_position; + /* 用于保存View的信息的key */ + private static final String KEY_SUPER_STATE = "key_super_state"; + private static final String KEY_TEXT_COLOR_STATE = "key_text_color_state"; + private static final String KEY_TEXT_SIZE_STATE = "key_text_size_state"; + private static final String KEY_BG_RES_ID_STATE = "key_bg_res_id_state"; + private static final String KEY_PADDING_STATE = "key_padding_state"; + private static final String KEY_WORD_MARGIN_STATE = "key_word_margin_state"; + private static final String KEY_LINE_MARGIN_STATE = "key_line_margin_state"; + private static final String KEY_SELECT_TYPE_STATE = "key_select_type_state"; + private static final String KEY_MAX_SELECT_STATE = "key_max_select_state"; + // 由于新版(1.4.0)的标签列表允许设置任何类型的数据,而不仅仅是String。并且标签显示的内容 + // 最终由LabelTextProvider提供,所以LabelsView不再在onSaveInstanceState()和onRestoreInstanceState() + // 中保存和恢复标签列表的数据。 + private static final String KEY_LABELS_STATE = "key_labels_state"; + private static final String KEY_SELECT_LABELS_STATE = "key_select_labels_state"; + private static final String KEY_COMPULSORY_LABELS_STATE = "key_select_compulsory_state"; + private Context mContext; + private ColorStateList mTextColor; + private float mTextSize; + private Drawable mLabelBg; + private int mTextPaddingLeft; + private int mTextPaddingTop; + private int mTextPaddingRight; + private int mTextPaddingBottom; + private int mWordMargin; + private int mLineMargin; + private SelectType mSelectType; + private int mMaxSelect; + private boolean mAddVisible; + private TextView mAddTextView; + private ArrayList mLabels = new ArrayList<>(); + //保存选中的label的位置 + private ArrayList mSelectLabels = new ArrayList<>(); + //保存必选项。在多选模式下,可以设置必选项,必选项默认选中,不能反选 + private ArrayList mCompulsorys = new ArrayList<>(); + private OnLabelClickListener mLabelClickListener; + private OnLabelSelectChangeListener mLabelSelectChangeListener; + public LabelsView(Context context) { + super(context); + mContext = context; + } + public LabelsView(Context context, AttributeSet attrs) { + super(context, attrs); + mContext = context; + getAttrs(context, attrs); + } + public LabelsView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + mContext = context; + getAttrs(context, attrs); + } + /** + * sp转px + */ + public static int sp2px(Context context, float spVal) { + return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, + spVal, context.getResources().getDisplayMetrics()); + } + private void getAttrs(Context context, AttributeSet attrs) { + if (attrs != null) { + TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.LabelsView); + int type = mTypedArray.getInt(R.styleable.LabelsView_selectType, 1); + mSelectType = SelectType.get(type); + + mMaxSelect = mTypedArray.getInteger(R.styleable.LabelsView_maxSelect, 0); + mTextColor = mTypedArray.getColorStateList(R.styleable.LabelsView_labelTextColor); + mTextSize = mTypedArray.getDimension(R.styleable.LabelsView_labelTextSize, + sp2px(context, 14)); + mTextPaddingLeft = mTypedArray.getDimensionPixelOffset( + R.styleable.LabelsView_labelTextPaddingLeft, 0); + mTextPaddingTop = mTypedArray.getDimensionPixelOffset( + R.styleable.LabelsView_labelTextPaddingTop, 0); + mTextPaddingRight = mTypedArray.getDimensionPixelOffset( + R.styleable.LabelsView_labelTextPaddingRight, 0); + mTextPaddingBottom = mTypedArray.getDimensionPixelOffset( + R.styleable.LabelsView_labelTextPaddingBottom, 0); + mLineMargin = mTypedArray.getDimensionPixelOffset(R.styleable.LabelsView_lineMargin, 0); + mWordMargin = mTypedArray.getDimensionPixelOffset(R.styleable.LabelsView_wordMargin, 0); + int labelBgResId = mTypedArray.getResourceId(R.styleable.LabelsView_labelBackground, 0); + mLabelBg = getResources().getDrawable(labelBgResId); + mAddVisible = mTypedArray.getBoolean(R.styleable.LabelsView_AddLabelVisible, false); + mTypedArray.recycle(); + } + + mAddTextView = new TextView(getContext()); + mAddTextView.setText("+添加标签"); + } + @Override + protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { + + int count = getChildCount(); + int maxWidth = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight(); + + int contentHeight = 0; //记录内容的高度 + int lineWidth = 0; //记录行的宽度 + int maxLineWidth = 0; //记录最宽的行宽 + int maxItemHeight = 0; //记录一行中item高度最大的高度 + boolean begin = true; //是否是行的开头 + + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + measureChild(view, widthMeasureSpec, heightMeasureSpec); + + if (!begin) { + lineWidth += mWordMargin; + } else { + begin = false; + } + + if (maxWidth <= lineWidth + view.getMeasuredWidth()) { + contentHeight += mLineMargin; contentHeight += maxItemHeight; + maxItemHeight = 0; maxLineWidth = Math.max(maxLineWidth, lineWidth); - - setMeasuredDimension(measureWidth(widthMeasureSpec, maxLineWidth), - measureHeight(heightMeasureSpec, contentHeight)); - } - - private int measureWidth(int measureSpec, int contentWidth) { - int result = 0; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - if (specMode == MeasureSpec.EXACTLY) { - result = specSize; - } else { - result = contentWidth + getPaddingLeft() + getPaddingRight(); - if (specMode == MeasureSpec.AT_MOST) { - result = Math.min(result, specSize); - } - } - result = Math.max(result, getSuggestedMinimumWidth()); - return result; - } - - private int measureHeight(int measureSpec, int contentHeight) { - int result = 0; - int specMode = MeasureSpec.getMode(measureSpec); - int specSize = MeasureSpec.getSize(measureSpec); - - if (specMode == MeasureSpec.EXACTLY) { - result = specSize; - } else { - result = contentHeight + getPaddingTop() + getPaddingBottom(); - if (specMode == MeasureSpec.AT_MOST) { - result = Math.min(result, specSize); - } - } - result = Math.max(result, getSuggestedMinimumHeight()); - return result; - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - - int x = getPaddingLeft(); - int y = getPaddingTop(); - - int contentWidth = right - left; - int maxItemHeight = 0; - - int count = getChildCount(); - for (int i = 0; i < count; i++) { - View view = getChildAt(i); - - if (contentWidth < x + view.getMeasuredWidth() + getPaddingRight()) { - x = getPaddingLeft(); - y += mLineMargin; - y += maxItemHeight; - maxItemHeight = 0; - } - view.layout(x, y, x + view.getMeasuredWidth(), y + view.getMeasuredHeight()); - x += view.getMeasuredWidth(); - x += mWordMargin; - maxItemHeight = Math.max(maxItemHeight, view.getMeasuredHeight()); - } - } - - /* 用于保存View的信息的key */ - private static final String KEY_SUPER_STATE = "key_super_state"; - private static final String KEY_TEXT_COLOR_STATE = "key_text_color_state"; - private static final String KEY_TEXT_SIZE_STATE = "key_text_size_state"; - private static final String KEY_BG_RES_ID_STATE = "key_bg_res_id_state"; - private static final String KEY_PADDING_STATE = "key_padding_state"; - private static final String KEY_WORD_MARGIN_STATE = "key_word_margin_state"; - private static final String KEY_LINE_MARGIN_STATE = "key_line_margin_state"; - private static final String KEY_SELECT_TYPE_STATE = "key_select_type_state"; - private static final String KEY_MAX_SELECT_STATE = "key_max_select_state"; - // 由于新版(1.4.0)的标签列表允许设置任何类型的数据,而不仅仅是String。并且标签显示的内容 - // 最终由LabelTextProvider提供,所以LabelsView不再在onSaveInstanceState()和onRestoreInstanceState() - // 中保存和恢复标签列表的数据。 - private static final String KEY_LABELS_STATE = "key_labels_state"; - private static final String KEY_SELECT_LABELS_STATE = "key_select_labels_state"; - private static final String KEY_COMPULSORY_LABELS_STATE = "key_select_compulsory_state"; - - @Override - protected Parcelable onSaveInstanceState() { - - Bundle bundle = new Bundle(); - //保存父类的信息 - bundle.putParcelable(KEY_SUPER_STATE, super.onSaveInstanceState()); - //保存标签文字颜色 - if (mTextColor != null) { - bundle.putParcelable(KEY_TEXT_COLOR_STATE, mTextColor); - } - //保存标签文字大小 - bundle.putFloat(KEY_TEXT_SIZE_STATE, mTextSize); - //保存标签背景 (由于背景改用Drawable,所以不能自动保存和恢复) -// bundle.putInt(KEY_BG_RES_ID_STATE, mLabelBgResId); - //保存标签内边距 - bundle.putIntArray(KEY_PADDING_STATE, new int[]{mTextPaddingLeft, mTextPaddingTop, - mTextPaddingRight, mTextPaddingBottom}); - //保存标签间隔 - bundle.putInt(KEY_WORD_MARGIN_STATE, mWordMargin); - //保存行间隔 - bundle.putInt(KEY_LINE_MARGIN_STATE, mLineMargin); - //保存标签的选择类型 - bundle.putInt(KEY_SELECT_TYPE_STATE, mSelectType.value); - //保存标签的最大选择数量 - bundle.putInt(KEY_MAX_SELECT_STATE, mMaxSelect); - //保存标签列表 -// if (!mLabels.isEmpty()) { -// bundle.putStringArrayList(KEY_LABELS_STATE, mLabels); -// } - //保存已选择的标签列表 - if (!mSelectLabels.isEmpty()) { - bundle.putIntegerArrayList(KEY_SELECT_LABELS_STATE, mSelectLabels); - } - - //保存必选项列表 - if (!mCompulsorys.isEmpty()) { - bundle.putIntegerArrayList(KEY_COMPULSORY_LABELS_STATE, mCompulsorys); - } - - return bundle; - } - - @Override - protected void onRestoreInstanceState(Parcelable state) { - if (state instanceof Bundle) { - Bundle bundle = (Bundle) state; - //恢复父类信息 - super.onRestoreInstanceState(bundle.getParcelable(KEY_SUPER_STATE)); - - //恢复标签文字颜色 - ColorStateList color = bundle.getParcelable(KEY_TEXT_COLOR_STATE); - if (color != null) { - setLabelTextColor(color); - } - //恢复标签文字大小 - setLabelTextSize(bundle.getFloat(KEY_TEXT_SIZE_STATE, mTextSize)); -// //恢复标签背景 (由于背景改用Drawable,所以不能自动保存和恢复) -// int resId = bundle.getInt(KEY_BG_RES_ID_STATE, mLabelBgResId); -// if (resId != 0) { -// setLabelBackgroundResource(resId); -// } - //恢复标签内边距 - int[] padding = bundle.getIntArray(KEY_PADDING_STATE); - if (padding != null && padding.length == 4) { - setLabelTextPadding(padding[0], padding[1], padding[2], padding[3]); - } - //恢复标签间隔 - setWordMargin(bundle.getInt(KEY_WORD_MARGIN_STATE, mWordMargin)); - //恢复行间隔 - setLineMargin(bundle.getInt(KEY_LINE_MARGIN_STATE, mLineMargin)); - //恢复标签的选择类型 - setSelectType(SelectType.get(bundle.getInt(KEY_SELECT_TYPE_STATE, mSelectType.value))); - //恢复标签的最大选择数量 - setMaxSelect(bundle.getInt(KEY_MAX_SELECT_STATE, mMaxSelect)); -// //恢复标签列表 -// ArrayList labels = bundle.getStringArrayList(KEY_LABELS_STATE); -// if (labels != null && !labels.isEmpty()) { -// setLabels(labels); -// } - //恢复必选项列表 - ArrayList compulsory = bundle.getIntegerArrayList(KEY_COMPULSORY_LABELS_STATE); - if (compulsory != null && !compulsory.isEmpty()) { - setCompulsorys(compulsory); - } - //恢复已选择的标签列表 - ArrayList selectLabel = bundle.getIntegerArrayList(KEY_SELECT_LABELS_STATE); - if (selectLabel != null && !selectLabel.isEmpty()) { - int size = selectLabel.size(); - int[] positions = new int[size]; - for (int i = 0; i < size; i++) { - positions[i] = selectLabel.get(i); - } - setSelects(positions); - } - return; - } - super.onRestoreInstanceState(state); - } - - /** - * 设置标签列表 - * - * @param labels - */ - public void setLabels(List labels) { - setLabels(labels, new LabelTextProvider() { - @Override - public CharSequence getLabelText(TextView label, int position, String data) { - return data.trim(); - } - }); - } - - /** - * 设置标签列表,标签列表的数据可以是任何类型的数据,它最终显示的内容由LabelTextProvider根据标签的数据提供。 - * - * @param labels - * @param provider - * @param - */ - public void setLabels(List labels, LabelTextProvider provider) { - //清空原有的标签 + lineWidth = 0; + begin = true; + } + maxItemHeight = Math.max(maxItemHeight, view.getMeasuredHeight()); + + lineWidth += view.getMeasuredWidth(); + } + + contentHeight += maxItemHeight; + maxLineWidth = Math.max(maxLineWidth, lineWidth); + + setMeasuredDimension(measureWidth(widthMeasureSpec, maxLineWidth), + measureHeight(heightMeasureSpec, contentHeight)); + } + private int measureWidth(int measureSpec, int contentWidth) { + int result = 0; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if (specMode == MeasureSpec.EXACTLY) { + result = specSize; + } else { + result = contentWidth + getPaddingLeft() + getPaddingRight(); + if (specMode == MeasureSpec.AT_MOST) { + result = Math.min(result, specSize); + } + } + result = Math.max(result, getSuggestedMinimumWidth()); + return result; + } + private int measureHeight(int measureSpec, int contentHeight) { + int result = 0; + int specMode = MeasureSpec.getMode(measureSpec); + int specSize = MeasureSpec.getSize(measureSpec); + + if (specMode == MeasureSpec.EXACTLY) { + result = specSize; + } else { + result = contentHeight + getPaddingTop() + getPaddingBottom(); + if (specMode == MeasureSpec.AT_MOST) { + result = Math.min(result, specSize); + } + } + result = Math.max(result, getSuggestedMinimumHeight()); + return result; + } + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + + int x = getPaddingLeft(); + int y = getPaddingTop(); + + int contentWidth = right - left; + int maxItemHeight = 0; + + int count = getChildCount(); + for (int i = 0; i < count; i++) { + View view = getChildAt(i); + + if (contentWidth < x + view.getMeasuredWidth() + getPaddingRight()) { + x = getPaddingLeft(); + y += mLineMargin; + y += maxItemHeight; + maxItemHeight = 0; + } + view.layout(x, y, x + view.getMeasuredWidth(), y + view.getMeasuredHeight()); + x += view.getMeasuredWidth(); + x += mWordMargin; + maxItemHeight = Math.max(maxItemHeight, view.getMeasuredHeight()); + } + } + @Override + protected Parcelable onSaveInstanceState() { + + Bundle bundle = new Bundle(); + //保存父类的信息 + bundle.putParcelable(KEY_SUPER_STATE, super.onSaveInstanceState()); + //保存标签文字颜色 + if (mTextColor != null) { + bundle.putParcelable(KEY_TEXT_COLOR_STATE, mTextColor); + } + //保存标签文字大小 + bundle.putFloat(KEY_TEXT_SIZE_STATE, mTextSize); + //保存标签背景 (由于背景改用Drawable,所以不能自动保存和恢复) + // bundle.putInt(KEY_BG_RES_ID_STATE, mLabelBgResId); + //保存标签内边距 + bundle.putIntArray(KEY_PADDING_STATE, new int[]{mTextPaddingLeft, mTextPaddingTop, + mTextPaddingRight, mTextPaddingBottom}); + //保存标签间隔 + bundle.putInt(KEY_WORD_MARGIN_STATE, mWordMargin); + //保存行间隔 + bundle.putInt(KEY_LINE_MARGIN_STATE, mLineMargin); + //保存标签的选择类型 + bundle.putInt(KEY_SELECT_TYPE_STATE, mSelectType.value); + //保存标签的最大选择数量 + bundle.putInt(KEY_MAX_SELECT_STATE, mMaxSelect); + //保存标签列表 + // if (!mLabels.isEmpty()) { + // bundle.putStringArrayList(KEY_LABELS_STATE, mLabels); + // } + //保存已选择的标签列表 + if (!mSelectLabels.isEmpty()) { + bundle.putIntegerArrayList(KEY_SELECT_LABELS_STATE, mSelectLabels); + } + + //保存必选项列表 + if (!mCompulsorys.isEmpty()) { + bundle.putIntegerArrayList(KEY_COMPULSORY_LABELS_STATE, mCompulsorys); + } + + return bundle; + } + + @Override + protected void onRestoreInstanceState(Parcelable state) { + if (state instanceof Bundle) { + Bundle bundle = (Bundle) state; + //恢复父类信息 + super.onRestoreInstanceState(bundle.getParcelable(KEY_SUPER_STATE)); + + //恢复标签文字颜色 + ColorStateList color = bundle.getParcelable(KEY_TEXT_COLOR_STATE); + if (color != null) { + setLabelTextColor(color); + } + //恢复标签文字大小 + setLabelTextSize(bundle.getFloat(KEY_TEXT_SIZE_STATE, mTextSize)); + // //恢复标签背景 (由于背景改用Drawable,所以不能自动保存和恢复) + // int resId = bundle.getInt(KEY_BG_RES_ID_STATE, mLabelBgResId); + // if (resId != 0) { + // setLabelBackgroundResource(resId); + // } + //恢复标签内边距 + int[] padding = bundle.getIntArray(KEY_PADDING_STATE); + if (padding != null && padding.length == 4) { + setLabelTextPadding(padding[0], padding[1], padding[2], padding[3]); + } + //恢复标签间隔 + setWordMargin(bundle.getInt(KEY_WORD_MARGIN_STATE, mWordMargin)); + //恢复行间隔 + setLineMargin(bundle.getInt(KEY_LINE_MARGIN_STATE, mLineMargin)); + //恢复标签的选择类型 + setSelectType(SelectType.get(bundle.getInt(KEY_SELECT_TYPE_STATE, mSelectType.value))); + //恢复标签的最大选择数量 + setMaxSelect(bundle.getInt(KEY_MAX_SELECT_STATE, mMaxSelect)); + // //恢复标签列表 + // ArrayList labels = bundle.getStringArrayList(KEY_LABELS_STATE); + // if (labels != null && !labels.isEmpty()) { + // setLabels(labels); + // } + //恢复必选项列表 + ArrayList compulsory = bundle.getIntegerArrayList(KEY_COMPULSORY_LABELS_STATE); + if (compulsory != null && !compulsory.isEmpty()) { + setCompulsorys(compulsory); + } + //恢复已选择的标签列表 + ArrayList selectLabel = bundle.getIntegerArrayList(KEY_SELECT_LABELS_STATE); + if (selectLabel != null && !selectLabel.isEmpty()) { + int size = selectLabel.size(); + int[] positions = new int[size]; + for (int i = 0; i < size; i++) { + positions[i] = selectLabel.get(i); + } + setSelects(positions); + } + return; + } + super.onRestoreInstanceState(state); + } + /** + * 设置标签列表,标签列表的数据可以是任何类型的数据,它最终显示的内容由LabelTextProvider根据标签的数据提供。 + * + * @param labels + * @param provider + * @param + */ + public void setLabels(List labels, LabelTextProvider provider) { + //清空原有的标签 + innerClearAllSelect(); + removeAllViews(); + mLabels.clear(); + + if (labels != null) { + mLabels.addAll(labels); + int size = labels.size(); + for (int i = 0; i < size; i++) { + addLabel(labels.get(i), i, provider); + } + } + + if (mAddVisible) { + setAddTextViewStyle(); + addView(mAddTextView); + } + + if (mSelectType == SelectType.SINGLE_IRREVOCABLY) { + setSelects(0); + } + } + /** + * 获取标签列表 + * + * @return + */ + public List getLabels() { + return (List) mLabels; + } + /** + * 设置标签列表 + * + * @param labels + */ + public void setLabels(List labels) { + setLabels(labels, new LabelTextProvider() { + @Override + public CharSequence getLabelText(TextView label, int position, String data) { + return data.trim(); + } + }); + } + private void addLabel(T data, int position, LabelTextProvider provider) { + final TextView label = new TextView(mContext); + label.setPadding(mTextPaddingLeft, mTextPaddingTop, mTextPaddingRight, mTextPaddingBottom); + label.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); + label.setTextColor(mTextColor != null ? mTextColor : ColorStateList.valueOf(0xFF000000)); + //设置给label的背景(Drawable)是一个Drawable对象的拷贝, + // 因为如果所有的标签都共用一个Drawable对象,会引起背景错乱。 + label.setBackgroundDrawable(mLabelBg.getConstantState().newDrawable()); + //label通过tag保存自己的数据(data)和位置(position) + label.setTag(KEY_DATA, data); + label.setTag(KEY_POSITION, position); + label.setOnClickListener(this); + addView(label); + label.setText(provider.getLabelText(label, position, data)); + } + + private void setAddTextViewStyle() { + mAddTextView.setPadding(mTextPaddingLeft, mTextPaddingTop, mTextPaddingRight, mTextPaddingBottom); + mAddTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); + mAddTextView.setTextColor(mTextColor != null ? mTextColor : ColorStateList.valueOf(0xFF000000)); + //设置给label的背景(Drawable)是一个Drawable对象的拷贝, + // 因为如果所有的标签都共用一个Drawable对象,会引起背景错乱。 + mAddTextView.setBackgroundDrawable(mLabelBg.getConstantState().newDrawable()); + } + + @Override + public void onClick(View v) { + if (v instanceof TextView) { + TextView label = (TextView) v; + if (mSelectType != SelectType.NONE) { + if (label.isSelected()) { + if (mSelectType != SelectType.SINGLE_IRREVOCABLY + && !mCompulsorys.contains((Integer) label.getTag(KEY_POSITION))) { + setLabelSelect(label, false); + } + } else if (mSelectType == SelectType.SINGLE || mSelectType == SelectType.SINGLE_IRREVOCABLY) { + innerClearAllSelect(); + setLabelSelect(label, true); + } else if (mSelectType == SelectType.MULTI + && (mMaxSelect <= 0 || mMaxSelect > mSelectLabels.size())) { + setLabelSelect(label, true); + } + } + + if (mLabelClickListener != null) { + mLabelClickListener.onLabelClick(label, label.getTag(KEY_DATA), (int) label.getTag(KEY_POSITION)); + } + } + } + + private void setLabelSelect(TextView label, boolean isSelect) { + if (label.isSelected() != isSelect) { + label.setSelected(isSelect); + if (isSelect) { + mSelectLabels.add((Integer) label.getTag(KEY_POSITION)); + } else { + mSelectLabels.remove((Integer) label.getTag(KEY_POSITION)); + } + if (mLabelSelectChangeListener != null) { + mLabelSelectChangeListener.onLabelSelectChange(label, label.getTag(KEY_DATA), + isSelect, (int) label.getTag(KEY_POSITION)); + } + } + } + + /** + * 取消所有选中的label + */ + public void clearAllSelect() { + if (mSelectType != SelectType.SINGLE_IRREVOCABLY) { + if (mSelectType == SelectType.MULTI && !mCompulsorys.isEmpty()) { + clearNotCompulsorySelect(); + } else { innerClearAllSelect(); - removeAllViews(); - mLabels.clear(); - - if (labels != null) { - mLabels.addAll(labels); - int size = labels.size(); - for (int i = 0; i < size; i++) { - addLabel(labels.get(i), i, provider); - } - } - - if (mSelectType == SelectType.SINGLE_IRREVOCABLY) { - setSelects(0); - } - } - - /** - * 获取标签列表 - * - * @return - */ - public List getLabels() { - return (List) mLabels; - } - - private void addLabel(T data, int position, LabelTextProvider provider) { - final TextView label = new TextView(mContext); - label.setPadding(mTextPaddingLeft, mTextPaddingTop, mTextPaddingRight, mTextPaddingBottom); - label.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTextSize); - label.setTextColor(mTextColor != null ? mTextColor : ColorStateList.valueOf(0xFF000000)); - //设置给label的背景(Drawable)是一个Drawable对象的拷贝, - // 因为如果所有的标签都共用一个Drawable对象,会引起背景错乱。 - label.setBackgroundDrawable(mLabelBg.getConstantState().newDrawable()); - //label通过tag保存自己的数据(data)和位置(position) - label.setTag(KEY_DATA, data); - label.setTag(KEY_POSITION, position); - label.setOnClickListener(this); - addView(label); - label.setText(provider.getLabelText(label, position, data)); - } - - @Override - public void onClick(View v) { - if (v instanceof TextView) { - TextView label = (TextView) v; - if (mSelectType != SelectType.NONE) { - if (label.isSelected()) { - if (mSelectType != SelectType.SINGLE_IRREVOCABLY - && !mCompulsorys.contains((Integer) label.getTag(KEY_POSITION))) { - setLabelSelect(label, false); - } - } else if (mSelectType == SelectType.SINGLE || mSelectType == SelectType.SINGLE_IRREVOCABLY) { - innerClearAllSelect(); - setLabelSelect(label, true); - } else if (mSelectType == SelectType.MULTI - && (mMaxSelect <= 0 || mMaxSelect > mSelectLabels.size())) { - setLabelSelect(label, true); - } - } - - if (mLabelClickListener != null) { - mLabelClickListener.onLabelClick(label, label.getTag(KEY_DATA), (int) label.getTag(KEY_POSITION)); - } - } - } - - private void setLabelSelect(TextView label, boolean isSelect) { - if (label.isSelected() != isSelect) { - label.setSelected(isSelect); - if (isSelect) { - mSelectLabels.add((Integer) label.getTag(KEY_POSITION)); - } else { - mSelectLabels.remove((Integer) label.getTag(KEY_POSITION)); - } - if (mLabelSelectChangeListener != null) { - mLabelSelectChangeListener.onLabelSelectChange(label, label.getTag(KEY_DATA), - isSelect, (int) label.getTag(KEY_POSITION)); - } - } - } - - /** - * 取消所有选中的label - */ - public void clearAllSelect() { - if (mSelectType != SelectType.SINGLE_IRREVOCABLY) { - if (mSelectType == SelectType.MULTI && !mCompulsorys.isEmpty()) { - clearNotCompulsorySelect(); - } else { - innerClearAllSelect(); - } - } - } - - private void innerClearAllSelect() { - int count = getChildCount(); - for (int i = 0; i < count; i++) { - setLabelSelect((TextView) getChildAt(i), false); - } - mSelectLabels.clear(); - } - - private void clearNotCompulsorySelect() { - int count = getChildCount(); - List temps = new ArrayList<>(); - for (int i = 0; i < count; i++) { - if (!mCompulsorys.contains(i)) { - setLabelSelect((TextView) getChildAt(i), false); - temps.add(i); - } - - } - mSelectLabels.removeAll(temps); - } - - /** - * 设置选中label - * - * @param positions - */ - public void setSelects(List positions) { - if (positions != null) { - int size = positions.size(); - int[] ps = new int[size]; - for (int i = 0; i < size; i++) { - ps[i] = positions.get(i); - } - setSelects(ps); - } - } - - /** - * 设置选中label - * - * @param positions - */ - public void setSelects(int... positions) { - if (mSelectType != SelectType.NONE) { - ArrayList selectLabels = new ArrayList<>(); - int count = getChildCount(); - int size = mSelectType == SelectType.SINGLE || mSelectType == SelectType.SINGLE_IRREVOCABLY - ? 1 : mMaxSelect; - for (int p : positions) { - if (p < count) { - TextView label = (TextView) getChildAt(p); - if (!selectLabels.contains(label)) { - setLabelSelect(label, true); - selectLabels.add(label); - } - if (size > 0 && selectLabels.size() == size) { - break; - } - } - } - - for (int i = 0; i < count; i++) { - TextView label = (TextView) getChildAt(i); - if (!selectLabels.contains(label)) { - setLabelSelect(label, false); - } - } - } - } + } + } + } + + private void innerClearAllSelect() { + int count = getChildCount(); + for (int i = 0; i < count; i++) { + setLabelSelect((TextView) getChildAt(i), false); + } + mSelectLabels.clear(); + } + + private void clearNotCompulsorySelect() { + int count = getChildCount(); + List temps = new ArrayList<>(); + for (int i = 0; i < count; i++) { + if (!mCompulsorys.contains(i)) { + setLabelSelect((TextView) getChildAt(i), false); + temps.add(i); + } + + } + mSelectLabels.removeAll(temps); + } + + /** + * 设置选中label + * + * @param positions + */ + public void setSelects(List positions) { + if (positions != null) { + int size = positions.size(); + int[] ps = new int[size]; + for (int i = 0; i < size; i++) { + ps[i] = positions.get(i); + } + setSelects(ps); + } + } + + /** + * 设置选中label + * + * @param positions + */ + public void setSelects(int... positions) { + if (mSelectType != SelectType.NONE) { + ArrayList selectLabels = new ArrayList<>(); + int count = getChildCount(); + int size = mSelectType == SelectType.SINGLE || mSelectType == SelectType.SINGLE_IRREVOCABLY + ? 1 : mMaxSelect; + for (int p : positions) { + if (p < count) { + TextView label = (TextView) getChildAt(p); + if (!selectLabels.contains(label)) { + setLabelSelect(label, true); + selectLabels.add(label); + } + if (size > 0 && selectLabels.size() == size) { + break; + } + } + } + + for (int i = 0; i < count; i++) { + TextView label = (TextView) getChildAt(i); + if (!selectLabels.contains(label)) { + setLabelSelect(label, false); + } + } + } + } + + /** + * 设置必选项,只有在多项模式下,这个方法才有效 + * + * @param positions + */ + public void setCompulsorys(List positions) { + if (mSelectType == SelectType.MULTI && positions != null) { + mCompulsorys.clear(); + mCompulsorys.addAll(positions); + //必选项发生改变,就要恢复到初始状态。 + innerClearAllSelect(); + setSelects(positions); + } + } + /** + * 获取必选项, + * + * @return + */ + public List getCompulsorys() { + return mCompulsorys; + } + /** + * 设置必选项,只有在多项模式下,这个方法才有效 + * + * @param positions + */ + public void setCompulsorys(int... positions) { + if (mSelectType == SelectType.MULTI && positions != null) { + List ps = new ArrayList<>(positions.length); + for (int i : positions) { + ps.add(i); + } + setCompulsorys(ps); + } + } + /** + * 清空必选项,只有在多项模式下,这个方法才有效 + */ + public void clearCompulsorys() { + if (mSelectType == SelectType.MULTI && !mCompulsorys.isEmpty()) { + mCompulsorys.clear(); + //必选项发生改变,就要恢复到初始状态。 + innerClearAllSelect(); + } + } + + /** + * 获取选中的label(返回的是所有选中的标签的位置) + * + * @return + */ + public List getSelectLabels() { + return mSelectLabels; + } + + /** + * 获取选中的label(返回的是所头选中的标签的数据) + * + * @param + * @return + */ + public List getSelectLabelDatas() { + List list = new ArrayList<>(); + int size = mSelectLabels.size(); + for (int i = 0; i < size; i++) { + View label = getChildAt(mSelectLabels.get(i)); + Object data = label.getTag(KEY_DATA); + if (data != null) { + list.add((T) data); + } + } + return list; + } + + /** + * 设置标签背景 + * + * @param resId + */ + public void setLabelBackgroundResource(int resId) { + setLabelBackgroundDrawable(getResources().getDrawable(resId)); + } + + /** + * 设置标签背景 + * + * @param color + */ + public void setLabelBackgroundColor(int color) { + setLabelBackgroundDrawable(new ColorDrawable(color)); + } + + /** + * 设置标签背景 + * + * @param drawable + */ + public void setLabelBackgroundDrawable(Drawable drawable) { + mLabelBg = drawable; + int count = getChildCount(); + for (int i = 0; i < count; i++) { + TextView label = (TextView) getChildAt(i); + label.setBackgroundDrawable(mLabelBg.getConstantState().newDrawable()); + } + } + + /** + * 设置标签内边距 + * + * @param left + * @param top + * @param right + * @param bottom + */ + public void setLabelTextPadding(int left, int top, int right, int bottom) { + if (mTextPaddingLeft != left || mTextPaddingTop != top + || mTextPaddingRight != right || mTextPaddingBottom != bottom) { + mTextPaddingLeft = left; + mTextPaddingTop = top; + mTextPaddingRight = right; + mTextPaddingBottom = bottom; + int count = getChildCount(); + for (int i = 0; i < count; i++) { + TextView label = (TextView) getChildAt(i); + label.setPadding(left, top, right, bottom); + } + } + } + + public int getTextPaddingLeft() { + return mTextPaddingLeft; + } + + public int getTextPaddingTop() { + return mTextPaddingTop; + } + + public int getTextPaddingRight() { + return mTextPaddingRight; + } + + public int getTextPaddingBottom() { + return mTextPaddingBottom; + } + public float getLabelTextSize() { + return mTextSize; + } + /** + * 设置标签的文字大小(单位是px) + * + * @param size + */ + public void setLabelTextSize(float size) { + if (mTextSize != size) { + mTextSize = size; + int count = getChildCount(); + for (int i = 0; i < count; i++) { + TextView label = (TextView) getChildAt(i); + label.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); + } + } + } + /** + * 设置标签的文字颜色 + * + * @param color + */ + public void setLabelTextColor(int color) { + setLabelTextColor(ColorStateList.valueOf(color)); + } + public ColorStateList getLabelTextColor() { + return mTextColor; + } + /** + * 设置标签的文字颜色 + * + * @param color + */ + public void setLabelTextColor(ColorStateList color) { + mTextColor = color; + int count = getChildCount(); + for (int i = 0; i < count; i++) { + TextView label = (TextView) getChildAt(i); + label.setTextColor(mTextColor != null ? mTextColor : ColorStateList.valueOf(0xFF000000)); + } + } + public int getLineMargin() { + return mLineMargin; + } + /** + * 设置行间隔 + */ + public void setLineMargin(int margin) { + if (mLineMargin != margin) { + mLineMargin = margin; + requestLayout(); + } + } + public int getWordMargin() { + return mWordMargin; + } + /** + * 设置标签的间隔 + */ + public void setWordMargin(int margin) { + if (mWordMargin != margin) { + mWordMargin = margin; + requestLayout(); + } + } + public SelectType getSelectType() { + return mSelectType; + } + /** + * 设置标签的选择类型 + * + * @param selectType + */ + public void setSelectType(SelectType selectType) { + if (mSelectType != selectType) { + mSelectType = selectType; + //选择类型发生改变,就要恢复到初始状态。 + innerClearAllSelect(); + + if (mSelectType == SelectType.SINGLE_IRREVOCABLY) { + setSelects(0); + } + + if (mSelectType != SelectType.MULTI) { + mCompulsorys.clear(); + } + } + } + public int getMaxSelect() { + return mMaxSelect; + } + /** + * 设置最大的选择数量 + * + * @param maxSelect + */ + public void setMaxSelect(int maxSelect) { + if (mMaxSelect != maxSelect) { + mMaxSelect = maxSelect; + if (mSelectType == SelectType.MULTI) { + //最大选择数量发生改变,就要恢复到初始状态。 + innerClearAllSelect(); + } + } + } + /** + * 设置标签的点击监听 + * + * @param l + */ + public void setOnLabelClickListener(OnLabelClickListener l) { + mLabelClickListener = l; + } + + /** + * 设置标签的选择监听 + * + * @param l + */ + public void setOnLabelSelectChangeListener(OnLabelSelectChangeListener l) { + mLabelSelectChangeListener = l; + } + public void setAddLabel(boolean visible) { + mAddVisible = visible; + } + public boolean isAddVisible() { + return mAddVisible; + } + public void setAddTextViewListener(OnClickListener listener) { + mAddTextView.setOnClickListener(listener); + } + + /** + * Label的选择类型 + */ + public enum SelectType { + //不可选中,也不响应选中事件回调。(默认) + NONE(1), + //单选,可以反选。 + SINGLE(2), + //单选,不可以反选。这种模式下,至少有一个是选中的,默认是第一个 + SINGLE_IRREVOCABLY(3), + //多选 + MULTI(4); + + int value; + + SelectType(int value) { + this.value = value; + } + + static SelectType get(int value) { + switch (value) { + case 1: + return NONE; + case 2: + return SINGLE; + case 3: + return SINGLE_IRREVOCABLY; + case 4: + return MULTI; + } + return NONE; + } + } + + public interface OnLabelClickListener { /** - * 设置必选项,只有在多项模式下,这个方法才有效 - * - * @param positions + * @param label 标签 + * @param data 标签对应的数据 + * @param position 标签位置 */ - public void setCompulsorys(List positions) { - if (mSelectType == SelectType.MULTI && positions != null) { - mCompulsorys.clear(); - mCompulsorys.addAll(positions); - //必选项发生改变,就要恢复到初始状态。 - innerClearAllSelect(); - setSelects(positions); - } - } + void onLabelClick(TextView label, Object data, int position); + } - /** - * 设置必选项,只有在多项模式下,这个方法才有效 - * - * @param positions - */ - public void setCompulsorys(int... positions) { - if (mSelectType == SelectType.MULTI && positions != null) { - List ps = new ArrayList<>(positions.length); - for (int i : positions) { - ps.add(i); - } - setCompulsorys(ps); - } - } + public interface OnLabelSelectChangeListener { /** - * 获取必选项, - * - * @return + * @param label 标签 + * @param data 标签对应的数据 + * @param isSelect 是否选中 + * @param position 标签位置 */ - public List getCompulsorys() { - return mCompulsorys; - } + void onLabelSelectChange(TextView label, Object data, boolean isSelect, int position); + } + + /** + * 给标签提供最终需要显示的数据。因为LabelsView的列表可以设置任何类型的数据,而LabelsView里的每个item的是一 + * 个TextView,只能显示CharSequence的数据,所以LabelTextProvider需要根据每个item的数据返回item最终要显示 + * 的CharSequence。 + * + * @param + */ + public interface LabelTextProvider { /** - * 清空必选项,只有在多项模式下,这个方法才有效 - */ - public void clearCompulsorys() { - if (mSelectType == SelectType.MULTI && !mCompulsorys.isEmpty()) { - mCompulsorys.clear(); - //必选项发生改变,就要恢复到初始状态。 - innerClearAllSelect(); - } - } - - /** - * 获取选中的label(返回的是所有选中的标签的位置) + * 根据data和position返回label需要需要显示的数据。 * + * @param label + * @param position + * @param data * @return */ - public List getSelectLabels() { - return mSelectLabels; - } - - /** - * 获取选中的label(返回的是所头选中的标签的数据) - * - * @param - * @return - */ - public List getSelectLabelDatas() { - List list = new ArrayList<>(); - int size = mSelectLabels.size(); - for (int i = 0; i < size; i++) { - View label = getChildAt(mSelectLabels.get(i)); - Object data = label.getTag(KEY_DATA); - if (data != null) { - list.add((T) data); - } - } - return list; - } - - /** - * 设置标签背景 - * - * @param resId - */ - public void setLabelBackgroundResource(int resId) { - setLabelBackgroundDrawable(getResources().getDrawable(resId)); - } - - /** - * 设置标签背景 - * - * @param color - */ - public void setLabelBackgroundColor(int color) { - setLabelBackgroundDrawable(new ColorDrawable(color)); - } - - /** - * 设置标签背景 - * - * @param drawable - */ - public void setLabelBackgroundDrawable(Drawable drawable) { - mLabelBg = drawable; - int count = getChildCount(); - for (int i = 0; i < count; i++) { - TextView label = (TextView) getChildAt(i); - label.setBackgroundDrawable(mLabelBg.getConstantState().newDrawable()); - } - } - - /** - * 设置标签内边距 - * - * @param left - * @param top - * @param right - * @param bottom - */ - public void setLabelTextPadding(int left, int top, int right, int bottom) { - if (mTextPaddingLeft != left || mTextPaddingTop != top - || mTextPaddingRight != right || mTextPaddingBottom != bottom) { - mTextPaddingLeft = left; - mTextPaddingTop = top; - mTextPaddingRight = right; - mTextPaddingBottom = bottom; - int count = getChildCount(); - for (int i = 0; i < count; i++) { - TextView label = (TextView) getChildAt(i); - label.setPadding(left, top, right, bottom); - } - } - } - - public int getTextPaddingLeft() { - return mTextPaddingLeft; - } - - public int getTextPaddingTop() { - return mTextPaddingTop; - } - - public int getTextPaddingRight() { - return mTextPaddingRight; - } - - public int getTextPaddingBottom() { - return mTextPaddingBottom; - } - - /** - * 设置标签的文字大小(单位是px) - * - * @param size - */ - public void setLabelTextSize(float size) { - if (mTextSize != size) { - mTextSize = size; - int count = getChildCount(); - for (int i = 0; i < count; i++) { - TextView label = (TextView) getChildAt(i); - label.setTextSize(TypedValue.COMPLEX_UNIT_PX, size); - } - } - } - - public float getLabelTextSize() { - return mTextSize; - } - - /** - * 设置标签的文字颜色 - * - * @param color - */ - public void setLabelTextColor(int color) { - setLabelTextColor(ColorStateList.valueOf(color)); - } - - /** - * 设置标签的文字颜色 - * - * @param color - */ - public void setLabelTextColor(ColorStateList color) { - mTextColor = color; - int count = getChildCount(); - for (int i = 0; i < count; i++) { - TextView label = (TextView) getChildAt(i); - label.setTextColor(mTextColor != null ? mTextColor : ColorStateList.valueOf(0xFF000000)); - } - } - - public ColorStateList getLabelTextColor() { - return mTextColor; - } - - /** - * 设置行间隔 - */ - public void setLineMargin(int margin) { - if (mLineMargin != margin) { - mLineMargin = margin; - requestLayout(); - } - } - - public int getLineMargin() { - return mLineMargin; - } - - /** - * 设置标签的间隔 - */ - public void setWordMargin(int margin) { - if (mWordMargin != margin) { - mWordMargin = margin; - requestLayout(); - } - } - - public int getWordMargin() { - return mWordMargin; - } - - /** - * 设置标签的选择类型 - * - * @param selectType - */ - public void setSelectType(SelectType selectType) { - if (mSelectType != selectType) { - mSelectType = selectType; - //选择类型发生改变,就要恢复到初始状态。 - innerClearAllSelect(); - - if (mSelectType == SelectType.SINGLE_IRREVOCABLY) { - setSelects(0); - } - - if (mSelectType != SelectType.MULTI) { - mCompulsorys.clear(); - } - } - } - - public SelectType getSelectType() { - return mSelectType; - } - - /** - * 设置最大的选择数量 - * - * @param maxSelect - */ - public void setMaxSelect(int maxSelect) { - if (mMaxSelect != maxSelect) { - mMaxSelect = maxSelect; - if (mSelectType == SelectType.MULTI) { - //最大选择数量发生改变,就要恢复到初始状态。 - innerClearAllSelect(); - } - } - } - - public int getMaxSelect() { - return mMaxSelect; - } - - /** - * 设置标签的点击监听 - * - * @param l - */ - public void setOnLabelClickListener(OnLabelClickListener l) { - mLabelClickListener = l; - } - - /** - * 设置标签的选择监听 - * - * @param l - */ - public void setOnLabelSelectChangeListener(OnLabelSelectChangeListener l) { - mLabelSelectChangeListener = l; - } - - /** - * sp转px - */ - public static int sp2px(Context context, float spVal) { - return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, - spVal, context.getResources().getDisplayMetrics()); - } - - public interface OnLabelClickListener { - - /** - * @param label 标签 - * @param data 标签对应的数据 - * @param position 标签位置 - */ - void onLabelClick(TextView label, Object data, int position); - } - - public interface OnLabelSelectChangeListener { - - /** - * @param label 标签 - * @param data 标签对应的数据 - * @param isSelect 是否选中 - * @param position 标签位置 - */ - void onLabelSelectChange(TextView label, Object data, boolean isSelect, int position); - } - - /** - * 给标签提供最终需要显示的数据。因为LabelsView的列表可以设置任何类型的数据,而LabelsView里的每个item的是一 - * 个TextView,只能显示CharSequence的数据,所以LabelTextProvider需要根据每个item的数据返回item最终要显示 - * 的CharSequence。 - * - * @param - */ - public interface LabelTextProvider { - - /** - * 根据data和position返回label需要需要显示的数据。 - * - * @param label - * @param position - * @param data - * @return - */ - CharSequence getLabelText(TextView label, int position, T data); - } + CharSequence getLabelText(TextView label, int position, T data); + } } diff --git a/labels/src/main/res/values/attr.xml b/labels/src/main/res/values/attr.xml index ea58d65..8bb5678 100644 --- a/labels/src/main/res/values/attr.xml +++ b/labels/src/main/res/values/attr.xml @@ -1,6 +1,6 @@ - + @@ -17,5 +17,6 @@ +