概述
首先给出主控件主要代码
public class TagLayout extends ViewGroup {
private static final String INSTANCE_STATE = "saved_instance";
private static final String TAGS = "tags";
private static final String SELECTED_TAG_POSITIONS = "selected_tag_positions";
private static final int SELECT_MODE_NONE = 0;
private static final int SELECT_MODE_SINGLE = 1;
private static final int SELECT_MODE_MULTIPLE = 2;
private static final int CACHE_MODE_AUTO = 0;
private static final int CACHE_MODE_LAZY = 1;
private static final int CACHE_MODE_NONE = 2;
private static final int LINES_CACHE_COUNT = 10;
public static final int MAX_PRE_CACHE_COUNT = 30;
private static final String DEFAULT_TEXT = "";
private int mTagSelectMode = SELECT_MODE_NONE;
private Integer mTagTextSize;
private Integer mTagResId;
private List<TagLine> mTagLines = new ArrayList<>();
private int mHorizontalSpace = 0;
private int mVerticalSpace = 0;
private int maxLines = Integer.MAX_VALUE;
private int mMaximumSelectionCount = Integer.MAX_VALUE;
private List<String> mTags;
private LayoutInflater mInflater;
private Integer mTagBackground;
private Integer mTagMinWidth;
private ColorStateList mTagTextColor;
private Integer mTagTextHorizontalPadding;
private Integer mTagTextVerticalPadding;
//
private int mCacheMode;
private int mMaxTags;
private boolean mUsePreCache = false;
private TextView mCurrentSelected;
private boolean mHasMeasured = false;
private int mLastWidthMeasureSpec;
private int mLastHeightMeasureSpec;
private int mLastMeasureWidth;
private int mLstMeasureHeight;
private int mSelectedChildCount;
public List<String> getTags() {
return mTags;
}
public interface OnSelectChangeListener {
void onSelectChange(TagLayout parent, TextView child, int index, boolean isSelected);
}
public interface OnItemClickListener {
void onItemClick(TextView child, int index);
}
private OnSelectChangeListener onSelectChangeListener;
private OnItemClickListener onItemClickListener;
public void setOnSelectChangeListener(OnSelectChangeListener onSelectChangeListener) {
this.onSelectChangeListener = onSelectChangeListener;
}
public void setOnItemClickListener(OnItemClickListener onItemClickListener) {
this.onItemClickListener = onItemClickListener;
}
public TagLayout(Context context) {
super(context);
mInflater = LayoutInflater.from(context);
}
public TagLayout(Context context, AttributeSet attrs) {
super(context, attrs);
mInflater = LayoutInflater.from(context);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TagLayout);
if (a != null) {
mHorizontalSpace = a.getDimensionPixelOffset(R.styleable.TagLayout_horizontalSpace, 0);
mVerticalSpace = a.getDimensionPixelOffset(R.styleable.TagLayout_verticalSpace, 0);
maxLines = a.getInteger(R.styleable.TagLayout_maxLines, Integer.MAX_VALUE);
mUsePreCache = a.getBoolean(R.styleable.TagLayout_preCache, false);
mMaximumSelectionCount = a.getInteger(R.styleable.TagLayout_maximumSelectionCount, Integer.MAX_VALUE);
mCacheMode = a.getInt(R.styleable.TagLayout_cacheMode, CACHE_MODE_AUTO);
mMaxTags = a.getInteger(R.styleable.TagLayout_maxTags, Integer.MAX_VALUE);
if (a.hasValue(R.styleable.TagLayout_tagResId)) {
mTagResId = a.getResourceId(R.styleable.TagLayout_tagResId, -1);
}
if (a.hasValue(R.styleable.TagLayout_tagTextSize)) {
mTagTextSize = a.getDimensionPixelSize(R.styleable.TagLayout_tagTextSize, 0);
}
if (a.hasValue(R.styleable.TagLayout_tagBackground)) {
mTagBackground = a.getResourceId(R.styleable.TagLayout_tagBackground, -1);
}
if (a.hasValue(R.styleable.TagLayout_tagTextColor)) {
mTagTextColor = a.getColorStateList(R.styleable.TagLayout_tagTextColor);
}
if (a.hasValue(R.styleable.TagLayout_tagTextHorizontalPadding)) {
mTagTextHorizontalPadding = a.getDimensionPixelOffset(R.styleable.TagLayout_tagTextHorizontalPadding, 0);
}
if (a.hasValue(R.styleable.TagLayout_tagTextVerticalPadding)) {
mTagTextVerticalPadding = a.getDimensionPixelOffset(R.styleable.TagLayout_tagTextVerticalPadding, 0);
}
if (a.hasValue(R.styleable.TagLayout_tagSelectMode)) {
mTagSelectMode = a.getInt(R.styleable.TagLayout_tagSelectMode, SELECT_MODE_NONE);
}
if (a.hasValue(R.styleable.TagLayout_tagMinWidth)) {
mTagMinWidth = a.getDimensionPixelOffset(R.styleable.TagLayout_tagMinWidth, 0);
}
a.recycle();
}
if (mUsePreCache) {
int count = Math.min(MAX_PRE_CACHE_COUNT, Math.min(mMaxTags, maxLines * LINES_CACHE_COUNT));
for (int i = 0; i < count; i++) {
TextView tagView = addTag(DEFAULT_TEXT);
tagView.setVisibility(View.INVISIBLE);
}
}
}
private TextView addTag(final String tagText) {
TextView addedTag;
if (mTagResId != null) {
addedTag = (TextView) mInflater.inflate(mTagResId, null);
} else {
addedTag = new TextView(getContext());
addedTag.setGravity(Gravity.CENTER);
}
final TextView tagView = addedTag;
if (hasValue(mTagBackground)) {
tagView.setBackgroundResource(mTagBackground);
}
if (hasValue(mTagTextSize)) {
tagView.setTextSize(TypedValue.COMPLEX_UNIT_PX, mTagTextSize);
}
if (hasValue(mTagTextColor)) {
tagView.setTextColor(mTagTextColor);
}
if (hasValue(mTagMinWidth)) {
tagView.setMinWidth(mTagMinWidth);
}
int paddingLeft = tagView.getPaddingLeft();
int paddingRight = tagView.getPaddingRight();
int paddingTop = tagView.getPaddingTop();
int paddingBottom = tagView.getPaddingBottom();
if (hasValue(mTagTextHorizontalPadding)) {
paddingLeft = mTagTextHorizontalPadding;
paddingRight = mTagTextHorizontalPadding;
}
if (hasValue(mTagTextVerticalPadding)) {
paddingTop = mTagTextVerticalPadding;
paddingBottom = mTagTextVerticalPadding;
}
tagView.setPadding(paddingLeft, paddingTop, paddingRight, paddingBottom);
tagView.setText(tagText);
final int position = getChildCount();
tagView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (tagView.getVisibility() != View.VISIBLE)
return;
if (onItemClickListener != null) {
onItemClickListener.onItemClick(tagView, position);
}
if (mTagSelectMode == SELECT_MODE_MULTIPLE) {
if (mSelectedChildCount >= mMaximumSelectionCount && !tagView.isSelected()) {
return;
}
tagView.setSelected(!tagView.isSelected());
if (tagView.isSelected()) {
mSelectedChildCount++;
} else {
mSelectedChildCount--;
}
if (onSelectChangeListener != null) {
onSelectChangeListener.onSelectChange(TagLayout.this, tagView, position, tagView.isSelected());
}
} else if (mTagSelectMode == SELECT_MODE_SINGLE) {
if (mCurrentSelected != null) {
mCurrentSelected.setSelected(false);
}
tagView.setSelected(true);
mSelectedChildCount = 1;
mCurrentSelected = tagView;
if (onSelectChangeListener != null) {
onSelectChangeListener.onSelectChange(TagLayout.this, tagView, position, tagView.isSelected());
}
}
}
});
addView(tagView);
return tagView;
}
private boolean hasValue(Object value) {
return value != null;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mHasMeasured && mLastWidthMeasureSpec == widthMeasureSpec && mLastHeightMeasureSpec == heightMeasureSpec) {
setMeasuredDimension(mLastMeasureWidth, mLstMeasureHeight);
return;
}
mTagLines.clear();
int parentSuggestWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
TagLine tagLine = null;
int maxWidth = parentSuggestWidth - getPaddingLeft() - getPaddingRight();
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
if (child.getVisibility() == View.GONE) {
continue;
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
if (tagLine == null) {
tagLine = newTagLine(maxWidth);
} else {
if (!tagLine.accept(child)) {
if (mTagLines.size() == maxLines) {
for (int hiddenIndex = i; hiddenIndex < getChildCount(); hiddenIndex++) {
getChildAt(hiddenIndex).setVisibility(View.GONE);
}
break;
}
tagLine = newTagLine(maxWidth);
}
}
tagLine.addView(child);
}
int measureHeight = getPaddingTop() + getPaddingBottom();
for (int i = 0; i < mTagLines.size(); i++) {
measureHeight += mTagLines.get(i).height;
if (i != mTagLines.size() - 1) {
measureHeight += mVerticalSpace;
}
}
setMeasuredDimension(mLastMeasureWidth = parentSuggestWidth, mLstMeasureHeight = resolveSize(measureHeight, heightMeasureSpec));
mLastWidthMeasureSpec = widthMeasureSpec;
mLastHeightMeasureSpec = heightMeasureSpec;
mHasMeasured = true;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int marginTop = getPaddingTop();
int marginLeft = getPaddingLeft();
for (int i = 0; i < mTagLines.size(); i++) {
TagLine line = mTagLines.get(i);
line.layout(marginLeft, marginTop);
marginTop += mVerticalSpace + line.height;
}
}
@Override
protected Parcelable onSaveInstanceState() {
final Bundle bundle = new Bundle();
bundle.putParcelable(INSTANCE_STATE, super.onSaveInstanceState());
if (mTags != null) {
bundle.putStringArrayList(TAGS, wrap(mTags));
}
List<Integer> selectedPositions = getSelectedTagPositions();
if (selectedPositions != null) {
bundle.putIntegerArrayList(SELECTED_TAG_POSITIONS, wrap(selectedPositions));
}
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state) {
if (state instanceof Bundle) {
Bundle bundle = (Bundle) state;
mTags = bundle.getStringArrayList(TAGS);
List<Integer> selectedTagPositions = bundle.getIntegerArrayList(SELECTED_TAG_POSITIONS);
if (selectedTagPositions != null && selectedTagPositions.size() > 0) {
if (getChildCount() > selectedTagPositions.size()) {
if (mTagSelectMode == SELECT_MODE_MULTIPLE) {
selectTagPositions(selectedTagPositions);
} else if (selectedTagPositions.size() > 0) {
selectTagPosition(selectedTagPositions.get(0));
}
}
}
super.onRestoreInstanceState(bundle.getParcelable(INSTANCE_STATE));
} else {
super.onRestoreInstanceState(state);
}
}
public interface TagTextConverter<T> {
String convert(T t);
}
public <T> void setTagObjects(List<T> tagObjects, TagTextConverter<T> tagTextConverter) {
setTagObjects(tagObjects, tagTextConverter, null);
}
public <T> void setTagObjects(List<T> tagObjects, TagTextConverter<T> tagTextConverter, ViewCreatedCallback viewCreatedCallback) {
List<String> tagsList = new ArrayList<>();
for (T tagObject : tagObjects) {
tagsList.add(tagTextConverter.convert(tagObject).trim());
}
setTags(tagsList, viewCreatedCallback);
}
public void setTags(String... tagsList) {
if (tagsList != null && tagsList.length > 0) {
setTags(Arrays.asList(tagsList));
}
}
public interface ViewCreatedCallback {
void onViewCreated(int position, TextView textView);
}
public void setTags(List<String> tagsList) {
setTags(tagsList, null);
}
public void setTags(List<String> tagsList, ViewCreatedCallback viewCreatedCallback) {
mHasMeasured = false;
if (this.mTags == tagsList) {
return;
}
if (mCacheMode != CACHE_MODE_NONE) {//使用缓存
int maxDisplayTags = Math.min(tagsList == null ? 0 : tagsList.size(), mMaxTags);
int childCount = getChildCount();
int availableCount = Math.min(maxDisplayTags, childCount);
if (availableCount > 0) {
for (int i = 0; i < availableCount; i++) {
TextView tagView = (TextView) getChildAt(i);
tagView.setVisibility(View.VISIBLE);
String tagText = tagsList.get(i);
tagView.setText(tagText);
if (viewCreatedCallback != null) {
viewCreatedCallback.onViewCreated(i, tagView);
}
}
}
if (childCount > maxDisplayTags) {
List<View> removedViews = null;
for (int i = availableCount; i < childCount; i++) {
TextView tagView = (TextView) getChildAt(i);
if (mCacheMode == CACHE_MODE_LAZY) {
tagView.setVisibility(View.GONE);
} else {
if (removedViews == null) {
removedViews = new ArrayList<>();
}
removedViews.add(tagView);
}
}
if (removedViews != null) {
for (View child : removedViews) {
removeView(child);
}
removedViews.clear();
}
} else if (childCount < maxDisplayTags) {
int addedCount = maxDisplayTags - childCount;
for (int i = 0; i < addedCount; i++) {
String tagText = tagsList.get(i + childCount);
TextView tag = addTag(tagText);
if (viewCreatedCallback != null) {
viewCreatedCallback.onViewCreated(i + childCount, tag);
}
}
}
} else {//删除 再添加
removeAllViews();
if (tagsList != null && tagsList.size() > 0) {
for (int i = 0; i < tagsList.size(); i++) {
TextView tv = addTag(tagsList.get(i));
if (viewCreatedCallback != null) {
viewCreatedCallback.onViewCreated(i, tv);
}
}
}
}
this.mTags = tagsList;
}
private static <T> ArrayList<T> wrap(List<T> list) {
if (list instanceof ArrayList) {
return (ArrayList<T>) list;
} else {
return new ArrayList(list);
}
}
public void selectTagPositions(Integer... selectedPos) {
selectTagPositions(Arrays.asList(selectedPos));
}
public void selectTagPositions(List<Integer> selectedPos) {
if (mTagSelectMode != SELECT_MODE_MULTIPLE) {
throw new UnsupportedOperationException("this method only support in SELECT_MODE_MULTIPLE!");
}
int childCount = getChildCount();
int selectedCount = 0;
for (int i = 0; i < childCount; i++) {
if (selectedPos.contains(i)) {
getChildAt(i).setSelected(true);
selectedCount++;
} else {
getChildAt(i).setSelected(false);
}
}
mSelectedChildCount = selectedCount;
}
public void selectTagPosition(int index) {
if (mTagSelectMode != SELECT_MODE_SINGLE) {
throw new UnsupportedOperationException("this method only support in SELECT_MODE_SINGLE!");
}
TextView tagView = (TextView) getChildAt(index);
if (mCurrentSelected != tagView) {
if (mCurrentSelected != null) {
mCurrentSelected.setSelected(false);
}
mCurrentSelected = tagView;
mCurrentSelected.setSelected(true);
mSelectedChildCount = 1;
}
}
public void setMaximumSelectionCount(int maximumSelectionCount) {
this.mMaximumSelectionCount = maximumSelectionCount;
}
public int getSelectedTagPosition() {
if (mTagSelectMode == SELECT_MODE_SINGLE && mCurrentSelected != null) {
return indexOfChild(mCurrentSelected);
}
return -1;
}
public String getSelectedTag() {
int pos = getSelectedTagPosition();
if (pos != -1) {
return mTags.get(pos);
}
return null;
}
public List<Integer> getSelectedTagPositions() {
List<Integer> selectedList = new ArrayList<>();
if (mTagSelectMode == SELECT_MODE_SINGLE && mCurrentSelected != null) {
selectedList.add(indexOfChild(mCurrentSelected));
} else {
for (int i = 0; i < getChildCount(); i++) {
if (getChildAt(i).getVisibility() == View.VISIBLE && getChildAt(i).isSelected()) {
selectedList.add(i);
}
}
}
return selectedList;
}
private TagLine newTagLine(int maxWidth) {
TagLine tagLine = new TagLine(maxWidth, mHorizontalSpace);
mTagLines.add(tagLine);
return tagLine;
}
public class TagLine {
private List<View> mTagViews = new ArrayList<>();
private int totalWidth;
private int space;
private int usedWidth;
private int height;
public TagLine(int totalWidth, int horizontalSpace) {
this.totalWidth = totalWidth;
this.space = horizontalSpace;
}
public void addView(View child) {
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
if (mTagViews.size() == 0) {
if (childWidth > totalWidth) {
usedWidth = totalWidth;
height = childHeight;
} else {
usedWidth = childWidth;
height = childHeight;
}
} else {
usedWidth = usedWidth + space + childWidth;
height = (childHeight > height) ? childHeight : height;
}
mTagViews.add(child);
}
public boolean accept(View child) {
int width = child.getMeasuredWidth();
if (mTagViews.size() == 0) {
return true;
}
if (usedWidth + width + space > totalWidth) {
return false;
}
return true;
}
public void layout(int marginLeft, int marginTop) {
for (int i = 0; i < mTagViews.size(); i++) {
View child = mTagViews.get(i);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
int extraTop = (int) ((height - childHeight) / 2f + 0.5f);
int left = marginLeft;
int top = marginTop + extraTop;
int right = left + childWidth;
int bottom = top + childHeight;
child.layout(left, top, right, bottom);
marginLeft += childWidth + space;
}
}
}
}
然后在自定义的attrs.xml中增加
<attr name="horizontalSpace" format="dimension" /><!-- tag之间的横向间距-->
<attr name="verticalSpace" format="dimension" /><!-- tag之间的纵向间距-->
<attr name="tagResId" format="reference" /><!-- tag自定义布局的资源id-->
<attr name="tagTextSize" format="dimension" /><!-- tag文字大小-->
<attr name="tagBackground" format="reference" /><!-- tag背景-->
<attr name="tagMinWidth" format="dimension" /><!-- tag最小宽度-->
<attr name="tagTextColor" format="color" /><!-- tag文字颜色-->
<attr name="tagTextHorizontalPadding" format="dimension" /><!-- tag 内部横向padding-->
<attr name="tagTextVerticalPadding" format="dimension" /><!-- tag 内部纵向padding-->
<declare-styleable name="TagLayout">
<attr name="horizontalSpace" />
<attr name="verticalSpace" />
<attr name="tagResId" />
<attr name="tagTextSize" />
<attr name="tagBackground" />
<attr name="tagMinWidth" />
<attr name="tagTextColor" />
<attr name="tagTextHorizontalPadding" />
<attr name="tagTextVerticalPadding" />
<attr name="maxLines" format="integer" /><!-- 最大行数-->
<attr name="maximumSelectionCount" format="integer" /><!-- 设置最多能够选择的个数-->
<attr name="tagSelectMode" format="enum"><!-- 单选 多选-->
<enum name="single" value="1"></enum><!--单选-->
<enum name="multiple" value="2"></enum><!--多选-->
<enum name="none" value="0"></enum><!--不可选-->
</attr>
<!--以下配置建议在列表中提高性能使用-->
<attr name="cacheMode" format="enum"><!-- 缓存方式,常用方式下没有影响,当tag需要在RecycleView或者ListView中显示,合理设置能显著提高性能-->
<enum name="auto" value="0"></enum><!--自动根据当前tag数量来增删childView,默认方式-->
<enum name="lazy" value="1"></enum><!--tag数量会根据最大tag数量来决定,大于会等于tag数量的childView自动隐藏,性能最佳-->
<enum name="none" value="2"></enum><!--不使用缓存-->
</attr>
<attr name="maxTags" format="integer" /><!--tags最大数量-->
<attr name="preCache" format="boolean" /><!-- 预缓存,初始化时预先添加一定数量的childView-->
</declare-styleable>
通过上面的<declare-styleable name="TagLayout">很容易看出来用法下面就是布局中的用法
<com.xxx.xxxx.widget.TagLayout
android:id="@+id/tagLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/w14"
android:layout_marginTop="@dimen/w6"
android:layout_marginRight="@dimen/w15"
app:horizontalSpace="@dimen/w10"
app:layout_constraintLeft_toRightOf="@id/img_content"
app:layout_constraintRight_toLeftOf="@id/tvMoney"
app:layout_constraintTop_toBottomOf="@id/tvStage"
app:tagBackground="@drawable/bg_guild_tag_red_r20"
app:tagSelectMode="single"
app:tagTextHorizontalPadding="@dimen/w8"
app:tagTextSize="@dimen/sp11"
app:tagTextVerticalPadding="@dimen/w2"
app:verticalSpace="@dimen/w10" />
可以看到app开头的都是在attrs.xml中定义的了 所以自己加什么属性 可以更具项目自己配置
上面是整个TagLayout 的代码
············································································
下面就是整个Taglayout的在Activity中的使用
tagLayout.setTagObjects(label, topicInfo -> topicInfo, (position, textView) -> {
textView.setPadding(4, 1, 4, 1);
if (position % 2 == 0) {
textView.setBackgroundResource(R.drawable.bg_search_tag_fe784b_10_r20);
textView.setTextColor(getContext().getResources().getColor(R.color.color_FE784B));
} else {
textView.setBackgroundResource(R.drawable.bg_search_tag_10_r20);
textView.setTextColor(getContext().getResources().getColor(R.color.color_13C5CD));
}
});
上面的代码就是你所选中的文字 还有很多需要自己看
最后
以上就是贪玩小伙为你收集整理的Android中标签TagLayout支持单选多选的全部内容,希望文章能够帮你解决Android中标签TagLayout支持单选多选所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复