最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android自定義ViewGroup實(shí)現(xiàn)標(biāo)簽流容器FlowLayout

 更新時(shí)間:2022年02月16日 11:35:47   作者:qq_20785431  
這篇文章主要介紹了Android自定義ViewGroup實(shí)現(xiàn)FlowLayout標(biāo)簽流容器,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

本篇文章講的是Android 自定義ViewGroup之實(shí)現(xiàn)標(biāo)簽流式布局-FlowLayout,開(kāi)發(fā)中我們會(huì)經(jīng)常需要實(shí)現(xiàn)類似于熱門標(biāo)簽等自動(dòng)換行的流式布局的功能,網(wǎng)上也有很多這樣的FlowLayout,但不影響我對(duì)其的學(xué)習(xí)。和往常一樣,主要還是想總結(jié)一下自定義ViewGroup的開(kāi)發(fā)過(guò)程以及一些需要注意的地方。

按照慣例,我們先來(lái)看看效果圖

一、寫代碼之前,有幾個(gè)是問(wèn)題是我們先要弄清楚的:

1、什么是ViewGroup:從名字上來(lái)看,它可以被翻譯為控件組,言外之意是ViewGroup內(nèi)部包含了許多個(gè)控件,是一組View。在Android的設(shè)計(jì)中,ViewGroup也繼承了View,這就意味著View本身就可以是單個(gè)控件也可以是由多個(gè)控件組成的一組控件;

2、ViewGroup的種類:常見(jiàn)的有LinearLayout、RelativeLayout、FrameLayout、AbsoluteLayout、GirdLayout、TableLayout。其中LinearLayout和RelativeLayout使用的最多的兩種;

3、ViewGroup的職責(zé):給childView計(jì)算出建議的寬和高和測(cè)量模式 ,然后決定childView的位置;

4、話說(shuō)何為流式布局(FlowLayout):就是控件根據(jù)ViewGroup的寬,自動(dòng)的從左往右添加。如果當(dāng)前行還能放得這個(gè)子View,就放到當(dāng)前行,如果當(dāng)前行剩余的空間不足于容納這個(gè)子View,則自動(dòng)添加到下一行的最左邊;

二、先總結(jié)下自定義ViewGroup的步驟:

1、自定義ViewGroup的屬性
2、在ViewGroup的構(gòu)造方法中獲得我們自定義的屬性
3、重寫onMesure
4、重寫onLayout

三、ViewGroup的幾個(gè)構(gòu)造函數(shù):

1、public FlowLayout(Context context)
—>Java代碼直接new一個(gè)FlowLayout實(shí)例的時(shí)候,會(huì)調(diào)用這個(gè)只有一個(gè)參數(shù)的構(gòu)造函數(shù);
2、public FlowLayout(Context context, AttributeSet attrs)
—>在默認(rèn)的XML布局文件中創(chuàng)建的時(shí)候調(diào)用這個(gè)有兩個(gè)參數(shù)的構(gòu)造函數(shù)。AttributeSet類型的參數(shù)負(fù)責(zé)把XML布局文件中所自定義的屬性通過(guò)AttributeSet帶入到View內(nèi);
3、public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr)
—>構(gòu)造函數(shù)中第三個(gè)參數(shù)是默認(rèn)的Style,這里的默認(rèn)的Style是指它在當(dāng)前Application或者Activity所用的Theme中的默認(rèn)Style,且只有在明確調(diào)用的時(shí)候才會(huì)調(diào)用
4、public FlowLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
—>該構(gòu)造函數(shù)是在API21的時(shí)候才添加上的

四、下面我們就開(kāi)始來(lái)看看自定義ViewGroup的主要代碼啦

 1、自定義ViewGroup的屬性,首先在res/values/ 下建立一個(gè)attr.xml , 在里面定義我們的需要用到的屬性以及聲明相對(duì)應(yīng)屬性的取值類型

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <!--每個(gè)item縱向間距-->
 <attr name="verticalSpacing" format="dimension" />
 <!-- 每個(gè)item橫向間距-->
 <attr name="horizontalSpacing" format="dimension" />

 <declare-styleable name="FlowLayout">
 <attr name="verticalSpacing" />
 <attr name="horizontalSpacing" />
 </declare-styleable>

</resources>

我們定義了verticalSpacing以及horizontalSpacing2個(gè)屬性,分別表示每個(gè)標(biāo)簽之間縱向間距和橫向間距,其中format是值該屬性的取值類型,format取值類型總共有10種,包括:string,color,demension,integer,enum,reference,float,boolean,fraction和flag。

