android 自定义流布局。实现热门标签。开源库SimpleFlowLayout

前言

实际项目中需要实现一个 热门搜索 的栏目,类似下图:

由于 子项(子view) 中的文字是可变的,一行能显示的 子项 的个数也无法确定。需要支持自动换行和计算位置。

开源类库

我自己写了个 自定义view ,继承自viewGroup, 来实现它,托管到github开源平台。

名称:SimpleFlowLayout

地址:https://github.com/vir56k/SimpleFlowLayout

特点:可以不断添加多个子view,计算位置,自动换行。 类似html中的div标签

适用: 热门标签

实现思路

 要实现 自定义的viewgroup,需要:

1. 继承自 ViewGroup

2. 实现 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

  这个方法用于测量 自己(自定义view)本身需要的宽度和高度

3. 实现 protected void onLayout(boolean changed, int l, int t, int r, int b)

  这个方法用于指定如何摆放 子view 的位置。

实现代码

package zhangyf.vir56k.flowframelayout;

import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;

/**
 * name: android 简单的流布局自定义view
 * 作者:张云飞
 * 特点:可以不断添加多个子view,计算位置,自动换行。
 * 适用: 热门标签
 * Created by zhangyunfei on 15/12/4.
 */
public class SimpleFlowLayout extends ViewGroup {
    public SimpleFlowLayout(Context context) {
        super(context);
    }

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

    public SimpleFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMax = MeasureSpec.getSize(widthMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMax = MeasureSpec.getSize(heightMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        int widthNeed = 0;
        int heightNeed = 0;
        int x = 0;
        int y = 0;
        int currentLineHeight = 0;
        View child;
        for (int i = 0; i < getChildCount(); i++) {
            child = getChildAt(i);
            if (child.getVisibility() == View.GONE) {
                continue;
            }

            child.measure(widthMeasureSpec, heightMeasureSpec);
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();//获得子view的 外边距
            //测算子view宽度,本行这句代码有问题,不能计算子view的自动换行 int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            //使用viewGroup的measureChildWithMargins测算宽度,在这个方法里处理了 LayoutParams的match_parent等方式的处理
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);

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

            if (x + childWidth > widthMax) {//换行处理,本行高度和x轴都清零,y轴下移(加上上次的行高)
                y += currentLineHeight;
                currentLineHeight = 0;
                x = 0;
            }
            x += childWidth;
            currentLineHeight = Math.max(currentLineHeight, childHeight);

            widthNeed = Math.max(widthNeed, x);//加入了这个 子view后,留下最大宽度
            heightNeed = Math.max(heightNeed, y + currentLineHeight);//对比上次的,留下最大的高度
        }
        setMeasuredDimension(widthMode == MeasureSpec.EXACTLY ? widthMax : widthNeed,
                heightMode == MeasureSpec.EXACTLY ? heightMax : heightNeed);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        int widthMax = getWidth();
        int x, y;
        x = 0;
        y = 0;
        View child;
        int left = 0;
        int top = 0;
        int currentLineHeight = 0;
        for (int i = 0; i < getChildCount(); i++) {
            child = getChildAt(i);
            if (child.getVisibility() == View.GONE) {
                continue;
            }
            MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
            int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
            int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
            if (x + childWidth > widthMax) {//换行处理
                y += currentLineHeight;
                x = 0;
                currentLineHeight = 0;
            }
            left = x + lp.leftMargin;
            top = y + lp.topMargin;
            //定位子view的位置
            child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());

            x += childWidth;
            currentLineHeight = Math.max(currentLineHeight, childHeight);
        }
    }

    @Override
    public LayoutParams generateLayoutParams(AttributeSet attrs) {
        return new MarginLayoutParams(getContext(), attrs);
    }

}

  

时间: 2024-10-24 01:52:41

android 自定义流布局。实现热门标签。开源库SimpleFlowLayout的相关文章

Android中常见的热门标签的流式布局的实现

一.概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出) 类似的自定义布局.下面我们就来详细介绍流式布局的应用特点以及用的的技术点: 1.流式布局的特点以及应用场景    特点:当上面一行的空间不够容纳新的TextView时候,    才开辟下一行的空间 原理图: 场景:主要用于关键词搜索或者热门标签等场景2.自定义ViewGroup,重点重写下面两个方法 1.o

iOS 热门高效开源库集锦,收藏备用

