Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果
本文實(shí)例為大家分享了Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果的具體代碼,供大家參考,具體內(nèi)容如下
自定義View,一是為了滿足設(shè)計(jì)需求,二是開發(fā)者進(jìn)階的標(biāo)志之一。隨心所欲就是我等奮斗的目標(biāo)?。?!
效果
實(shí)現(xiàn)邏輯
明確需求
1、標(biāo)簽流效果;
2、可以動(dòng)態(tài)添加標(biāo)簽;
3、標(biāo)簽需要有點(diǎn)擊效果以及回調(diào);
整理思路
既然要裝載標(biāo)簽,就需要自定義ViewGroup ,而自定義ViewGroup 比較復(fù)雜的就是onLayout()中對(duì)子View的排版。既然是標(biāo)簽,在一行中一定要顯示完整,在排版的時(shí)候注意這一點(diǎn),需要添加判斷!其次,標(biāo)簽要有點(diǎn)擊事件,這里的實(shí)現(xiàn)我們可以借助子View的點(diǎn)擊事件封裝一個(gè)接口,實(shí)現(xiàn)我們自己的點(diǎn)擊事件!
要點(diǎn)
1、對(duì)于子View的測(cè)量;
2、對(duì)于子View的排版;
Ps: 需要注意的是給子View設(shè)置背景Drawable的時(shí)候不可以設(shè)置同一個(gè)Drawable,否則會(huì)出現(xiàn)錯(cuò)亂情況!見getSonView()方法中完整代碼
/** ?* 自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流效果 ?* ?* @attr customInterval ?//標(biāo)簽之間的間隔 ?* @attr customSelectMode ?//標(biāo)簽選項(xiàng)模式 ?* @attr customSonBackground ? //標(biāo)簽背景 ?* @attr customSonPaddingBottom ? //標(biāo)簽底部?jī)?nèi)邊距 ?* @attr customSonPaddingLeft ?//標(biāo)簽左邊內(nèi)邊距 ?* @attr customSonPaddingRight ?//標(biāo)簽右邊內(nèi)邊距 ?* @attr customSonPaddingTop ?//標(biāo)簽頂部?jī)?nèi)邊距 ?* @attr customSonTextColor ?//標(biāo)簽文字顏色 ?* @attr customSonTextSize ?//標(biāo)簽文字尺寸 ?*/ 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(); ? ? ? ? //防止重復(fù)添加 ? ? ? ? CustomLableView.this.removeAllViews(); ? ? ? ? for (int i = 0; i < mSonTextViews.size(); i++) { ? ? ? ? ? ? final TextView mTextView = mSonTextViews.get(i); ? ? ? ? ? ? //將當(dāng)前子View添加到ViewGroup中 ? ? ? ? ? ? CustomLableView.this.addView(mTextView); ? ? ? ? ? ? //獲取當(dāng)前子View的寬高 ? ? ? ? ? ? int measuredHeight = mTextView.getMeasuredHeight(); ? ? ? ? ? ? int measuredWidth = mTextView.getMeasuredWidth(); ? ? ? ? ? ? //判斷一行是否可顯示 ? ? ? ? ? ? if ((mMeasuredWidth - left) >= (measuredWidth + customInterval * 2)) {//一行可顯示 ? ? ? ? ? ? ? ? /** ? ? ? ? ? ? ? ? ?* 1、(mMeasuredWidth - left) X軸剩余空間 ? ? ? ? ? ? ? ? ?* 2、(measuredWidth + customInterval * 2) 當(dāng)前子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); ? ? ? ? //顯示行數(shù) ? ? ? ? int line = 1; ? ? ? ? //每行當(dāng)前寬度 ? ? ? ? int lineWidht = customInterval; ? ? ? ? //每行高度(子View的高度) ? ? ? ? int mSonMeasuredHeight = 0; ? ? ? ? mSonTextViews.clear(); ? ? ? ? for (int i = 0; i < mSonTextContents.size(); i++) { ? ? ? ? ? ? TextView mSonView = getSonView(i, mSonTextContents.get(i)); ? ? ? ? ? ? //對(duì)子View進(jìn)行測(cè)量 ? ? ? ? ? ? mSonView.measure(0, 0); ? ? ? ? ? ? //獲取子View的測(cè)量尺寸 ? ? ? ? ? ? int mSonMeasuredWidth = mSonView.getMeasuredWidth() + customInterval; ? ? ? ? ? ? mSonMeasuredHeight = mSonView.getMeasuredHeight() + customInterval; ? ? ? ? ? ? //添加到數(shù)組中 ? ? ? ? ? ? mSonTextViews.add(mSonView); ? ? ? ? ? ? if (mMeasureViewWidht >= mSonMeasuredWidth) { ? ? ? ? ? ? ? ? if ((mMeasureViewWidht - lineWidht) >= mSonMeasuredWidth) { ? ? ? ? ? ? ? ? ? ? lineWidht += mSonMeasuredWidth; ? ? ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? ? ? //行數(shù)自加1 ? ? ? ? ? ? ? ? ? ? line += 1; ? ? ? ? ? ? ? ? ? ? lineWidht = customInterval + mSonMeasuredWidth; ? ? ? ? ? ? ? ? } ? ? ? ? ? ? } else { ? ? ? ? ? ? ? ? mSonTextViews.clear(); ? ? ? ? ? ? ? ? setMeasuredDimension(0, 0); ? ? ? ? ? ? ? ? return; ? ? ? ? ? ? } ? ? ? ? } ? ? ? ? //設(shè)置控件尺寸 ? ? ? ? setMeasuredDimension(mMeasureViewWidht, mSonMeasuredHeight * line + customInterval); ? ? } ? ? /** ? ? ?* 設(shè)置標(biāo)簽內(nèi)容集合 ? ? ?* ? ? ?* @param sonContent 標(biāo)簽內(nèi)容 ? ? ?*/ ? ? public void setSonContent(ArrayList<String> sonContent) { ? ? ? ? if (sonContent != null) { ? ? ? ? ? ? mSonTextContents.clear(); ? ? ? ? ? ? mSonTextContents.addAll(sonContent); ? ? ? ? ? ? requestLayout(); ? ? ? ? } ? ? } ? ? /** ? ? ?* 添加一個(gè)標(biāo)簽 ? ? ?* ? ? ?* @param sonContent 標(biāo)簽內(nèi)容 ? ? ?*/ ? ? public void addSonContent(String sonContent) { ? ? ? ? if (!TextUtils.isEmpty(sonContent)) { ? ? ? ? ? ? mSonTextContents.add(0, sonContent); ? ? ? ? ? ? requestLayout(); ? ? ? ? } ? ? } ? ? /** ? ? ?* 設(shè)置標(biāo)簽點(diǎn)擊事件 ? ? ?* ? ? ?* @param onItemClickListener 回調(diào)接口 ? ? ?*/ ? ? 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); ? ? ? ? ? ? //不可以設(shè)置相同的Drawable ? ? ? ? ? ? mTextView.setBackgroundDrawable(customSonBackground.getConstantState().newDrawable()); ? ? ? ? ? ? mTextView.setText(content); ? ? ? ? ? ? mTextView.setPadding(customSonPaddingLeft, customSonPaddingTop, customSonPaddingRight, customSonPaddingBottom); ? ? ? ? ? ? //消除TextView默認(rèn)的上下內(nèi)邊距 ? ? ? ? ? ? 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>
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- Android自定義ViewGroup多行多列效果
- Android自定義ViewGroup實(shí)現(xiàn)朋友圈九宮格控件
- Android自定義ViewGroup實(shí)現(xiàn)流式布局
- Android進(jìn)階教程之ViewGroup自定義布局
- Android自定義ViewGroup實(shí)現(xiàn)豎向引導(dǎo)界面
- Android自定義ViewGroup實(shí)現(xiàn)淘寶商品詳情頁(yè)
- 一篇文章弄懂Android自定義viewgroup的相關(guān)難點(diǎn)
- Android自定義控件ViewGroup實(shí)現(xiàn)標(biāo)簽云
- Android自定義ViewGroup實(shí)現(xiàn)選擇面板
相關(guān)文章
Android TouchListener實(shí)現(xiàn)拖拽刪實(shí)例代碼
這篇文章主要介紹了Android TouchListener實(shí)現(xiàn)拖拽刪實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下2017-02-02Android自定義View實(shí)現(xiàn)鐘擺效果進(jìn)度條PendulumView
這篇文章主要介紹了Android自定義View實(shí)現(xiàn)鐘擺效果進(jìn)度條PendulumView,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09Android 動(dòng)態(tài)顯示和隱藏狀態(tài)欄詳解及實(shí)例
這篇文章主要介紹了Android 動(dòng)態(tài)顯示和隱藏狀態(tài)欄的相關(guān)資料,需要的朋友可以參考下2017-06-06Android自定義View實(shí)現(xiàn)圓弧進(jìn)度的效果
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)圓弧進(jìn)度的效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-01-01Android studio實(shí)現(xiàn)刮刮樂的方法
這篇文章主要為大家詳細(xì)介紹了Android studio實(shí)現(xiàn)刮刮樂的兩種方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-10-10詳解Android ContentProvider的基本原理和使用
ContentProvider(內(nèi)容提供者)是 Android 的四大組件之一,管理 Android 以結(jié)構(gòu)化方式存放的數(shù)據(jù),以相對(duì)安全的方式封裝數(shù)據(jù)(表)并且提供簡(jiǎn)易的處理機(jī)制和統(tǒng)一的訪問接口供其他程序調(diào)用2021-06-06自己實(shí)現(xiàn)的android樹控件treeview
在項(xiàng)目中經(jīng)常需要一個(gè)需要一個(gè)樹狀框架,因?yàn)橐恍┰驔]有使用系統(tǒng)自帶的控件,所以就自己寫了一個(gè),現(xiàn)在分享給大家2014-01-01Android基于RecyclerView實(shí)現(xiàn)高亮搜索列表
本文詳細(xì)介紹了Android基于RecyclerView實(shí)現(xiàn)高亮搜索列表的方法。具有一定的參考價(jià)值,下面跟著小編一起來看下吧2017-01-01讓Android中RadioGroup不顯示在輸入法上面的辦法
在Android開發(fā)中,發(fā)現(xiàn)一個(gè)問題,打開輸入法導(dǎo)致下面的radioGroup的位置發(fā)生了變化,被頂?shù)搅溯斎敕ǖ纳厦妫敲丛撊绾谓鉀Q呢?下面來看看。2016-08-08