2、然后在XML布局中聲明我們的自定義View

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:custom="http://schemas.android.com/apk/res-auto"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 android:orientation="vertical">

 <TextView
 android:layout_width="match_parent"
 android:layout_height="48dp"
 android:background="#38353D"
 android:gravity="center"
 android:text="標(biāo)簽"
 android:textColor="@android:color/white"
 android:textSize="16dp" />

 <ScrollView
 android:layout_width="match_parent"
 android:layout_height="wrap_content">

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical">

 <TextView
 android:id="@+id/tv_remind"
 android:layout_width="match_parent"
 android:layout_height="46dp"
 android:background="@android:color/white"
 android:gravity="center_vertical"
 android:paddingLeft="15dp"
 android:text="我的標(biāo)簽(最多5個(gè)) "
 android:textSize="16dp" />

 <com.per.flowlayoutdome.FlowLayout
 android:id="@+id/tcy_my_label"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@android:color/white"
 android:padding="5dp"
 android:visibility="gone"
 custom:horizontalSpacing="6dp"
 custom:verticalSpacing="12dp" />

 <View
 android:layout_width="match_parent"
 android:layout_height="10dp"
 android:background="#f6f6f6" />

 <RelativeLayout
 android:layout_width="match_parent"
 android:layout_height="46dp"
 android:background="@android:color/white">

 <TextView
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:layout_centerVertical="true"
  android:paddingLeft="15dp"
  android:text="推薦標(biāo)簽 "
  android:textSize="16dp" />
 </RelativeLayout>

 <View
 android:layout_width="match_parent"
 android:layout_height="1dp"
 android:background="#f6f6f6" />

 <com.per.flowlayoutdome.FlowLayout
 android:id="@+id/tcy_hot_label"
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:background="@android:color/white"
 android:padding="5dp"
 custom:horizontalSpacing="6dp"
 custom:verticalSpacing="12dp" />
 </LinearLayout>
 </ScrollView>
</LinearLayout>

一定要引入xmlns:custom=”http://schemas.android.com/apk/res-auto”,Android Studio中我們可以使用res-atuo命名空間,就不用在添加自定義View全類名。

3、在View的構(gòu)造方法中,獲得我們的自定義的樣式

/**
 * 每個(gè)item縱向間距
 */
 private int mVerticalSpacing;
 /**
 * 每個(gè)item橫向間距
 */
 private int mHorizontalSpacing;

 public FlowLayout(Context context) {
 this(context, null);
 }

 public FlowLayout(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

 public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 /**
 * 獲得我們所定義的自定義樣式屬性
 */
 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlowLayout, defStyle, 0);
 for (int i = 0; i < a.getIndexCount(); i++) {
 int attr = a.getIndex(i);
 switch (attr) {
 case R.styleable.FlowLayout_verticalSpacing:
  mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 5);
  break;
 case R.styleable.FlowLayout_horizontalSpacing:
  mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 10);
  break;
 }
 }
 a.recycle();
 }

我們重寫了3個(gè)構(gòu)造方法,在上面的構(gòu)造方法中說(shuō)過(guò)默認(rèn)的布局文件調(diào)用的是兩個(gè)參數(shù)的構(gòu)造方法,所以記得讓所有的構(gòu)造方法調(diào)用三個(gè)參數(shù)的構(gòu)造方法,然后在三個(gè)參數(shù)的構(gòu)造方法中獲得自定義屬性。

一開(kāi)始一個(gè)參數(shù)的構(gòu)造方法和兩個(gè)參數(shù)的構(gòu)造方法是這樣的:

 public FlowLayout(Context context) {
 super(context);
 }

 public FlowLayout(Context context, AttributeSet attrs) {
 super(context, attrs);
 }