一.推荐使用的第三方库 1:基于响应式编程思想的ReactiveCocoa 地址:https://github.com/ReactiveCocoa/ReactiveCocoa 2:iOS解耦与组件化开发神器-FFRouter 地址:https://github.com/imlifengfeng/FFRouter 3:XML/HTML解析 地址:https://github.com/topfunky/hpple 4:有文字输入时,能根据键盘是否弹出来调整自身显示内容的位置 地址:https://g

android流式布局热门标签的实现

在日常的app使用中,我们会在android 的app中看见热门标签等自动换行的流式布局,今天就为大家分享一种android流式布局的实现. 先看最终效果 自定义流式布局的实现 package com.sunny.flowlayout.view; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.util.AttributeSet; import an

关于Android沉浸式通知栏的一个开源库SystemBarTint简单使用

SystemBarTint链接:https://github.com/jgilfelt/SystemBarTint 最早听这个概念是在MI4发布会上,雷布斯鼓吹的一个概念,让原先安然无光,黑色的通知栏,变成与APP主题相一致的颜色,经过度娘,得知是从4.4开始,Android已经有这个概念(ImmersiveMode)了. 效果如下: 使用方法比较简单,官方给了一个例子: public class MatchActionBarActivity extends Activity { @Overri

Android 开源库获取途径整理

介绍目前收藏 Android 开源库比较多的 GitHub 项目.网站.Twitter.App 及如何获取最新的 Android 开源库. 1. GitHub Android 开源项目汇总 Android 优秀开源项目实现原理解析 把这两个放在前面,是因为这两个项目我和一群小伙伴在精心维护,同时任何人都可以提交 PR 参与进来.其他网站或 App 都可以以此为数据源 AndroidElementals 西班牙一工程师整理的,目前项目数量和介绍上与 Android 开源项目汇总 还有一定差距 2.

android开源库发布到jcenter图文详解与填坑

相信很多人都用过开源项目,特别是android studio普及以后,使用开源库更方便简单.而如何上传开源库到jcenter供大家方便使用,虽然网上也有教程,但还是遇坑了,最后总结一下,希望可以帮助大家. [csdn地址: http://blog.csdn.net/zhangke3016/article/details/52075159] [本文简书地址: http://www.jianshu.com/p/0acf9e05b27e]同步更新 AndroidStudio是从Maven Reposi

Android开源库与设计模式开源组SAOS建立

Android开源库与设计模式开源组建立 简介 在2014年年底突然参与了CSDN的博客之星评选,看着自己的博客水平实在太低,于是就想一定得写一些跟别人不太一样的博客出来.经过自己的一番思考,觉得在Android开源库的深入实现上并没有什么太多的资料,或者只是大概讲述了一些基本原理.这样我觉得是不够的,很多事情你没有自己去经历你不会有很深的认识,或者你根本不知道原来它会出现这样的问题.于是我就想我没通过学习轮子制造过程来更加深入的学习,这样不仅能够了解那些知名的开源库,也能够从实战的角度学习开源

Android自定义View--自己撸一个柱状图也没那么难

绪论 *转眼间,2016伴随着互联网寒冬和帝都的雾霾马上就过去了,不知道大家今年一整年过得怎么样?最近票圈被各个城市的雾霾刷屏, 内心难免会动荡,庆幸自己早出来一年,也担忧着自己的未来的职业规划.无所谓了,既然选择了这个行业,我觉得大家就应该坚持下去,路是自己走的,及时再寒冬,只要你足够优秀,足够努力,相信你最后还是会找到自己满意的工作的.最后还要感谢今年博客之星大家对我的投票支持,非常感谢.不多说了,今天的主题是它–对,自定义View柱状图. 先来说说我最近在做什么吧?好久没有写博客了,最近手

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

本篇文章讲的是Android 自定义ViewGroup之实现标签流式布局-FlowLayout,开发中我们会经常需要实现类似于热门标签等自动换行的流式布局的功能,网上也有很多这样的FlowLayout,但不影响我对其的学习.和往常一样,主要还是想总结一下自定义ViewGroup的开发过程以及一些需要注意的地方. 按照惯例,我们先来看看效果图 一.写代码之前,有几个是问题是我们先要弄清楚的: 1.什么是ViewGroup:从名字上来看,它可以被翻译为控件组,言外之意是ViewGroup内部包含了许