Android中标签TagLayout支持单选多选,首先给出主要类继承了ViewGroup。

public class TagLayout extends ViewGroup {

private static final int DEFAULT_TAG_RES_ID = R.layout.item_tag;

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 int mTagSelectMode = SELECT_MODE_NONE;

private Integer mTagTextSize;

private int mTagResId = DEFAULT_TAG_RES_ID;

private List mTagLines = new ArrayList<>();

private int mHorizontalSpace = 0;

private int mVerticalSpace = 0;

private int maxLines = Integer.MAX_VALUE;

private List mTags;

private LayoutInflater mInflater;

private Integer mTagBackground;

private Integer mTagMinWidth;

private ColorStateList mTagTextColor;

private Integer mTagTextHorizontalPadding;

private Integer mTagTextVerticalPadding;

private static final int DEFAULT_CACHE_LINES = 3;

private TextView mCurrentSelected;

private boolean mHasMeasured = false;

private int mLastWidthMeasureSpec;

private int mLastHeightMeasureSpec;

private int mLastMeasureWidth;

private int mLstMeasureHeight;

public interface OnSelectChangeListener {

void onSelectChange(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);

mTagResId = a.getResourceId(R.styleable.TagLayout_tagResId, DEFAULT_TAG_RES_ID);

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 (maxLines <= DEFAULT_CACHE_LINES) {

int maxWidth = ViewUtils.getDisplayWidth();

for (int i = 0; i < maxLines; i++) {

int totalChildSizeWidth = 0;

while (totalChildSizeWidth < maxLines) {

TextView tagView = addTag(" ");

tagView.measure(MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST));

tagView.setVisibility(View.INVISIBLE);

totalChildSizeWidth += tagView.getMeasuredWidth() + mHorizontalSpace;

}

}

}

}

private TextView addTag(final String tagText) {

final TextView tagView = (TextView) mInflater.inflate(mTagResId, null);

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) {

tagView.setSelected(!tagView.isSelected());

if (onSelectChangeListener != null) {

onSelectChangeListener.onSelectChange(tagView, position, tagView.isSelected());

}

} else if (mTagSelectMode == SELECT_MODE_SINGLE) {

if (mCurrentSelected != null) {

mCurrentSelected.setSelected(false);

}

tagView.setSelected(true);

mCurrentSelected = tagView;

if (onSelectChangeListener != null) {

onSelectChangeListener.onSelectChange(tagView, position, tagView.isSelected());

}

}

}

});

addView(tagView);

return tagView;

}

private boolean hasValue(Object value) {

return value != null;

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int parentSuggestWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);

if (mHasMeasured && mLastWidthMeasureSpec == widthMeasureSpec && mLastHeightMeasureSpec == heightMeasureSpec) {

setMeasuredDimension(mLastMeasureWidth, mLstMeasureHeight);

return;

}

mTagLines.clear();

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);

tagLine.addView(child);

} else {

if (tagLine.accept(child)) {

tagLine.addView(child);

} else {

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;

}

public void setTags(List tagsList) {

mHasMeasured = false;

if (this.mTags == tagsList) {

return;

}

if (maxLines <= DEFAULT_CACHE_LINES || tagsList.size() <= getChildCount()) {//使用缓存

for (int i = 0; i < getChildCount(); i++) {

TextView tagView = (TextView) getChildAt(i);

tagView.setVisibility(View.GONE);

}

if (tagsList != null && tagsList.size() > 0) {

int visibleChildCount = Math.min(tagsList.size(), getChildCount());

for (int i = 0; i < visibleChildCount; i++) {

TextView tagView = (TextView) getChildAt(i);

tagView.setVisibility(View.VISIBLE);

final String tagText = tagsList.get(i);

tagView.setText(tagText);

}

}

} else {//删除 再添加

if (mTags != null && mTags.size() > 0) {

mTags.clear();

}

removeAllViews();

if (tagsList != null && tagsList.size() > 0) {

for (int i = 0; i < tagsList.size(); i++) {

addTag(tagsList.get(i));

}

}

}

}

public List getSelectedTagPositions() {

List 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;

}

@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;

}

}

public class TagLine {

private List 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;

}

}

}

}

List tags = new ArrayList<>();

for (GDCommonItem item : items) {

tags.add(item.getRealValue());

}

sexualTags.setTags(tags);

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