有一點(diǎn)要注意的是super應(yīng)該改成this,然后讓一個(gè)參數(shù)的構(gòu)造方法引用兩個(gè)參數(shù)的構(gòu)造方法,兩個(gè)參數(shù)的構(gòu)造方法引用三個(gè)參數(shù)的構(gòu)造方法,代碼如下:

 public FlowLayout(Context context) {
 this(context, null);
 }

 public FlowLayout(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

4、重寫onMesure方法

/**
 * 負(fù)責(zé)設(shè)置子控件的測(cè)量模式和大小 根據(jù)所有子控件設(shè)置自己的寬和高
 */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 /**
 * 獲得此ViewGroup上級(jí)容器為其推薦的寬和高,以及計(jì)算模式
 */
 int heighMode = MeasureSpec.getMode(heightMeasureSpec);
 int heighSize = MeasureSpec.getSize(heightMeasureSpec);
 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
 /**
 * 高
 */
 int height = 0;
 /**
 * 每一行的高度,累加至height
 */
 int lineHeight = 0;
 /**
 * 在warp_content情況下,記錄當(dāng)前childView的左邊的一個(gè)位置
 */
 int childLeft = getPaddingLeft();
 /**
 * 在warp_content情況下,記錄當(dāng)前childView的上邊的一個(gè)位置
 */
 int childTop = getPaddingTop();
 // getChildCount得到子view的數(shù)目,遍歷循環(huán)出每個(gè)子View
 for (int i = 0; i < getChildCount(); i++) {
 //拿到index上的子view
 View childView = getChildAt(i);
 // 測(cè)量每一個(gè)child的寬和高
 measureChild(childView, widthMeasureSpec, heightMeasureSpec);
 //當(dāng)前子空間實(shí)際占據(jù)的高度
 int childHeight = childView.getMeasuredHeight();
 //當(dāng)前子空間實(shí)際占據(jù)的寬度
 int childWidth = childView.getMeasuredWidth();
 lineHeight = Math.max(childHeight, lineHeight);// 取最大值
 //如果加入當(dāng)前childView,超出最大寬度,則將目前最大寬度給width,類加height 然后開(kāi)啟新行
 if (childWidth + childLeft + getPaddingRight() > widthSize) {
 childLeft = getPaddingLeft();// 重新開(kāi)啟新行,開(kāi)始記錄childLeft
 childTop += mVerticalSpacing + childHeight;// 疊加當(dāng)前的高度
 lineHeight = childHeight;// 開(kāi)啟記錄下一行的高度
 }else{
 //否則累加當(dāng)前childView的寬度
 childLeft += childWidth + mHorizontalSpacing;
 }
 }
 height += childTop + lineHeight + getPaddingBottom();
 setMeasuredDimension(widthSize, heighMode == MeasureSpec.EXACTLY ? heighSize : height);
 }

首先首先得到其父容器傳入的測(cè)量模式和寬高的計(jì)算值,然后遍歷所有的childView,使用measureChild方法對(duì)所有的childView進(jìn)行測(cè)量。然后根據(jù)所有childView的測(cè)量得出的高得到該ViewGroup如果設(shè)置為wrap_content時(shí)的高。最后根據(jù)模式,如果是MeasureSpec.EXACTLY則直接使用父ViewGroup傳入的高,否則設(shè)置為自己計(jì)算的高,細(xì)心的朋友會(huì)問(wèn),那兒寬呢,在這里我們默認(rèn)寬為MeasureSpec.EXACTLY模式。

5、重寫onLayout方法

@Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 int width = r - l;
 int childLeft = getPaddingLeft();
 int childTop = getPaddingTop();
 int lineHeight = 0;
 //遍歷所有childView根據(jù)其寬和高,計(jì)算子控件應(yīng)該出現(xiàn)的位置
 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);
 // 如果已經(jīng)需要換行
 if (childLeft + childWidth + getPaddingRight() > width) {
 childLeft = getPaddingLeft();
 childTop += mVerticalSpacing + lineHeight;
 lineHeight = childHeight;
 }
 childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
 childLeft += childWidth + mHorizontalSpacing;
 }
 }

onLayout中完成對(duì)所有childView的位置以及大小的指定

6、到此,我們對(duì)自定義ViewGroup的代碼已經(jīng)寫完了,有幾點(diǎn)要注意的:

(1)getChildAt(int index):獲得index上的子view;
(2)getChildCount():得到所有子view的數(shù)目;
(3)measureChild(childView, widthMeasureSpec, heightMeasureSpec):使用子view自身的測(cè)量方法,測(cè)量每一個(gè)child的寬和高;

回歸到主題,現(xiàn)在我們把自定義ViewGroup,實(shí)現(xiàn)FlowLayout的部分完成了,接下來(lái)的就是一些邏輯代碼了

五、下面就是一些邏輯代碼啦

1、我把FlowLayout里面完整的代碼貼出來(lái):

package com.per.flowlayoutdome;

import android.content.Context;
import android.content.res.TypedArray;
import android.database.DataSetObserver;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;

/**
 * @author: xiaolijuan
 * @description: 流式布局-標(biāo)簽流容器
 * @projectName: FlowLayoutDome
 * @date: 2016-06-16
 * @time: 16:21
 */
