一、概述:

在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何

自定义一个类似热门标签那样的流式布局吧

类似的自定义换行流式布局控件。下面我们就来详细介绍流式布局的应用特点以及用的的技术点:

1.流式布局的特点以及应用场景    特点:当上面一行的空间不够容纳新的TextView时候,    才开辟下一行的空间

原理图:

场景:主要用于关键词搜索或者热门标签等场景

2.自定义ViewGroup,重点重写下面两个方法

1、onMeasure:测量子view的宽高,设置自己的宽和高

2、onLayout:设置子view的位置

onMeasure:根据子view的布局文件中属性,来为子view设置测量模式和测量值    测量=测量模式+测量值;

测量模式有3种:    EXACTLY:表示设置了精确的值,一般当childView设置其宽、高为精确值、match_parent时,ViewGroup会将其设置为EXACTLY;    AT_MOST:表示子布局被限制在一个最大值内,一般当childView设置其宽、高为wrap_content时,ViewGroup会将其设置为AT_MOST;    UNSPECIFIED:表示子布局想要多大就多大,一般出现在AadapterView的item的heightMode中、ScrollView的childView的heightMode中;此种模式比较少见。

3.LayoutParams    ViewGroup LayoutParams :每个 ViewGroup 对应一个 LayoutParams; 即 ViewGroup -> LayoutParams    getLayoutParams 不知道转为哪个对应的LayoutParams ,其实很简单,就是如下:    子View.getLayoutParams 得到的LayoutParams对应的就是 子View所在的父控件的LayoutParams;    例如,LinearLayout 里面的子view.getLayoutParams ->LinearLayout.LayoutParams    所以 咱们的FlowLayout 也需要一个LayoutParams,由于上面的效果图是子View的 margin,    所以应该使用MarginLayoutParams。即FlowLayout->MarginLayoutParams

4.最后来看看实现的最终效果图:

二、热门标签的流式布局的实现:

1. 自定义热门标签的ViewGroup实现

根据上面的技术分析,自定义类继承于ViewGroup,并重写 onMeasure和onLayout等方法。具体核心实现代码如下:package com.czm.flowlayout;

import java.util.ArrayList;

import java.util.List;

import android.content.Context;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

/**

*

* @author caizhiming

*

*/

public class XCFlowLayout extends ViewGroup{

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

// TODO Auto-generated method stub

//父控件传进来的宽度和高度以及对应的测量模式

int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);

int modeWidth = MeasureSpec.getMode(widthMeasureSpec);

int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);

int modeHeight = MeasureSpec.getMode(heightMeasureSpec);

//如果当前ViewGroup的宽高为wrap_content的情况

int width = 0;//自己测量的 宽度

int height = 0;//自己测量的高度

//记录每一行的宽度和高度

int lineWidth = 0;

int lineHeight = 0;

//获取子view的个数

int childCount = getChildCount();

for(int i = 0;i

View child = getChildAt(i);

//测量子View的宽和高

measureChild(child, widthMeasureSpec, heightMeasureSpec);

//得到LayoutParams

MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

//子View占据的宽度

int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;

//子View占据的高度

int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;

//换行时候

if(lineWidth + childWidth > sizeWidth){

//对比得到最大的宽度

width = Math.max(width, lineWidth);

//重置lineWidth

lineWidth = childWidth;

//记录行高

height += lineHeight;

lineHeight = childHeight;

}else{//不换行情况

//叠加行宽

lineWidth += childWidth;

//得到最大行高

lineHeight = Math.max(lineHeight, childHeight);

}

//处理最后一个子View的情况

if(i == childCount -1){

width = Math.max(width, lineWidth);

height += lineHeight;

}

}

//wrap_content

setMeasuredDimension(modeWidth == MeasureSpec.EXACTLY ? sizeWidth : width,

modeHeight == MeasureSpec.EXACTLY ? sizeHeight : height);

}

@Override

