本篇文章帮助大家实现如下标签效果,有不足的地方欢迎大家私信我。下面来看一下效果:
1:这个效果类似于通过筛选获取对应评论数据
1:此功能的实现是基于Android TagFlowLayout完全解析 一款针对Tag的布局_Hongyang-CSDN博客
这个实现的,又不懂的大家可以看下,我把源码贴一下:
public class MyFlowLayout extends ViewGroup
{
private static final String TAG = "FlowLayout";
private static final int LEFT = -1;
private static final int CENTER = 0;
private static final int RIGHT = 1;
protected List<List<View>> mAllViews = new ArrayList<List<View>>();
protected List<Integer> mLineHeight = new ArrayList<Integer>();
protected List<Integer> mLineWidth = new ArrayList<Integer>();
private int mGravity;
private List<View> lineViews = new ArrayList<>();
public MyFlowLayout(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);
mGravity = ta.getInt(R.styleable.TagFlowLayout_gravity,LEFT);
ta.recycle();
}
public MyFlowLayout(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public MyFlowLayout(Context context)
{
this(context, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int modeWidth = MeasureSpec.getMode(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
int modeHeight = MeasureSpec.getMode(heightMeasureSpec);
// wrap_content
int width = 0;
int height = 0;
int lineWidth = 0;
int lineHeight = 0;
int cCount = getChildCount();
for (int i = 0; i < cCount; i++)
{
View child = getChildAt(i);
if (child.getVisibility() == View.GONE)
{
if (i == cCount - 1)
{
width = Math.max(lineWidth, width);
height += lineHeight;
}
continue;
}
measureChild(child, widthMeasureSpec, heightMeasureSpec);
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int childWidth = child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
int childHeight = child.getMeasuredHeight() + lp.topMargin
+ lp.bottomMargin;
if (lineWidth + childWidth > sizeWidth - getPaddingLeft() - getPaddingRight())
{
width = Math.max(width, lineWidth);
lineWidth = childWidth;
height += lineHeight;
lineHeight = childHeight;
} else
{
lineWidth += childWidth;
lineHeight = Math.max(lineHeight, childHeight);
}
if (i == cCount - 1)
{
width = Math.max(lineWidth, width);
height += lineHeight;
}
}
setMeasuredDimension(
//
modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width + getPaddingLeft() + getPaddingRight(),
modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height + getPaddingTop() + getPaddingBottom()//
);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b)
{
mAllViews.clear();
mLineHeight.clear();
mLineWidth.clear();
lineViews.clear();
int width = getWidth();
int lineWidth = 0;
int lineHeight = 0;
int cCount = getChildCount();
for (int i = 0; i < cCount; i++)
{
View child = getChildAt(i);
if (child.getVisibility() == View.GONE) continue;
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
if (childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width - getPaddingLeft() - getPaddingRight())
{
mLineHeight.add(lineHeight);
mAllViews.add(lineViews);
mLineWidth.add(lineWidth);
lineWidth = 0;
lineHeight = childHeight + lp.topMargin + lp.bottomMargin;
lineViews = new ArrayList<View>();
}
lineWidth += childWidth + lp.leftMargin + lp.rightMargin;
lineHeight = Math.max(lineHeight, childHeight + lp.topMargin
+ lp.bottomMargin);
lineViews.add(child);
}
mLineHeight.add(lineHeight);
mLineWidth.add(lineWidth);
mAllViews.add(lineViews);
int left = getPaddingLeft();
int top = getPaddingTop();
int lineNum = mAllViews.size();
for (int i = 0; i < lineNum; i++)
{
lineViews = mAllViews.get(i);
lineHeight = mLineHeight.get(i);
// set gravity
int currentLineWidth = this.mLineWidth.get(i);
switch (this.mGravity){
case LEFT:
left = getPaddingLeft();
break;
case CENTER:
left = (width - currentLineWidth)/2+getPaddingLeft();
break;
case RIGHT:
left = width - currentLineWidth + getPaddingLeft();
break;
}
for (int j = 0; j < lineViews.size(); j++)
{
View child = lineViews.get(j);
if (child.getVisibility() == View.GONE)
{
continue;
}
MarginLayoutParams lp = (MarginLayoutParams) child
.getLayoutParams();
int lc = left + lp.leftMargin;
int tc = top + lp.topMargin;
int rc = lc + child.getMeasuredWidth();
int bc = tc + child.getMeasuredHeight();
child.layout(lc, tc, rc, bc);
left += child.getMeasuredWidth() + lp.leftMargin
+ lp.rightMargin;
}
top += lineHeight;
}
}
@Override
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs)
{
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected LayoutParams generateDefaultLayoutParams()
{
return new MarginLayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
}
@Override
protected LayoutParams generateLayoutParams(LayoutParams p)
{
return new MarginLayoutParams(p);
}
}
<declare-styleable name="TagFlowLayout">
<attr name="auto_select_effect" format="boolean" />
<attr name="max_select" format="integer" />
<attr name="gravity">
<enum name="left" value="-1" />
<enum name="center" value="0" />
<enum name="right" value="1" />
</attr>
</declare-styleable>
public abstract class MyTagAdapter<T> {
private List<T> mTagDatas;
private MyTagAdapter.OnDataChangedListener mOnDataChangedListener;
private HashSet<Integer> mCheckedPosList = new HashSet<Integer>();
public MyTagAdapter(List<T> datas) {
mTagDatas = datas;
}
public MyTagAdapter(T[] datas)
{
mTagDatas = new ArrayList<T>(Arrays.asList(datas));
}
static interface OnDataChangedListener
{
void onChanged();
}
void setOnDataChangedListener(OnDataChangedListener listener)
{
mOnDataChangedListener = listener;
}
@Deprecated
public void setSelectedList(int... poses) {
Set<Integer> set = new HashSet<>();
for (int pos : poses) {
set.add(pos);
}
setSelectedList(set);
}
public void setSelectedList(Set<Integer> set)
{
mCheckedPosList.clear();
if (set != null)
mCheckedPosList.addAll(set);
notifyDataChanged();
}
HashSet<Integer> getPreCheckedList()
{
return mCheckedPosList;
}
public int getCount()
{
return mTagDatas == null ? 0 : mTagDatas.size();
}
public void notifyDataChanged()
{
if (mOnDataChangedListener != null)
mOnDataChangedListener.onChanged();
}
public T getItem(int position)
{
return mTagDatas.get(position);
}
public abstract View getView(MyFlowLayout parent, int position, T t, int i);
public void onSelected(int position, View view){
Log.d("zhy","onSelected " + position);
}
public void unSelected(int position, View view){
Log.d("zhy","unSelected " + position);
}
public boolean setSelected(int position, T t)
{
return false;
}
}
public class MyTagFlowLayout extends MyFlowLayout implements MyTagAdapter.OnDataChangedListener
{
private MyTagAdapter mTagAdapter;
private boolean mAutoSelectEffect = true;
private int mSelectedMax = -1;//-1为不限制数量
private static final String TAG = "MyTagFlowLayout";
private MotionEvent mMotionEvent;
private Set<Integer> mSelectedView = new HashSet<Integer>();
private MyTagFlowLayout.OnSelectListener mOnSelectListener;
private MyTagFlowLayout.OnTagClickListener mOnTagClickListener;
private MyTagFlowLayout.OnTagClickListener2 mOnTagClickListener2;
/**
* 0 : 正常的 1 :为了评论那里写的
*/
public int type = 0;
public interface OnSelectListener
{
void onSelected(Set<Integer> selectPosSet);
}
public interface OnTagClickListener
{
boolean onTagClick(View view, int position, MyFlowLayout parent);
}
public interface OnTagClickListener2
{
boolean onTagClick(View view, int position, MyFlowLayout parent);
}
public MyTagFlowLayout(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.TagFlowLayout);
mAutoSelectEffect = ta.getBoolean(R.styleable.TagFlowLayout_auto_select_effect, true);
mSelectedMax = ta.getInt(R.styleable.TagFlowLayout_max_select, -1);
ta.recycle();
if (mAutoSelectEffect)
{
setClickable(true);
}
}
public MyTagFlowLayout(Context context, AttributeSet attrs)
{
this(context, attrs, 0);
}
public MyTagFlowLayout(Context context)
{
this(context, null);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
{
int cCount = getChildCount();
for (int i = 0; i < cCount; i++)
{
MyTagView tagView = (MyTagView) getChildAt(i);
if (tagView.getVisibility() == View.GONE) continue;
if (tagView.getTagView().getVisibility() == View.GONE)
{
tagView.setVisibility(View.GONE);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void setOnSelectListener(MyTagFlowLayout.OnSelectListener onSelectListener)
{
mOnSelectListener = onSelectListener;
if (mOnSelectListener != null) setClickable(true);
}
public void setOnTagClickListener(MyTagFlowLayout.OnTagClickListener onTagClickListener)
{
mOnTagClickListener = onTagClickListener;
if (onTagClickListener != null) setClickable(true);
}
public void setOnTagClickListener(MyTagFlowLayout.OnTagClickListener2 onTagClickListener)
{
mOnTagClickListener2 = onTagClickListener;
if (onTagClickListener != null) setClickable(true);
}
public void setAdapter(MyTagAdapter adapter)
{
//if (mTagAdapter == adapter)
// return;
mTagAdapter = adapter;
mTagAdapter.setOnDataChangedListener(this);
mSelectedView.clear();
changeAdapter(0);
}
private void changeAdapter(int po)
{
removeAllViews();
MyTagAdapter adapter = mTagAdapter;
MyTagView tagViewContainer = null;
HashSet preCheckedList = mTagAdapter.getPreCheckedList();
for (int i = 0; i < adapter.getCount(); i++)
{
View tagView = adapter.getView(this, i, adapter.getItem(i),po);
tagViewContainer = new MyTagView(getContext());
// ViewGroup.MarginLayoutParams clp = (ViewGroup.MarginLayoutParams) tagView.getLayoutParams();
// ViewGroup.MarginLayoutParams lp = new ViewGroup.MarginLayoutParams(clp);
// lp.width = ViewGroup.LayoutParams.WRAP_CONTENT;
// lp.height = ViewGroup.LayoutParams.WRAP_CONTENT;
// lp.topMargin = clp.topMargin;
// lp.bottomMargin = clp.bottomMargin;
// lp.leftMargin = clp.leftMargin;
// lp.rightMargin = clp.rightMargin;
tagView.setDuplicateParentStateEnabled(true);
if (tagView.getLayoutParams() != null)
{
tagViewContainer.setLayoutParams(tagView.getLayoutParams());
} else {
MarginLayoutParams lp = new MarginLayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
lp.setMargins(0,
0,
Utils.dpToPx(23),
Utils.dpToPx(20));
tagViewContainer.setLayoutParams(lp);
}
tagViewContainer.addView(tagView);
addView(tagViewContainer);
if (preCheckedList.contains(i))
{
tagViewContainer.setChecked(true);
}
if (mTagAdapter.setSelected(i, adapter.getItem(i))) {
setChildChecked(i, tagViewContainer);
}
tagView.setClickable(false);
final MyTagView finalTagViewContainer = tagViewContainer;
final int position = i;
tagViewContainer.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if (type == 0){
doSelect(finalTagViewContainer, position);
if (mOnTagClickListener != null) {
mOnTagClickListener.onTagClick(finalTagViewContainer, position,
MyTagFlowLayout.this);
}
} else {
doSelect1(finalTagViewContainer, position,finalTagViewContainer);
}
}
});
}
mSelectedView.addAll(preCheckedList);
}
private void setChildChecked(int position, MyTagView view) {
view.setChecked(true);
mTagAdapter.onSelected(position, view.getTagView());
}
private void setChildUnChecked(int position, MyTagView view) {
view.setChecked(false);
mTagAdapter.unSelected(position, view.getTagView());
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
if (event.getAction() == MotionEvent.ACTION_UP)
{
mMotionEvent = MotionEvent.obtain(event);
}
return super.onTouchEvent(event);
}
@Override
public boolean performClick()
{
if (mMotionEvent == null) return super.performClick();
int x = (int) mMotionEvent.getX();
int y = (int) mMotionEvent.getY();
mMotionEvent = null;
MyTagView child = findChild(x, y);
int pos = findPosByView(child);
if (child != null)
{
doSelect(child, pos);
if (mOnTagClickListener != null)
{
return mOnTagClickListener.onTagClick(child.getTagView(), pos, this);
}
}
return true;
}
public void setMaxSelectCount(int count)
{
if (mSelectedView.size() > count)
{
Log.w(TAG, "you has already select more than " + count + " views , so it will be clear .");
mSelectedView.clear();
}
mSelectedMax = count;
}
public Set<Integer> getSelectedList()
{
return new HashSet<Integer>(mSelectedView);
}
private void doSelect(MyTagView child, int position) {
if (!child.isChecked()) {
//处理max_select=1的情况
if (mSelectedMax == 1 && mSelectedView.size() == 1) {
Iterator<Integer> iterator = mSelectedView.iterator();
Integer preIndex = iterator.next();
MyTagView pre = (MyTagView) getChildAt(preIndex);
setChildUnChecked(preIndex, pre);
setChildChecked(position, child);
mSelectedView.remove(preIndex);
mSelectedView.add(position);
} else {
if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) {
return;
}
setChildChecked(position, child);
mSelectedView.add(position);
}
} else {
setChildUnChecked(position, child);
mSelectedView.remove(position);
}
if (mOnSelectListener != null) {
mOnSelectListener.onSelected(new HashSet<Integer>(mSelectedView));
}
}
/**
* 这个是为了 评价那里
* @param child
* @param position
* @param finalTagViewContainer
*/
private void doSelect1(MyTagView child, int position,MyTagView finalTagViewContainer) {
if (!child.isChecked()) {
//处理max_select=1的情况
if (mSelectedMax == 1 && mSelectedView.size() == 1) {
Iterator<Integer> iterator = mSelectedView.iterator();
Integer preIndex = iterator.next();
MyTagView pre = (MyTagView) getChildAt(preIndex);
setChildUnChecked(preIndex, pre);
setChildChecked(position, child);
mSelectedView.remove(preIndex);
mSelectedView.add(position);
} else {
if (mSelectedMax > 0 && mSelectedView.size() >= mSelectedMax) {
return;
}
setChildChecked(position, child);
mSelectedView.add(position);
}
if (mOnSelectListener != null) {
mOnSelectListener.onSelected(new HashSet<Integer>(mSelectedView));
}
if (mOnTagClickListener2 != null) {
mOnTagClickListener2.onTagClick(finalTagViewContainer, position,
MyTagFlowLayout.this);
}
}
}
public MyTagAdapter getAdapter()
{
return mTagAdapter;
}
private static final String KEY_CHOOSE_POS = "key_choose_pos";
private static final String KEY_DEFAULT = "key_default";
@Override
protected Parcelable onSaveInstanceState()
{
Bundle bundle = new Bundle();
bundle.putParcelable(KEY_DEFAULT, super.onSaveInstanceState());
String selectPos = "";
if (mSelectedView.size() > 0)
{
for (int key : mSelectedView)
{
selectPos += key + "|";
}
selectPos = selectPos.substring(0, selectPos.length() - 1);
}
bundle.putString(KEY_CHOOSE_POS, selectPos);
return bundle;
}
@Override
protected void onRestoreInstanceState(Parcelable state)
{
if (state instanceof Bundle)
{
Bundle bundle = (Bundle) state;
String mSelectPos = bundle.getString(KEY_CHOOSE_POS);
if (!TextUtils.isEmpty(mSelectPos))
{
String[] split = mSelectPos.split("\\|");
for (String pos : split)
{
int index = Integer.parseInt(pos);
mSelectedView.add(index);
MyTagView tagView = (MyTagView) getChildAt(index);
if (tagView != null)
setChildChecked(index, tagView);
}
}
super.onRestoreInstanceState(bundle.getParcelable(KEY_DEFAULT));
return;
}
super.onRestoreInstanceState(state);
}
private int findPosByView(View child)
{
final int cCount = getChildCount();
for (int i = 0; i < cCount; i++)
{
View v = getChildAt(i);
if (v == child) return i;
}
return -1;
}
private MyTagView findChild(int x, int y)
{
final int cCount = getChildCount();
for (int i = 0; i < cCount; i++)
{
MyTagView v = (MyTagView) getChildAt(i);
if (v.getVisibility() == View.GONE) continue;
Rect outRect = new Rect();
v.getHitRect(outRect);
if (outRect.contains(x, y))
{
return v;
}
}
return null;
}
@Override
public void onChanged()
{
mSelectedView.clear();
changeAdapter(1);
}
public static int dip2px(Context context, float dpValue)
{
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
public class MyTagView extends FrameLayout implements Checkable
{
private boolean isChecked;
private static final int[] CHECK_STATE = new int[]{android.R.attr.state_checked};
public MyTagView(Context context)
{
super(context);
}
public View getTagView()
{
return getChildAt(0);
}
@Override
public int[] onCreateDrawableState(int extraSpace)
{
int[] states = super.onCreateDrawableState(extraSpace + 1);
if (isChecked())
{
mergeDrawableStates(states, CHECK_STATE);
}
return states;
}
/**
* Change the checked state of the view
*
* @param checked The new checked state
*/
@Override
public void setChecked(boolean checked)
{
if (this.isChecked != checked)
{
this.isChecked = checked;
refreshDrawableState();
}
}
/**
* @return The current checked state of the view
*/
@Override
public boolean isChecked()
{
return isChecked;
}
/**
* Change the checked state of the view to the inverse of its current state
*/
@Override
public void toggle()
{
setChecked(!isChecked);
}
}
public class CommenttagAdapter extends MyTagAdapter<String> {
public Context context;
public CommenttagAdapter(Context context, List datas) {
super(datas);
this.context = context;
}
@Override
public View getView(MyFlowLayout parent, int position, String s, int i) {
TextView tv = (TextView) LayoutInflater.from(context).inflate(R.layout.tv,null,false);
tv.setPadding(Utils.dpToPx(22),Utils.dpToPx(10),Utils.dpToPx(22),Utils.dpToPx(10));
tv.setBackgroundResource(R.drawable.shape_fd_solid_corners5);
tv.setTextColor(context.getResources().getColor(R.color.s20));
tv.setTextSize(TypedValue.COMPLEX_UNIT_PX,30);
tv.setText(s);
if (position == 0){
onSelected(position,tv);
} else {
unSelected(position,tv);
}
return tv;
}
@Override
public void onSelected(int position, View view) {
TextView tv = (TextView) view;
Drawable nav_up = context.getResources().getDrawable(R.mipmap.comment_choose);
nav_up.setBounds(0, 0, Utils.dpToPx(21), Utils.dpToPx(15));
tv.setCompoundDrawables(nav_up, null, null, null);
tv.setCompoundDrawablePadding(Utils.dpToPx(8));
tv.setBackgroundResource(R.drawable.shape_e7_solid_fd_corner4);
}
@Override
public void unSelected(int position, View view) {
TextView tv = (TextView) view;
tv.setTextColor(context.getResources().getColor(R.color.s20));
tv.setBackgroundResource(R.drawable.shape_fd_solid_corners5);
tv.setCompoundDrawables(null, null, null, null);
}
// @Override
// public boolean setSelected(int position, String s) {
//
// if (position == 0){
//
// return s.contains("全部");
// } else {
//
// return false;
// }
//
//
//
// }
}
public class Utils {
public static int dpToPx(int dp) {
return (int) TypedValue.applyDimension(1, (float) dp, Resources.getSystem().getDisplayMetrics());
}
}
R.drawable.shape_e7_solid_fd_corner4:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:color="#f23030" android:width="1dp"/>
<solid android:color="#fef7f7"/>
<corners android:radius="4dp"/>
</shape>
R.drawable.shape_fd_solid_corners5:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="#fdf2f1"/>
<corners android:radius="5dp"/>
</shape>
2:使用非常简单:
public class TagFlowLayoutActivity extends AppCompatActivity {
public List<String> list = new ArrayList<>();
MyTagFlowLayout tab;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_tagflowlayout);
tab = findViewById(R.id.tag_flow);
tab.setMaxSelectCount(1);
list.add("全部(15)");
list.add("最新");
list.add("好评(4)");
list.add("中评(3)");
list.add("差评(2)");
list.add("有图(1)");
list.add("视频(5)");
CommenttagAdapter commenttagAdapter = new CommenttagAdapter(this, list);
tab.setAdapter(commenttagAdapter);
tab.type = 1;
commenttagAdapter.setSelectedList(0);
tab.setOnTagClickListener(new MyTagFlowLayout.OnTagClickListener2() {
@Override
public boolean onTagClick(View view, int position, MyFlowLayout parent) {
Toast.makeText(TagFlowLayoutActivity.this,list.get(position),Toast.LENGTH_SHORT).show();
return true;
}
});
}
}
R.layout.activity_tagflowlayout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout android:orientation="vertical"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:sbl="http://schemas.android.com/apk/res-auto">
<com.sbl.hwscankitdemo.flowlayout.MyTagFlowLayout
android:id="@+id/tag_flow"
sbl:max_select="1"
android:layout_margin="15dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>