public class FlowLayout extends ViewGroup{
 /**
 * 每個(gè)item縱向間距
 */
 private int mVerticalSpacing;
 /**
 * 每個(gè)item橫向間距
 */
 private int mHorizontalSpacing;
 private BaseAdapter mAdapter;
 private TagItemClickListener mListener;
 private DataChangeObserver mObserver;

 public FlowLayout(Context context) {
 this(context, null);
 }

 public FlowLayout(Context context, AttributeSet attrs) {
 this(context, attrs, 0);
 }

 public FlowLayout(Context context, AttributeSet attrs, int defStyle) {
 super(context, attrs, defStyle);
 /**
 * 獲得我們所定義的自定義樣式屬性
 */
 TypedArray a = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlowLayout, defStyle, 0);
 for (int i = 0; i < a.getIndexCount(); i++) {
 int attr = a.getIndex(i);
 switch (attr) {
 case R.styleable.FlowLayout_verticalSpacing:
  mVerticalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_verticalSpacing, 5);
  break;
 case R.styleable.FlowLayout_horizontalSpacing:
  mHorizontalSpacing = a.getDimensionPixelSize(R.styleable.FlowLayout_horizontalSpacing, 10);
  break;
 }
 }
 a.recycle();
 }

 /**
 * 負(fù)責(zé)設(shè)置子控件的測(cè)量模式和大小 根據(jù)所有子控件設(shè)置自己的寬和高
 */
 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 /**
 * 獲得此ViewGroup上級(jí)容器為其推薦的寬和高,以及計(jì)算模式
 */
 int heighMode = MeasureSpec.getMode(heightMeasureSpec);
 int heighSize = MeasureSpec.getSize(heightMeasureSpec);
 int widthSize = MeasureSpec.getSize(widthMeasureSpec);
 /**
 * 高
 */
 int height = 0;
 /**
 * 每一行的高度,累加至height
 */
 int lineHeight = 0;
 /**
 * 在warp_content情況下,記錄當(dāng)前childView的左邊的一個(gè)位置
 */
 int childLeft = getPaddingLeft();
 /**
 * 在warp_content情況下,記錄當(dāng)前childView的上邊的一個(gè)位置
 */
 int childTop = getPaddingTop();
 // getChildCount得到子view的數(shù)目,遍歷循環(huán)出每個(gè)子View
 for (int i = 0; i < getChildCount(); i++) {
 //拿到index上的子view
 View childView = getChildAt(i);
 // 測(cè)量每一個(gè)child的寬和高
 measureChild(childView, widthMeasureSpec, heightMeasureSpec);
 //當(dāng)前子空間實(shí)際占據(jù)的高度
 int childHeight = childView.getMeasuredHeight();
 //當(dāng)前子空間實(shí)際占據(jù)的寬度
 int childWidth = childView.getMeasuredWidth();
 lineHeight = Math.max(childHeight, lineHeight);// 取最大值
 //如果加入當(dāng)前childView,超出最大寬度,則將目前最大寬度給width,類加height 然后開(kāi)啟新行
 if (childWidth + childLeft + getPaddingRight() > widthSize) {
 childLeft = getPaddingLeft();// 重新開(kāi)啟新行,開(kāi)始記錄childLeft
 childTop += mVerticalSpacing + childHeight;// 疊加當(dāng)前的高度
 lineHeight = childHeight;// 開(kāi)啟記錄下一行的高度
 }else{
 //否則累加當(dāng)前childView的寬度
 childLeft += childWidth + mHorizontalSpacing;
 }
 }
 height += childTop + lineHeight + getPaddingBottom();
 setMeasuredDimension(widthSize, heighMode == MeasureSpec.EXACTLY ? heighSize : height);
 }

 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 int width = r - l;
 int childLeft = getPaddingLeft();
 int childTop = getPaddingTop();
 int lineHeight = 0;
 //遍歷所有childView根據(jù)其寬和高,計(jì)算子控件應(yīng)該出現(xiàn)的位置
 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);
 // 如果已經(jīng)需要換行
 if (childLeft + childWidth + getPaddingRight() > width) {
 childLeft = getPaddingLeft();
 childTop += mVerticalSpacing + lineHeight;
 lineHeight = childHeight;
 }
 childView.layout(childLeft, childTop, childLeft + childWidth, childTop + childHeight);
 childLeft += childWidth + mHorizontalSpacing;
 }
 }

 private void drawLayout() {
 if (mAdapter == null || mAdapter.getCount() == 0) {
 return;
 }
 removeAllViews();
 for (int i = 0; i < mAdapter.getCount(); i++) {
 View view = mAdapter.getView(i, null, null);
 final int position = i;
 view.setOnClickListener(new View.OnClickListener() {
 @Override
 public void onClick(View v) {
  if (mListener != null) {
  mListener.itemClick(position);
  }
 }
 });
 addView(view);
 }
 }

 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() {
 drawLayout();
 }

 @Override
 public void onInvalidated() {
 super.onInvalidated();
 }
 }
}

