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

来源:互联网 发布:淘宝哪个店铺能套现 编辑:程序博客网 时间:2024/05/17 06:03

一、概述

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>
0 0
原创粉丝点击