Android自定義ViewGroup實現(xiàn)標簽流效果
本文實例為大家分享了Android自定義ViewGroup實現(xiàn)標簽流效果的具體代碼,供大家參考,具體內(nèi)容如下
自定義View,一是為了滿足設計需求,二是開發(fā)者進階的標志之一。隨心所欲就是我等奮斗的目標?。?!
效果

實現(xiàn)邏輯
明確需求
1、標簽流效果;
2、可以動態(tài)添加標簽;
3、標簽需要有點擊效果以及回調(diào);
整理思路
既然要裝載標簽,就需要自定義ViewGroup ,而自定義ViewGroup 比較復雜的就是onLayout()中對子View的排版。既然是標簽,在一行中一定要顯示完整,在排版的時候注意這一點,需要添加判斷!其次,標簽要有點擊事件,這里的實現(xiàn)我們可以借助子View的點擊事件封裝一個接口,實現(xiàn)我們自己的點擊事件!
要點
1、對于子View的測量;
2、對于子View的排版;
Ps: 需要注意的是給子View設置背景Drawable的時候不可以設置同一個Drawable,否則會出現(xiàn)錯亂情況!見getSonView()方法中完整代碼
/**
?* 自定義ViewGroup實現(xiàn)標簽流效果
?*
?* @attr customInterval ?//標簽之間的間隔
?* @attr customSelectMode ?//標簽選項模式
?* @attr customSonBackground ? //標簽背景
?* @attr customSonPaddingBottom ? //標簽底部內(nèi)邊距
?* @attr customSonPaddingLeft ?//標簽左邊內(nèi)邊距
?* @attr customSonPaddingRight ?//標簽右邊內(nèi)邊距
?* @attr customSonPaddingTop ?//標簽頂部內(nèi)邊距
?* @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);
? ? ? ? //顯示行數(shù)
? ? ? ? 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;
? ? ? ? ? ? //添加到數(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;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //設置控件尺寸
? ? ? ? setMeasuredDimension(mMeasureViewWidht, mSonMeasuredHeight * line + customInterval);
? ? }
? ? /**
? ? ?* 設置標簽內(nèi)容集合
? ? ?*
? ? ?* @param sonContent 標簽內(nèi)容
? ? ?*/
? ? public void setSonContent(ArrayList<String> sonContent) {
? ? ? ? if (sonContent != null) {
? ? ? ? ? ? mSonTextContents.clear();
? ? ? ? ? ? mSonTextContents.addAll(sonContent);
? ? ? ? ? ? requestLayout();
? ? ? ? }
? ? }
? ? /**
? ? ?* 添加一個標簽
? ? ?*
? ? ?* @param sonContent 標簽內(nèi)容
? ? ?*/
? ? public void addSonContent(String sonContent) {
? ? ? ? if (!TextUtils.isEmpty(sonContent)) {
? ? ? ? ? ? mSonTextContents.add(0, sonContent);
? ? ? ? ? ? requestLayout();
? ? ? ? }
? ? }
? ? /**
? ? ?* 設置標簽點擊事件
? ? ?*
? ? ?* @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);
? ? ? ? ? ? //不可以設置相同的Drawable
? ? ? ? ? ? mTextView.setBackgroundDrawable(customSonBackground.getConstantState().newDrawable());
? ? ? ? ? ? mTextView.setText(content);
? ? ? ? ? ? mTextView.setPadding(customSonPaddingLeft, customSonPaddingTop, customSonPaddingRight, customSonPaddingBottom);
? ? ? ? ? ? //消除TextView默認的上下內(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>
以上就是本文的全部內(nèi)容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。
相關文章
Android TouchListener實現(xiàn)拖拽刪實例代碼
這篇文章主要介紹了Android TouchListener實現(xiàn)拖拽刪實例代碼的相關資料,需要的朋友可以參考下2017-02-02
Android自定義View實現(xiàn)鐘擺效果進度條PendulumView
這篇文章主要介紹了Android自定義View實現(xiàn)鐘擺效果進度條PendulumView,具有一定的參考價值,感興趣的小伙伴們可以參考一下2016-09-09
Android 動態(tài)顯示和隱藏狀態(tài)欄詳解及實例
這篇文章主要介紹了Android 動態(tài)顯示和隱藏狀態(tài)欄的相關資料,需要的朋友可以參考下2017-06-06
詳解Android ContentProvider的基本原理和使用
ContentProvider(內(nèi)容提供者)是 Android 的四大組件之一,管理 Android 以結構化方式存放的數(shù)據(jù),以相對安全的方式封裝數(shù)據(jù)(表)并且提供簡易的處理機制和統(tǒng)一的訪問接口供其他程序調(diào)用2021-06-06
Android基于RecyclerView實現(xiàn)高亮搜索列表
本文詳細介紹了Android基于RecyclerView實現(xiàn)高亮搜索列表的方法。具有一定的參考價值,下面跟著小編一起來看下吧2017-01-01
讓Android中RadioGroup不顯示在輸入法上面的辦法
在Android開發(fā)中,發(fā)現(xiàn)一個問題,打開輸入法導致下面的radioGroup的位置發(fā)生了變化,被頂?shù)搅溯斎敕ǖ纳厦?,那么該如何解決呢?下面來看看。2016-08-08