2、FlowLayoutAdapter

package com.per.flowlayoutdome;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;

import java.util.List;

/**
 * @author: adan
 * @description: 流式布局適配器
 * @projectName: FlowLayoutDome
 * @date: 2016-06-16
 * @time: 16:22
 */
public class FlowLayoutAdapter extends BaseAdapter {

 private Context mContext;
 private List<String> mList;

 public FlowLayoutAdapter(Context context, List<String> list) {
 mContext = context;
 mList = list;
 }

 @Override
 public int getCount() {
 return mList.size();
 }

 @Override
 public String getItem(int position) {
 return mList.get(position);
 }

 @Override
 public long getItemId(int position) {
 return position;
 }

 @Override
 public View getView(int position, View convertView, ViewGroup parent) {
 ViewHolder holder;
 if (convertView == null) {
 convertView = LayoutInflater.from(mContext).inflate(
  R.layout.item_tag, null);
 holder = new ViewHolder();
 holder.mBtnTag = (Button) convertView.findViewById(R.id.btn_tag);
 convertView.setTag(holder);
 } else {
 holder = (ViewHolder) convertView.getTag();
 }
 holder.mBtnTag.setText(getItem(position));
 return convertView;
 }

 static class ViewHolder {
 Button mBtnTag;
 }
}

3、MainActivity

package com.per.flowlayoutdome;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;


public class MainActivity extends Activity {
 private TextView tv_remind;

 private FlowLayout tcy_my_label, tcy_hot_label;
 private FlowLayoutAdapter mMyLabelAdapter, mHotLabelAdapter;
 private List<String> MyLabelLists, HotLabelLists;

 private static int TAG_REQUESTCODE = 0x101;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_main);
 initView();
 initData();
 }

 private void initView() {
 tv_remind = (TextView) findViewById(R.id.tv_remind);
 tcy_my_label = (FlowLayout) findViewById(R.id.tcy_my_label);
 tcy_hot_label = (FlowLayout) findViewById(R.id.tcy_hot_label);
 }

 private void initData() {
 String[] date = getResources().getStringArray(R.array.tags);
 HotLabelLists = new ArrayList<>();
 for (int i = 0; i < date.length; i++) {
 HotLabelLists.add(date[i]);
 }
 mHotLabelAdapter = new FlowLayoutAdapter(this, HotLabelLists);
 tcy_hot_label.setAdapter(mHotLabelAdapter);
 tcy_hot_label.setItemClickListener(new TagCloudLayoutItemOnClick(1));

 MyLabelLists = new ArrayList<>();
 mMyLabelAdapter = new FlowLayoutAdapter(this, MyLabelLists);
 tcy_my_label.setAdapter(mMyLabelAdapter);
 tcy_my_label.setItemClickListener(new TagCloudLayoutItemOnClick(0));

 String labels = String.valueOf(getIntent().getStringExtra("labels"));
 if (!TextUtils.isEmpty(labels) && labels.length() > 0
 && !labels.equals("null")) {
 String[] temp = labels.split(",");
 for (int i = 0; i < temp.length; i++) {
 MyLabelLists.add(temp[i]);
 }
 ChangeMyLabels();
 }

 }

 /**
 * 刷新我的標(biāo)簽數(shù)據(jù)
 */
 private void ChangeMyLabels() {
 tv_remind.setVisibility(MyLabelLists.size() > 0 ? View.GONE
 : View.VISIBLE);
 tcy_my_label.setVisibility(MyLabelLists.size() > 0 ? View.VISIBLE
 : View.GONE);
 mMyLabelAdapter.notifyDataSetChanged();
 }

 /**
 * 標(biāo)簽的點(diǎn)擊事件
 *
 * @author lijuan
 */
 class TagCloudLayoutItemOnClick implements FlowLayout.TagItemClickListener {
 int index;

 public TagCloudLayoutItemOnClick(int index) {
 this.index = index;
 }

 @Override
 public void itemClick(int position) {
 switch (index) {
 case 0:
  MyLabelLists.remove(MyLabelLists.get(position));
  ChangeMyLabels();
  break;
 case 1:
  if (MyLabelLists.size() < 5) {
  if (HotLabelLists.get(position).equals("自定義")) {
  startActivityForResult(
   new Intent(MainActivity.this,
   AddTagActivity.class),
   TAG_REQUESTCODE);
  } else {
  Boolean isExits = isExist(MyLabelLists,
   HotLabelLists.get(position));
  if (isExits) {
  Toast.makeText(MainActivity.this, "此標(biāo)簽已經(jīng)添加啦", Toast.LENGTH_LONG).show();
  return;
  }
  MyLabelLists.add(HotLabelLists.get(position));
  ChangeMyLabels();
  }
  } else {
  Toast.makeText(MainActivity.this, "最多只能添加5個(gè)標(biāo)簽", Toast.LENGTH_LONG).show();
  }
  break;
 default:
  break;
 }
 }
 }

 /**
 * 將數(shù)組里面的字符串遍歷一遍,看是否存在相同標(biāo)簽
 *
 * @param str
 * @param compareStr
 * @return
 */
 public static Boolean isExist(List<String> str, String compareStr) {
 Boolean isExist = false;//默認(rèn)沒(méi)有相同標(biāo)簽
 for (int i = 0; i < str.size(); i++) {
 if (compareStr.equals(str.get(i))) {
 isExist = true;
 }
 }
 return isExist;
 }

 /**
 * 回傳數(shù)據(jù)
 */
 @Override
 protected void onActivityResult(int requestCode, int resultCode, Intent data) {
 if (TAG_REQUESTCODE == requestCode) {
 if (resultCode == AddTagActivity.TAG_RESULTCODE) {
 String label = data.getStringExtra("tags");
 MyLabelLists.add(label);
 ChangeMyLabels();
 }
 }
 }
}

