日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 运维知识 > Android >内容正文

Android

android 自定义flowlayout,Android 自定义ViewGroup之实现FlowLayout-标签流容器

發(fā)布時(shí)間:2024/1/23 Android 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 自定义flowlayout,Android 自定义ViewGroup之实现FlowLayout-标签流容器 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

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

這里寫圖片描述

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

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

2、ViewGroup的種類:常見的有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í)候才添加上的

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

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

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

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

xmlns:custom="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:orientation="vertical">

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" />

android:layout_width="match_parent"

android:layout_height="wrap_content">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical">

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" />

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" />

android:layout_width="match_parent"

android:layout_height="10dp"

android:background="#f6f6f6" />

android:layout_width="match_parent"

android:layout_height="46dp"

android:background="@android:color/white">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_centerVertical="true"

android:paddingLeft="15dp"

android:text="推薦標(biāo)簽 "

android:textSize="16dp" />

android:layout_width="match_parent"

android:layout_height="1dp"

android:background="#f6f6f6" />

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" />

一定要引入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)造方法中獲得自定義屬性。

一開始一個(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 然后開啟新行

if (childWidth + childLeft + getPaddingRight() > widthSize) {

childLeft = getPaddingLeft();// 重新開啟新行,開始記錄childLeft

childTop += mVerticalSpacing + childHeight;// 疊加當(dāng)前的高度

lineHeight = childHeight;// 開啟記錄下一行的高度

}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 然后開啟新行

if (childWidth + childLeft + getPaddingRight() > widthSize) {

childLeft = getPaddingLeft();// 重新開啟新行,開始記錄childLeft

childTop += mVerticalSpacing + childHeight;// 疊加當(dāng)前的高度

lineHeight = childHeight;// 開啟記錄下一行的高度

}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 mList;

public FlowLayoutAdapter(Context context, List 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 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 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) {

}

}

}

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

美妝

畫板

漫畫

高科技

韓國(guó)電影

股票

美術(shù)

高富帥

鴻泰安

運(yùn)動(dòng)

外語(yǔ)

財(cái)經(jīng)

大叔

非主流

暴走漫畫

心理學(xué)

漢語(yǔ)

白富美

自定義

7、item_tag.xml

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" />

8、activity_add_tag.xml

android:layout_width="250dp"

android:layout_height="wrap_content"

android:background="@android:color/white"

android:gravity="center_horizontal"

android:orientation="vertical"

android:padding="5dp" >

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical" >

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" />

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" />

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" />

9、selector_btn_item.xml

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

android:name=".AddTagActivity"

android:theme="@style/dialogstyle" />

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

@android:color/transparent

@null

true

true

true

@null

@android:style/Animation.Dialog

true

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

好了,已經(jīng)全部寫完了,有什么疑問(wèn)的,請(qǐng)?jiān)谙旅媪粞?#xff0c;有不足的還望指導(dǎo),感謝各位_

總結(jié)

以上是生活随笔為你收集整理的android 自定义flowlayout,Android 自定义ViewGroup之实现FlowLayout-标签流容器的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。