protected void onLayout(boolean changed, int l, int t, int r, int b) {

// TODO Auto-generated method stub

mAllChildViews.clear();

mLineHeight.clear();

//获取当前ViewGroup的宽度

int width = getWidth();

int lineWidth = 0;

int lineHeight = 0;

//记录当前行的view

List lineViews = new ArrayList();

int childCount = getChildCount();

for(int i = 0;i

View child = getChildAt(i);

MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

int childWidth = child.getMeasuredWidth();

int childHeight = child.getMeasuredHeight();

//如果需要换行

if(childWidth + lineWidth + lp.leftMargin + lp.rightMargin > width){

//记录LineHeight

mLineHeight.add(lineHeight);

//记录当前行的Views

mAllChildViews.add(lineViews);

//重置行的宽高

lineWidth = 0;

lineHeight = childHeight + lp.topMargin + lp.bottomMargin;

//重置view的集合

lineViews = new ArrayList();

}

lineWidth += childWidth + lp.leftMargin + lp.rightMargin;

lineHeight = Math.max(lineHeight, childHeight + lp.topMargin + lp.bottomMargin);

lineViews.add(child);

}

//处理最后一行

mLineHeight.add(lineHeight);

mAllChildViews.add(lineViews);

//设置子View的位置

int left = 0;

int top = 0;

//获取行数

int lineCount = mAllChildViews.size();

for(int i = 0; i

//当前行的views和高度

lineViews = mAllChildViews.get(i);

lineHeight = mLineHeight.get(i);

for(int j = 0; j

View child = lineViews.get(j);

//判断是否显示

if(child.getVisibility() == View.GONE){

continue;

}

MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

int cLeft = left + lp.leftMargin;

int cTop = top + lp.topMargin;

int cRight = cLeft + child.getMeasuredWidth();

int cBottom = cTop + child.getMeasuredHeight();

//进行子View进行布局

child.layout(cLeft, cTop, cRight, cBottom);

left += child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;

}

left = 0;

top += lineHeight;

}

}

}

2.相关的布局文件:

引用自定义控件:

xmlns:tools="http://schemas.android.com/tools"

android:id="@+id/container"

android:layout_width="match_parent"

android:layout_height="match_parent" >

android:id="@+id/flowlayout"

android:layout_width="match_parent"

android:layout_height="match_parent" >

三、使用该自定义布局控件类

最后,如何使用该自定义的热门标签控件类呢?很简单,请看下面实例代码:package com.czm.flowlayout;

import android.app.Activity;

import android.graphics.Color;

import android.os.Bundle;

import android.view.ViewGroup.LayoutParams;

import android.view.ViewGroup.MarginLayoutParams;

import android.widget.TextView;

/**

*

* @author caizhiming

*

*/

public class MainActivity extends Activity {

private String mNames[] = {

"welcome","android","TextView",

"apple","jamy","kobe bryant",

"jordan","layout","viewgroup",

"margin","padding","text",

"name","type","search","logcat"

};

private XCFlowLayout mFlowLayout;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

initChildViews();

}

private void initChildViews() {

// TODO Auto-generated method stub

mFlowLayout = (XCFlowLayout) findViewById(R.id.flowlayout);

MarginLayoutParams lp = new MarginLayoutParams(

LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);

lp.leftMargin = 5;

lp.rightMargin = 5;

lp.topMargin = 5;

lp.bottomMargin = 5;

for(int i = 0; i

TextView view = new TextView(this);

view.setText(mNames[i]);

view.setTextColor(Color.WHITE);

view.setBackgroundDrawable(getResources().getDrawable(R.drawable.textview_bg));

mFlowLayout.addView(view,lp);

}

}

}

四、项目代码目录结构图