4、AddTagActivity

package com.per.flowlayoutdome;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

/**
 * @author: xiaolijuan
 * @description: 添加自定義標(biāo)簽
 * @date: 2016-06-10
 * @time: 14:37
 */
public class AddTagActivity extends Activity implements View.OnClickListener{

 private EditText mEtLabel;
 private Button mBtnSure;
 public final static int TAG_RESULTCODE = 0x102;

 @Override
 protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_add_tag);
 initView();
 initData();
 }

 private void initData() {
 // 根據(jù)輸入框輸入值的改變提示最大允許輸入的個(gè)數(shù)
 mEtLabel.addTextChangedListener(new TextWatcher_Enum());
 }

 private void initView() {
 mEtLabel = (EditText) findViewById(R.id.et_label);
 mBtnSure = (Button) findViewById(R.id.btn_sure);

 mBtnSure.setOnClickListener(this);
 }

 @Override
 public void onClick(View v) {
 switch (v.getId()) {
 case R.id.btn_sure:
 String label = mEtLabel.getText().toString();
 if (TextUtils.isEmpty(label)) {
  Toast.makeText(AddTagActivity.this,"自定義標(biāo)簽不應(yīng)為空",Toast.LENGTH_LONG).show();
  return;
 }
 Intent intent = getIntent();
 intent.putExtra("tags", label);
 setResult(TAG_RESULTCODE, intent);
 finish();
 break;
 }
 }

 /**
 * 根據(jù)輸入框輸入值的長(zhǎng)度超過(guò)8個(gè)字符的時(shí)候,彈出輸入的標(biāo)簽應(yīng)控制在8個(gè)字
 *
 * @author lijuan
 *
 */
 class TextWatcher_Enum implements TextWatcher {
 @Override
 public void beforeTextChanged(CharSequence s, int start, int count,
   int after) {
 }

 @Override
 public void onTextChanged(CharSequence s, int start, int before,
   int count) {
 int lenght = mEtLabel.getText().toString().trim().length();
 if (lenght > 8) {
 Toast.makeText(AddTagActivity.this,"輸入的標(biāo)簽應(yīng)控制在8個(gè)字",Toast.LENGTH_LONG).show();
 }
 }

 @Override
 public void afterTextChanged(Editable s) {

 }
 }
}

5、activity_main.xml在上面已經(jīng)貼出來(lái)了,在這里就不重復(fù)了,我們創(chuàng)建了arrays.xml,在這里定義了一寫熱門的標(biāo)簽:

<?xml version="1.0" encoding="UTF-8"?>
<resources>

 <string-array name="tags">
 <item>美妝</item>
 <item>畫板</item>
 <item>漫畫</item>
 <item>高科技</item>
 <item>韓國(guó)電影</item>
 <item>股票</item>
 <item>美術(shù)</item>
 <item>高富帥</item>
 <item>鴻泰安</item>
 <item>運(yùn)動(dòng)</item>
 <item>外語(yǔ)</item>
 <item>財(cái)經(jīng)</item>
 <item>大叔</item>
 <item>非主流</item>
 <item>暴走漫畫</item>
 <item>心理學(xué)</item>
 <item>漢語(yǔ)</item>
 <item>白富美</item>
 <item>自定義</item>
 </string-array>

