Android标签流效果
Android师哥 人气:0自定义View,一是为了满足设计需求,二是开发者进阶的标志之一。随心所欲就是我等奋斗的目标!!!
效果
实现逻辑
明确需求
1、标签流效果;
2、可以动态添加标签;
3、标签需要有点击效果以及回调;
整理思路
既然要装载标签,就需要自定义ViewGroup ,而自定义ViewGroup 比较复杂的就是onLayout()中对子View的排版。既然是标签,在一行中一定要显示完整,在排版的时候注意这一点,需要添加判断!其次,标签要有点击事件,这里的实现我们可以借助子View的点击事件封装一个接口,实现我们自己的点击事件!
要点
1、对于子View的测量;
2、对于子View的排版;
Ps: 需要注意的是给子View设置背景Drawable的时候不可以设置同一个Drawable,否则会出现错乱情况!见getSonView()方法中完整代码
/** * 自定义ViewGroup实现标签流效果 * * @attr customInterval //标签之间的间隔 * @attr customSelectMode //标签选项模式 * @attr customSonBackground //标签背景 * @attr customSonPaddingBottom //标签底部内边距 * @attr customSonPaddingLeft //标签左边内边距 * @attr customSonPaddingRight //标签右边内边距 * @attr customSonPaddingTop //标签顶部内边距 * @attr customSonTextColor //标签文字颜色 * @attr customSonTextSize //标签文字尺寸 */ public class CustomLableView extends ViewGroup { private static final String TAG = "CustomLableView"; private int customInterval = 15; private int customSonPaddingLeft = 20; private int customSonPaddingRight = 20; private int customSonPaddingTop = 10; private int customSonPaddingBottom = 10; private Drawable customSonBackground = null; private float customSonTextSize = 0; private ColorStateList customSonTextColor = ColorStateList.valueOf(0xFF000000); private ArrayList<String> mSonTextContents = new ArrayList<>(); private ArrayList<TextView> mSonTextViews = new ArrayList<>(); private Context mContext = null; private OnItemClickListener mOnItemClickListener; private int customSelectMode; public CustomLableView(Context context) { this(context, null); } public CustomLableView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CustomLableView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); this.mContext = context; //初始化自定义属性 initAttrs(context, attrs); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = customInterval; int top = customInterval; int mMeasuredWidth = this.getMeasuredWidth(); //防止重复添加 CustomLableView.this.removeAllViews(); for (int i = 0; i < mSonTextViews.size(); i++) { final TextView mTextView = mSonTextViews.get(i); //将当前子View添加到ViewGroup中 CustomLableView.this.addView(mTextView); //获取当前子View的宽高 int measuredHeight = mTextView.getMeasuredHeight(); int measuredWidth = mTextView.getMeasuredWidth(); //判断一行是否可显示 if ((mMeasuredWidth - left) >= (measuredWidth + customInterval * 2)) {//一行可显示 /** * 1、(mMeasuredWidth - left) X轴剩余空间 * 2、(measuredWidth + customInterval * 2) 当前子View和间隔需要的空间 */ mTextView.layout(left, top, left + measuredWidth, top + measuredHeight); left += (measuredWidth + customInterval); } else {//需要换行显示 //还原X轴的起始位置 left = customInterval; //Y轴高度增加 top += (measuredHeight + customInterval); mTextView.layout(left, top, left + measuredWidth, top + measuredHeight); left += (measuredWidth + customInterval); } } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //控件宽度 int mMeasureViewWidht = MeasureSpec.getSize(widthMeasureSpec); //显示行数 int line = 1; //每行当前宽度 int lineWidht = customInterval; //每行高度(子View的高度) int mSonMeasuredHeight = 0; mSonTextViews.clear(); for (int i = 0; i < mSonTextContents.size(); i++) { TextView mSonView = getSonView(i, mSonTextContents.get(i)); //对子View进行测量 mSonView.measure(0, 0); //获取子View的测量尺寸 int mSonMeasuredWidth = mSonView.getMeasuredWidth() + customInterval; mSonMeasuredHeight = mSonView.getMeasuredHeight() + customInterval; //添加到数组中 mSonTextViews.add(mSonView); if (mMeasureViewWidht >= mSonMeasuredWidth) { if ((mMeasureViewWidht - lineWidht) >= mSonMeasuredWidth) { lineWidht += mSonMeasuredWidth; } else { //行数自加1 line += 1; lineWidht = customInterval + mSonMeasuredWidth; } } else { mSonTextViews.clear(); setMeasuredDimension(0, 0); return; } } //设置控件尺寸 setMeasuredDimension(mMeasureViewWidht, mSonMeasuredHeight * line + customInterval); } /** * 设置标签内容集合 * * @param sonContent 标签内容 */ public void setSonContent(ArrayList<String> sonContent) { if (sonContent != null) { mSonTextContents.clear(); mSonTextContents.addAll(sonContent); requestLayout(); } } /** * 添加一个标签 * * @param sonContent 标签内容 */ public void addSonContent(String sonContent) { if (!TextUtils.isEmpty(sonContent)) { mSonTextContents.add(0, sonContent); requestLayout(); } } /** * 设置标签点击事件 * * @param onItemClickListener 回调接口 */ public void setOnItemClickListener(OnItemClickListener onItemClickListener) { this.mOnItemClickListener = onItemClickListener; } /** * 获取子View * * @return TextView */ private TextView getSonView(final int i, final String content) { if (mContext != null) { TextView mTextView = new TextView(mContext); mTextView.setTextColor(customSonTextColor); mTextView.setTextSize(TypedValue.COMPLEX_UNIT_PX, customSonTextSize); //不可以设置相同的Drawable mTextView.setBackgroundDrawable(customSonBackground.getConstantState().newDrawable()); mTextView.setText(content); mTextView.setPadding(customSonPaddingLeft, customSonPaddingTop, customSonPaddingRight, customSonPaddingBottom); //消除TextView默认的上下内边距 mTextView.setIncludeFontPadding(false); mTextView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { //选择模式 if (customSelectMode != 102) { for (int j = 0; j < mSonTextViews.size(); j++) { mSonTextViews.get(j).setSelected(false); } v.setSelected(true); } else { v.setSelected(true); } if (mOnItemClickListener != null) { mOnItemClickListener.onItemClick(v, i, content); } } }); return mTextView; } return null; } /** * 初始化自定义属性 * * @param context * @param attrs */ private void initAttrs(Context context, AttributeSet attrs) { TypedArray mTypedArray = context.obtainStyledAttributes(attrs, R.styleable.CustomLableView); customSonBackground = mTypedArray.getDrawable(R.styleable.CustomLableView_customSonBackground); customInterval = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customInterval, customInterval); customSonPaddingLeft = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingLeft, customSonPaddingLeft); customSonPaddingRight = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingRight, customSonPaddingRight); customSonPaddingTop = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingTop, customSonPaddingTop); customSonPaddingBottom = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonPaddingBottom, customSonPaddingBottom); customSonTextSize = (int) mTypedArray.getDimension(R.styleable.CustomLableView_customSonTextSize, 0); customSonTextColor = mTypedArray.getColorStateList(R.styleable.CustomLableView_customSonTextColor); customSelectMode = mTypedArray.getInt(R.styleable.CustomLableView_customSelectMode, 101); if (customSonTextSize == 0) { customSonTextSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, 14, getResources().getDisplayMetrics()); } mTypedArray.recycle(); } public interface OnItemClickListener { void onItemClick(View view, int position, String sonContent); } }
自定义属性
<declare-styleable name="CustomLableView"> <attr name="customSonBackground" format="reference" /> <attr name="customInterval" format="dimension" /> <attr name="customSonPaddingLeft" format="dimension" /> <attr name="customSonPaddingRight" format="dimension" /> <attr name="customSonPaddingTop" format="dimension" /> <attr name="customSonPaddingBottom" format="dimension" /> <attr name="customSonTextSize" format="dimension" /> <attr name="customSonTextColor" format="color" /> <attr name="customSelectMode"> <enum name="alone" value="101" /> <enum name="multi" value="102" /> </attr> </declare-styleable>
加载全部内容