android自定义view流布局,Android控件进阶-自定义流式布局和热门标签控件相关推荐

  1. android 热搜词 布局,Android FlowLayout流式布局打造热门标签(高仿抖音热搜)

    需要先学习下面2个内容 1.已经基本给大家介绍了如何自定义ViewGroup,如果你还不了解 2.宽高的计算 一.XML布局 从布局图中可以看到,FlowLayout中包含了很多TextView.难度 ...

  2. Android 实现FlowLayout流式布局(热门标签)

    先上效果图: 接着看代码实现: public class FlowLayout extends ViewGroup {protected DataSetObserver mDataSetObserve ...

  3. Android自定义流式布局-FlowLayout

    很多App在搜索页时都有对热门标签的一个排列,而Android官方没有对应的布局控件,所以自己写了一个流式布局(也称标签布局)--FlowLayout. 为了大家使用的方便,没有添加自定义属性,所以需 ...

  4. android分组流式布局,Android 流式布局实现

    概述 本文主要分享Android流式布局实现,实现效果如下: 在实现之前先来看一下View的生命周期,如下图: 流式布局属于自定义ViewGroup,重点关注onMeasure与onLayout方法 ...

  5. Android自定义组合布局,Android 流式布局 + 自定义组合控件

    自定义组合控件 package yanjupeng.bawei.com.day09.two; import android.content.Context; import android.util.A ...

  6. android 自定义view实现拖动放大缩小_自定义itemCheckView

    阅读五分钟,每日十点,和您一起终身学习,这里是程序员Android 本篇文章主要介绍 Android 开发中的部分知识点,通过阅读本篇文章,您将收获以下内容: 自定义View类实现 自定义View标签 ...

  7. Android 自定义View大全,Android中自定义View的实现方式总结大全

    Android自定义view是什么 在我们的日常开发中,很多时候系统提供的view是无法满足我们的需求的,例如,我们想给一个edittext加上清除按钮,等等. 这时候我们就需要对系统的view进行扩 ...

  8. Android自定义View之实现流式布局

    Android自定义View之实现流式布局 运行效果 流式布局 把子控件从左到右摆放,如果一行放不下,自动放到下一行 自定义布局流程 1. 自定义属性:声明,设置,解析获取自定义值 在attr.xml ...

  9. android 自定义view实现拖动放大缩小_自定义itemClickView

    和你一起终身学习,这里是程序员Android 经典好文推荐,通过阅读本文,您将收获以下知识点: 一.自定义View类实现 二.自定义View标签 三.自定义View 布局 四.自定义View 选择器 ...

最新文章

  1. 剑指offer:链表中环的入口结点
  2. MAVEN约定的目录结构
  3. 创作一个数字人,总共分几步?(上)
  4. decimal类型对象里面定义什么类型_奥斯塔罗 单身开启桃花雷达 现阶段的我适合什么类型的对象?...
  5. 哪些服务器支持win8系统,Win8服务器版更名Windows Server 2012
  6. mybatis一对多和多对一
  7. Ultra Librarian 生成Orcad封装教程
  8. 教程--免费为小程序接入客服机器人
  9. 如何使用微PE给电脑装windows10系统?
  10. Qt获取CPU编号和硬盘序列号
  11. 详解SQL Server STUFF的用法
  12. Go 使用for range time.Tick() 设置定时器
  13. 3w+字详解 23 种设计模式(多图 + 代码)
  14. java如何将两首歌按时间合成,用goldwave怎样把两首歌合并在一起
  15. 我在本科的第一个App项目
  16. 如何提高网站安全防护?
  17. 网络知识点之—UDP协议
  18. LSM6DS3驱动编写——learn form sparkfun company
  19. 1073 多选题常见计分法
  20. 管姓取名女孩儒雅大气

热门文章

  1. java io 工具,commonIO
  2. 大数据赋能交通业务管理——远眺智慧交通集成管控系统
  3. r610服务器 安装系统,dell r610服务器安装windows7系统
  4. ORACLE函数大全
  5. 神牛的养成计划---可持久化trie
  6. java context是什么意思_context什么意思
  7. 《数理经济学的基本方法》
  8. User表及相关操作
  9. Apache knox 版本升级后的小问题
  10. unicode 详解