</resources>

6、item_tag.xml

<?xml version="1.0" encoding="utf-8"?>
<Button xmlns:android="http://schemas.android.com/apk/res/android"
 android:id="@+id/btn_tag"
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:background="@drawable/selector_btn_item"
 android:gravity="center"
 android:minHeight="30dp"
 android:minWidth="45dp"
 android:paddingLeft="16dp"
 android:paddingRight="16dp"
 android:textSize="12sp" />

6、activity_add_tag.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 android:layout_width="250dp"
 android:layout_height="wrap_content"
 android:background="@android:color/white"
 android:gravity="center_horizontal"
 android:orientation="vertical"
 android:padding="5dp" >

 <LinearLayout
 android:layout_width="match_parent"
 android:layout_height="wrap_content"
 android:orientation="vertical" >

 <TextView
 android:layout_width="wrap_content"
 android:layout_height="wrap_content"
 android:layout_marginLeft="5dp"
 android:text="請(qǐng)輸入想要添加的標(biāo)簽"
 android:textColor="@android:color/black"
 android:textSize="16dp" />

 <EditText
 android:id="@+id/et_label"
 android:layout_width="match_parent"
 android:layout_height="80dp"
 android:layout_margin="5dp"
 android:background="@drawable/selector_btn_item"
 android:gravity="center_vertical|start"
 android:maxLength="8"
 android:paddingLeft="10dp"
 android:textColor="@android:color/black"
 android:textSize="16dp" />
 </LinearLayout>

 <Button
 android:id="@+id/btn_sure"
 android:layout_width="50dp"
 android:layout_height="32dp"
 android:layout_marginLeft="16dp"
 android:layout_marginRight="16dp"
 android:layout_marginTop="5dp"
 android:background="#38353D"
 android:gravity="center"
 android:text="確定"
 android:textColor="@android:color/white"
 android:textSize="14dp" />

</LinearLayout>

7、selector_btn_item.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
 <item android:state_pressed="true">
 <shape>
 <solid android:color="#ff76787b" />
 <corners android:bottomLeftRadius="5dp" android:bottomRightRadius="5dp" android:topLeftRadius="5dp" android:topRightRadius="5dp" />
 <stroke android:width="1px" android:color="#ffd1d1d1" />
 </shape>
 </item>
 <item>
 <shape>
 <solid android:color="#ffffff" />
 <corners android:bottomLeftRadius="2.5dp" android:bottomRightRadius="2.5dp" android:topLeftRadius="2.5dp" android:topRightRadius="2.5dp" />
 <stroke android:width="0.5px" android:color="#ffd1d1d1" />
 </shape>
 </item>
</selector>

最后一點(diǎn)了吧,我們?cè)贏ndroidManifest.xml中需要添加

<activity
 android:name=".AddTagActivity"
 android:theme="@style/dialogstyle" />

用于我們自定義標(biāo)簽,彈出的一個(gè)類似于對(duì)話框的一個(gè)Activity,這里我們引用了自定義一個(gè)樣式

<style name="dialogstyle">
 <!--設(shè)置dialog的背景-->
 <item name="android:windowBackground">@android:color/transparent</item>
 <!--設(shè)置Dialog的windowFrame框?yàn)闊o(wú)-->
 <item name="android:windowFrame">@null</item>
 <!--設(shè)置無(wú)標(biāo)題-->
 <item name="android:windowNoTitle">true</item>
 <!--是否浮現(xiàn)在activity之上-->
 <item name="android:windowIsFloating">true</item>
 <!--是否半透明-->
 <item name="android:windowIsTranslucent">true</item>
 <!--設(shè)置窗口內(nèi)容不覆蓋-->
 <item name="android:windowContentOverlay">@null</item>
 <!--設(shè)置動(dòng)畫,在這里使用讓它繼承系統(tǒng)的Animation.Dialog-->
 <item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
 <!--背景是否模糊顯示-->
 <item name="android:backgroundDimEnabled">true</item>
 </style>

對(duì)于這個(gè)類似于對(duì)話框的一個(gè)Activity,有不明白的可以上我之前的一篇文章: Android中使用Dialog風(fēng)格彈出框的Activity

