Android自定义View实现标签流效果

Odessa ·
更新时间:2024-09-20
· 1197 次阅读

本文实例为大家分享了Android自定义View实现标签流效果的具体代码,供大家参考,具体内容如下

一、概述

Android自定义View实现标签流效果,一行放不下时会自动换行,用户可以自己定义单个标签的样式,可以选中和取消,可以监听单个标签的点击事件,功能还算强大,可以满足大部分开发需求,值得推荐,效果图如下:

二、实现代码

1.自定义View

定义属性文件

<declare-styleable name="FlowTagView">         <attr name="lineSpacing" format="dimension" />         <attr name="tagSpacing" format="dimension" />         <!-- 是否是固定布局 -->         <attr name="isFixed" format="boolean" />         <attr name="columnSize" format="integer" /> </declare-styleable>

FlowTagConfig.java

package com.czhappy.effectdemo.flowtag; import android.content.Context; import android.content.res.TypedArray; import android.util.AttributeSet; import com.czhappy.effectdemo.R; /**  * Description:  * User: chenzheng  * Date: 2017/2/17 0017  * Time: 10:23  */ public class FlowTagConfig {     private static final int DEFAULT_LINE_SPACING = 5;//默认行间距     private static final int DEFAULT_TAG_SPACING = 10;//各个标签之间的默认距离     private static final int DEFAULT_FIXED_COLUMN_SIZE = 3; //默认列数     private int lineSpacing;     private int tagSpacing;     private int columnSize;     private boolean isFixed;     public FlowTagConfig(Context context,AttributeSet attrs){         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.FlowTagView);         try {             lineSpacing = a.getDimensionPixelSize(R.styleable.FlowTagView_lineSpacing, DEFAULT_LINE_SPACING);             tagSpacing = a.getDimensionPixelSize(R.styleable.FlowTagView_tagSpacing, DEFAULT_TAG_SPACING);             columnSize = a.getInteger(R.styleable.FlowTagView_columnSize, DEFAULT_FIXED_COLUMN_SIZE);             isFixed = a.getBoolean(R.styleable.FlowTagView_isFixed,false);         } finally {             a.recycle();         }     }     public int getLineSpacing() {         return lineSpacing;     }     public void setLineSpacing(int lineSpacing) {         this.lineSpacing = lineSpacing;     }     public int getTagSpacing() {         return tagSpacing;     }     public void setTagSpacing(int tagSpacing) {         this.tagSpacing = tagSpacing;     }     public int getColumnSize() {         return columnSize;     }     public void setColumnSize(int columnSize) {         this.columnSize = columnSize;     }     public boolean isFixed() {         return isFixed;     }     public void setIsFixed(boolean isFixed) {         this.isFixed = isFixed;     } }

FlowTagView.java

package com.czhappy.effectdemo.flowtag; import android.content.Context; import android.database.DataSetObserver; import android.graphics.Canvas; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; /**  * Description:  * User: chenzheng  * Date: 2017/2/17 0017  * Time: 10:23  */ public class FlowTagView extends ViewGroup {     private int mLineSpacing;//行间距     private int mTagSpacing;//各个标签之间的距离     private BaseAdapter mAdapter;     private TagItemClickListener mListener;     private DataChangeObserver mObserver;     public FlowTagView(Context context) {         super(context);         init(context, null, 0);     }     public FlowTagView(Context context, AttributeSet attrs) {         super(context, attrs);         init(context, attrs, 0);     }     public FlowTagView(Context context, AttributeSet attrs, int defStyle) {         super(context, attrs, defStyle);         init(context, attrs, defStyle);     }     private void init(Context context, AttributeSet attrs, int defStyle) {         //获取属性         FlowTagConfig config = new FlowTagConfig(context, attrs);         mLineSpacing = config.getLineSpacing();         mTagSpacing = config.getTagSpacing();     }     private void drawLayout() {         if (mAdapter == null || mAdapter.getCount() == 0) {             return;         }         this.removeAllViews();         for (int i = 0; i < mAdapter.getCount(); i++) {             View view = mAdapter.getView(i,null,null);             final int position = i;             view.setOnClickListener(new OnClickListener() {                 @Override                 public void onClick(View v) {                     if (mListener != null) {                         mListener.itemClick(position);                     }                 }             });             this.addView(view);         }     }     @Override     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {         int wantHeight = 0;         int wantWidth = resolveSize(0, widthMeasureSpec);         int paddingLeft = getPaddingLeft();         int paddingRight = getPaddingRight();         int paddingTop = getPaddingTop();         int paddingBottom = getPaddingBottom();         int childLeft = paddingLeft;         int childTop = paddingTop;         int lineHeight = 0;         //固定列的数量所需要的代码         for (int i = 0; i < getChildCount(); i++) {             final View childView = getChildAt(i);             LayoutParams params = childView.getLayoutParams();             childView.measure(                     getChildMeasureSpec(widthMeasureSpec, paddingLeft + paddingRight, params.width),                     getChildMeasureSpec(heightMeasureSpec, paddingTop + paddingBottom, params.height)             );             //获取单个tag的宽高             int childHeight = childView.getMeasuredHeight();             int childWidth = childView.getMeasuredWidth();             lineHeight = Math.max(childHeight, lineHeight);             //超过长度的新起一行             if (childLeft + childWidth + paddingRight > wantWidth) {                 childLeft = paddingLeft;                 childTop += mLineSpacing + childHeight;                 lineHeight = childHeight;             }             childLeft += childWidth + mTagSpacing;         }         wantHeight += childTop + lineHeight + paddingBottom;         setMeasuredDimension(wantWidth, resolveSize(wantHeight, heightMeasureSpec));     }     @Override     protected void onLayout(boolean changed, int l, int t, int r, int b) {         //固定列的数量所需要的代码         int width = r - l;         int paddingLeft = getPaddingLeft();         int paddingTop = getPaddingTop();         int paddingRight = getPaddingRight();         int childLeft = paddingLeft;         int childTop = paddingTop;         int lineHeight = 0;         for (int i = 0; i < getChildCount(); i++) {             final View childView = getChildAt(i);             if (childView.getVisibility() == View.GONE) {                 continue;             }             int childWidth = childView.getMeasuredWidth();             int childHeight = childView.getMeasuredHeight();             lineHeight = Math.max(childHeight, lineHeight);             if (childLeft + childWidth + paddingRight > width) {                 childLeft = paddingLeft;                 childTop += mLineSpacing + lineHeight;                 lineHeight = childHeight;             }             childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);             childLeft += childWidth + mTagSpacing;         }     }     @Override     protected void onDraw(Canvas canvas) {         super.onDraw(canvas);     }     @Override     public LayoutParams generateLayoutParams(AttributeSet attrs) {         return new LayoutParams(this.getContext(), attrs);     }     public void setAdapter(BaseAdapter adapter){         if (mAdapter == null){             mAdapter = adapter;             if (mObserver == null){                 mObserver = new DataChangeObserver();                 mAdapter.registerDataSetObserver(mObserver);             }             drawLayout();         }     }     public void setItemClickListener(TagItemClickListener mListener) {         this.mListener = mListener;     }     /**      * 单击监听接口      */     public interface TagItemClickListener {         void itemClick(int position);     }     class DataChangeObserver extends DataSetObserver {         @Override         public void onChanged() {             FlowTagView.this.drawLayout();         }         @Override         public void onInvalidated() {             super.onInvalidated();         }     } }

2.测试类

FlowTagActivity.java

package com.czhappy.effectdemo.activity; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.v7.app.AppCompatActivity; import com.czhappy.effectdemo.R; import com.czhappy.effectdemo.adapter.EvaluateAdapter; import com.czhappy.effectdemo.flowtag.FlowTagView; import com.czhappy.effectdemo.model.Evaluate; import java.util.ArrayList; import java.util.List; /**  * Description:  * User: chenzheng  * Date: 2017/2/17 0017  * Time: 11:47  */ public class FlowTagActivity extends AppCompatActivity {     private FlowTagView mContainer;     private EvaluateAdapter adapter;     private List<Evaluate> chooseList = new ArrayList<Evaluate>();     @Override     protected void onCreate(@Nullable Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_flowtag);         initView();         initData();     }     private void initData() {         List<Evaluate> list = new ArrayList();         Evaluate e1 = new Evaluate("热情", "1");         Evaluate e2 = new Evaluate("服务周到", "2");         Evaluate e3 = new Evaluate("一般", "3");         Evaluate e4 = new Evaluate("技术活杠杠的", "4");         Evaluate e5 = new Evaluate("专业精通", "5");         Evaluate e6 = new Evaluate("只会吹牛逼", "6");         Evaluate e7 = new Evaluate("地下第一仅此一家", "7");         list.add(e1);         list.add(e2);         list.add(e3);         list.add(e4);         list.add(e5);         list.add(e6);         list.add(e7);         adapter.setItems(list);     }     private void initView() {         mContainer = (FlowTagView) this.findViewById(R.id.container);         adapter = new EvaluateAdapter(this);         mContainer.setAdapter(adapter);         mContainer.setItemClickListener(new FlowTagView.TagItemClickListener() {             @Override             public void itemClick(int position) {                 Evaluate e = (Evaluate) adapter.getItem(position);                 e.is_choosed = !e.is_choosed;                 if(e.is_choosed){                     chooseList.add(e);                 }else{                     chooseList.remove(e);                 }                 adapter.notifyDataSetChanged();             }         });     } }

EvaluateAdapter.java

package com.czhappy.effectdemo.adapter; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; import com.czhappy.effectdemo.R; import com.czhappy.effectdemo.model.Evaluate; import java.util.ArrayList; import java.util.List; /**  * Description:  * User: chenzheng  * Date: 2017/2/17 0017  * Time: 11:43  */ public class EvaluateAdapter extends BaseAdapter {     private Context context;     private LayoutInflater mInflater;     private List<Evaluate> list;     public EvaluateAdapter(Context context) {         this.context = context;         this.mInflater = LayoutInflater.from(context);         this.list =  new ArrayList<Evaluate>();     }     public List<Evaluate> getList(){         return list;     }     public void setItems(List<Evaluate> list){         this.list = list;         notifyDataSetChanged();     }     @Override     public int getCount() {         return list == null ? 0 : list.size();     }     @Override     public Object getItem(int position) {         return list.get(position);     }     @Override     public long getItemId(int position) {         // TODO Auto-generated method stub         return 0;     }     @Override     public View getView(int position, View convertView, ViewGroup parent) {         ViewHolder holder = null;         if (convertView == null) {             holder = new ViewHolder();             convertView = mInflater.inflate(                     R.layout.evaluate_grid_item, null);             holder.evaluate_tv = (TextView)convertView.findViewById(R.id.evaluate_tv);             convertView.setTag(holder);         } else {             holder = (ViewHolder) convertView.getTag();         }         final Evaluate ee = (Evaluate) getItem(position);         holder.evaluate_tv.setText(ee.getName());         if(ee.is_choosed){             holder.evaluate_tv.setBackgroundResource(R.drawable.bg_round_corner_line_orange);         }else{             holder.evaluate_tv.setBackgroundResource(R.drawable.bg_round_corner_line_gray);         }         return convertView;     }     private final class ViewHolder {         private TextView evaluate_tv;     } }

布局文件

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"     xmlns:app="http://schemas.android.com/apk/res-auto"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical">     <com.czhappy.effectdemo.flowtag.FlowTagView         android:id="@+id/container"         android:layout_width="match_parent"         android:layout_height="wrap_content"         android:padding="10dp"         app:tagSpacing="10dp"         app:lineSpacing="10dp"/> </LinearLayout>

bg_round_corner_line_orange.xml

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" >     <solid android:color="#ffffff" />     <corners android:radius="5dp" />     <stroke android:width="0.5dp"         android:color="#FF6700"/> </shape>

bg_round_corner_line_gray.xml

<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" >     <solid android:color="#ffffff" />     <corners android:radius="5dp" />     <stroke android:width="0.5dp"         android:color="#cccccc"/> </shape>



view 标签 Android

需要 登录 后方可回复, 如果你还没有账号请 注册新账号