下載:源碼

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • Kotlin Lambda表達(dá)式實(shí)踐使用介紹

    Kotlin Lambda表達(dá)式實(shí)踐使用介紹

    lambda 本質(zhì)上是可以傳遞給函數(shù)的一小段代碼,Kotlin 與 Java 中的 Lambda 有一定的區(qū)別,除了對(duì) lambda 的全面支持外,還有內(nèi)聯(lián)函數(shù)等簡(jiǎn)潔高效的特性。下面我們來(lái)仔細(xì)看一下
    2022-12-12
  • Android Handler 原理分析及實(shí)例代碼

    Android Handler 原理分析及實(shí)例代碼

    這篇文章主要介紹了Android Handler 原理分析及實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Android使用DisplayManager創(chuàng)建虛擬屏流程及原理解析

    Android使用DisplayManager創(chuàng)建虛擬屏流程及原理解析

    這篇文章主要介紹了Android使用DisplayManager創(chuàng)建虛擬屏流程及原理解析,DisplayManager提供了createVirtualDisplay接口,用于創(chuàng)建虛擬屏,虛擬屏可以把屏幕分出不同的區(qū)域,需要的朋友可以參考下
    2024-05-05
  • android繪制多個(gè)黑豎線條

    android繪制多個(gè)黑豎線條

    這篇文章主要為大家詳細(xì)介紹了android繪制多個(gè)黑豎線條,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-05-05
  • Android自定義 WebView瀏覽器

    Android自定義 WebView瀏覽器

    WebView是Android中一個(gè)非常實(shí)用的組件,它和Safai、Chrome一樣都是基于Webkit網(wǎng)頁(yè)渲染引擎。接下來(lái)通過(guò)本文給大家介紹android自定義webview瀏覽器,感興趣的朋友一起學(xué)習(xí)吧
    2016-05-05
  • Android更改EditText下劃線顏色樣式的方法

    Android更改EditText下劃線顏色樣式的方法

    Android 里 EditText下劃線有默認(rèn)的顏色樣式,如何修改其顏色,而且想單獨(dú)定義某一個(gè)界面的顏色樣式呢。下面這篇文章主要介紹了Android更改EditText下劃線顏色樣式的方法,需要的朋友可以參考下
    2017-01-01
  • 安卓GET與POST網(wǎng)絡(luò)請(qǐng)求的三種方式

    安卓GET與POST網(wǎng)絡(luò)請(qǐng)求的三種方式

    今天小編就為大家分享一篇關(guān)于安卓GET與POST網(wǎng)絡(luò)請(qǐng)求的三種方式,小編覺(jué)得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-12-12
  • Android 更新RecyclerView的好方法

    Android 更新RecyclerView的好方法

    在使用RecyclerView的時(shí)候不免要修改RecyclerView的數(shù)據(jù),使用notifyDataSetChanged()來(lái)刷新界面,但是當(dāng)數(shù)據(jù)多,而只是修改了一點(diǎn)的數(shù)據(jù),或者刷新比較頻繁,這樣就會(huì)導(dǎo)致界面卡頓,用戶交互特別不好,這時(shí)可以使用RecyclerView方法解決,具體實(shí)現(xiàn)代碼大家參考下本文吧
    2017-06-06
  • Android開(kāi)發(fā)必備:秒殺真機(jī)超快模擬器Genymotion介紹

    Android開(kāi)發(fā)必備:秒殺真機(jī)超快模擬器Genymotion介紹

    這篇文章主要介紹了Android開(kāi)發(fā)必備:秒殺真機(jī)超快模擬器Genymotion介紹,本文直接用圖片說(shuō)明Genymotion的安裝和模擬效果,并提供官網(wǎng),需要的朋友可以參考下
    2015-04-04
  • Android自定義viewgroup 使用adapter適配數(shù)據(jù)(6)

    Android自定義viewgroup 使用adapter適配數(shù)據(jù)(6)

    這篇文章主要為大家詳細(xì)介紹了Android自定義viewgroup,使用adapter適配數(shù)據(jù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-12-12

最新評(píng)論

邓州市| 运城市| 苍山县| 莎车县| 东丽区| 新昌县| 广汉市| 扬中市| 绥江县| 玉林市| 永寿县| 海宁市| 宝丰县| 玉门市| 溧水县| 澜沧| 龙胜| 美姑县| 苍山县| 武安市| 手游| 伊宁县| 广汉市| 桦川县| 红原县| 鸡东县| 芦山县| 乐亭县| 青浦区| 大连市| 乐平市| 民勤县| 克山县| 平和县| 万源市| 格尔木市| 南充市| 班玛县| 洪洞县| 桦南县| 肇东市|