Android View - 实现流式布局

Android 组件 —— 流式布局 这是一个Android流式布局,根据鸿翔大神之前写的FlowLayout设计思路结合Material库中的ChipGroup设计架构衍生而来,全新的流式布局组件。 阅读详情

流式布局,就是一个容器(ViewGroup),往里面添加元素(子View),元素会一直跟在前一个元素的左边,如果超过容器的边界,就把元素放在下一行的第一个位置。Like This:

我们自己来实现一下这么一种布局,在实现之前,你需要理解关于自定义ViewGroup相关的知识,可以参考 Android 手把手教您自定ViewGroup;如果没问题,接着往下看。

网上已经有很多人实现流式布局了,不过大部分都是静态设置数据,也就是说直接在xml添加子View,像这样:

<com.zhy.zhy_flowlayout02.FlowLayout  
    android:layout_width="fill_parent"  
    android:layout_height="wrap_content" >  
    <TextView  
        style="@style/text_flag_01"  
        android:text="Welcome" />  
    <TextView  
        style="@style/text_flag_01"  
        android:text="IT工程师" />  
    <TextView  
        style="@style/text_flag_01"  
        android:text="学习ing" />  
    ... 
</com.zhy.zhy_flowlayout02.FlowLayout>

出自Android 自定义ViewGroup 实战篇 -> 实现FlowLayout
下面我实现的动态设置子View,像ListView和GridView一样,直接上码!!

流式布局FlowLayout

新建类,继承ViewGroup
// FlowLayout类
public class FlowLayout extends ViewGroup {
    /** 子View之间水平距离 */
    private int horizontalSpace = 0;
    /** 子View之间垂直距离 */
    private int verticalSpace = 0;
    // 构造
    public FlowLayout(Context context, AttributeSet attrs) {
        super(context, attrs);
        TypedArray array = context.obtainStyledAttributes(attrs, R.styleable.FlowLayout);
        horizontalSpace = array.getDimensionPixelOffset(R.styleable.FlowLayout_horizontal_space, 0);
        verticalSpace = array.getDimensionPixelOffset(R.styleable.FlowLayout_vertical_space, 0);
        array.recycle();
    }
}

支持xml定义水平距离和垂直距离。

计算所有子View的高宽(测量)
// FlowLayout类
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // 取出宽高的模式
    int widthMode = MeasureSpec.getMode(widthMeasureSpec);
    int heightMode = MeasureSpec.getMode(heightMeasureSpec);
    // 取出宽高的大小
    int widthSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSize = MeasureSpec.getSize(heightMeasureSpec);
    // 子View的个数
    int childCount = getChildCount();
    // 计算宽度
    int calculateWidth = 0;
    // 计算高度
    int calculateHeight = 0;
    // 行宽度
    int lineWidth = 0;
    // 行高度
    int lineHeight = 0;
    // 计算,遍历所有子View
    for (int index = 0; index < childCount; index++) {
        View childView = getChildAt(index);
        // 测量子View
        measureChild(childView, widthMeasureSpec, heightMeasureSpec);
        // 子View宽度
        int childWidth = childView.getMeasuredWidth() + horizontalSpace;
        // 子View高度
        int childHeight = childView.getMeasuredHeight();
        // 如果 当前行宽 + 当前子View宽度 > 最大宽度
        if (childWidth + lineWidth > widthSize) {
            // 换行
            // 更新计算宽度,如果当前行宽大于之前计算宽度,则计算宽度=当前行宽
            calculateWidth = Math.max(lineWidth, calculateWidth);
            // 计算高度累加当前行高
            calculateHeight += lineHeight + (calculateHeight == 0 ? 0 : verticalSpace);
            // 更新当前行宽
            lineWidth = childWidth;
            // 更新当前行高
            lineHeight = childHeight;
        } else {
            // 不换行
            // 累加当前行宽
            lineWidth += childWidth;
            // 更新当前行高,如果当前子View总高度大于当前行高,则当前行高=当前子View总高度
            lineHeight = Math.max(childHeight, lineHeight);
        }
        // 判断是否最后一个
        if (index == childCount - 1) {
            // 更新计算宽度,如果当前行宽大于之前计算宽度,则计算宽度=当前行宽
            calculateWidth = Math.max(lineWidth, calculateWidth);
            // 计算高度累加当前行高
            calculateHeight += lineHeight + (calculateHeight == 0 ? 0 : verticalSpace);
        }
    }
    // 如果是EXACTLY模式,直接设置用户指定的宽度
    int measureWidth = widthMode == MeasureSpec.EXACTLY ? widthSize : calculateWidth;
    // 如果是EXACTLY模式,直接设置用户指定的高度
    int measureHeight = heightMode == MeasureSpec.EXACTLY ? heightSize : calculateHeight;
    // 设置宽高
    setMeasuredDimension(measureWidth, measureHeight);
}
设置所有子View的位置(布局)
// FlowLayout类
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
    // 子View的个数
    int childCount = getChildCount();
    // 获取最大宽度
    int maxWidth = getWidth();
    // 行宽
    int lineWidth = 0;
    // 行高
    int lineHeight = 0;
    // 记录高度
    int recordHeight = 0;
    // 布局,遍历所有子View
    for (int index = 0; index < childCount; index++) {
        View childView = getChildAt(index);
        int childWidth = childView.getMeasuredWidth() + horizontalSpace;
        int childHeight = childView.getMeasuredHeight();
        // 如果 当前行宽 + 当前子View总宽度 > 最大宽度
        if (lineWidth + childWidth > maxWidth) {
            // 换行
            // 记录高度累加当前行高,从第2行起,都要加上垂直距离
            recordHeight += lineHeight + (recordHeight == 0 ? 0 : verticalSpace);
            // 布局
            int childLeft = 0;
            int childTop = recordHeight + verticalSpace;
            int childRight = childWidth;
            int childBottom = recordHeight + childHeight + verticalSpace;
            childView.layout(childLeft, childTop, childRight, childBottom);
            // 更新行宽
            lineWidth = childWidth;
            // 更新行高
            lineHeight = childHeight;
            // 下一个
            continue;
        }
        // 不换行
        // 布局
        int childLeft = lineWidth;
        int childTop = recordHeight + (recordHeight == 0 ? 0 : verticalSpace);
        int childRight = lineWidth + childWidth;
        int childBottom = recordHeight + childHeight + (recordHeight == 0 ? 0 : verticalSpace);
        childView.layout(childLeft, childTop, childRight, childBottom);
        // 更新行宽
        lineWidth += childWidth;
        // 更新行高,取最大
        lineHeight = Math.max(childHeight, lineHeight);
    }
}

只要实现以上3步,这个Layout就可以正常使用了,我们看看怎么添加元素。

适配器FlowAdapter

适配器用于把Object数据转化成View,然后交给FlowLayout显示。至于动态更新流式布局,也是操作这个适配器,采用观察者模式。FlowAdapter为发布者,FlowLayout为观察者,通过调用FlowAdapter的更新方法,便会通知FlowLayout观察者更新数据。我们看实现:

// FlowAdapter类
public abstract class FlowAdapter <T> implements FlowPublisher {

    // 数据源
    private List<T> dataList;
    // 观察者
    private FlowObserver observer;

    public FlowAdapter(List<T> dataList) {
        this.dataList = dataList;
    }

    @Override
    public void register(FlowObserver observer) {
        this.observer = observer;
    }

    @Override
    public void unregister() {
        this.observer = null;
    }

    /**
     * 子类复写,由数据data获取View
     * @param position
     * @param data
     * @return
     */
    public abstract View getView(int position, T data);

    /**
     * 解析所有数据
     * @return
     */
    List<View> parseViews() {
        List<View> viewList = new ArrayList<>();
        for (int position = 0; position < dataList.size(); position++) {
            viewList.add(getView(position, dataList.get(position)));
        }
        return viewList;
    }

    /**
     * 通知更新
     */
    public void notifyChange() {
        if (observer != null) {
            observer.notifyChange(this);
        }
    }

}

observer便是我们的FlowLayout,我们看看notifyChange方法:

// FlowLayout类
/**
 * 观察者更新方法
 * @param publisher
 */
@Override
public void notifyChange(FlowPublisher publisher) {
    if (publisher instanceof FlowAdapter) {
        refresh((FlowAdapter)publisher);
    }
}
/**
 * 刷新
 */
private void refresh(FlowAdapter adapter) {
    // 移除所有子View
    removeAllViews();
    // 获取FlowAdapter所有子View
    List<View> childViews = adapter.parseViews();
    // 添加到FlowLayout中
    for (int index = 0; index < childViews.size(); index++) {
        final View childView = childViews.get(index);
        // 设置点击事件
        final int position = index;
        childView.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                if (onItemClickListener != null) {
                    onItemClickListener.onItemClick(position, childView);
                }
            }
        });
        // 添加
        addView(childView);
    }
    // 更新
    requestLayout();
}

很简单,就是移除所有子View,然后添加所有适配器的View。
当然还有setAdapter方法:

/**
 * 设置适配器
 * @param adapter
 */
public void setAdapter(FlowAdapter adapter) {
    adapter.register(this);
    refresh(adapter);
}

和ListView很像,有木有?!(虽然内部实现有点不一样)

使用实例

xml布局:

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

    <com.johan.library.viewtoolkit.flowlayout.FlowLayout
        android:id="@+id/flow_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        flow_layout:horizontal_space="10dp"
        flow_layout:vertical_space="10dp"
        android:background="@android:color/white"
        />

    <!-- 设置了精确的宽度 -->
    <com.johan.library.viewtoolkit.flowlayout.FlowLayout
        android:id="@+id/flow_layout2"
        android:layout_width="150dp"
        android:layout_height="wrap_content"
        android:layout_margin="10dp"
        flow_layout:horizontal_space="10dp"
        flow_layout:vertical_space="10dp"
        android:background="@android:color/white"
        />

</LinearLayout>

activity使用:

public class FlowLayoutActivity extends Activity {

    private List<String> dataList = new ArrayList<>();

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_flow_layout);
        dataList.add("Java");
        dataList.add("Swift");
        dataList.add("Html");
        dataList.add("CSS");
        dataList.add("Go");
        dataList.add("C#");
        dataList.add("PHP");
        FlowLayout flowLayout = (FlowLayout) findViewById(R.id.flow_layout);
        final FlowLayoutAdapter adapter = new FlowLayoutAdapter(dataList);
        flowLayout.setAdapter(adapter);
        flowLayout.setOnItemClickListener(new FlowLayout.OnItemClickListener() {
            @Override
            public void onItemClick(int position, View view) {
                dataList.remove(position);
                adapter.notifyChange();
            }
        });
        FlowLayout flowLayout2 = (FlowLayout) findViewById(R.id.flow_layout2);
        FlowLayoutAdapter adapter2 = new FlowLayoutAdapter(dataList);
        flowLayout2.setAdapter(adapter2);
    }

    public class FlowLayoutAdapter extends FlowAdapter <String>  {
        public FlowLayoutAdapter(List<String> dataList) {
            super(dataList);
        }
        @Override
        public View getView(int position, String data) {
            View layout = LayoutInflater.from(FlowLayoutActivity.this).inflate(R.layout.item_flow_layout, null);
            TextView contentView = (TextView) layout.findViewById(R.id.item_content);
            contentView.setText(data);
            return layout;
        }
    }

}

效果图:

完整代码已经上传到我的github库,地址:https://github.com/JohanMan/viewtoolkit

参考资料

Android 手把手教您自定ViewGroup
Android 自定义ViewGroup 实战篇 -> 实现FlowLayout

Android自定义View之实现流式布局 流式布局 把子控件从左到右摆放,如果一行放不下,自动放到下一行 自定义布局流程 1. 自定义属性:声明,设置,解析获取自定义值 在attr.xml中声明 3. 测量:在onMeasure 方法测量自身的宽高和child的宽高 4. 布局:在onLayout方法里面根据自己的规则来确定children的位置 5. 绘制:onDraw 6. 处理layoutParams 7. 触摸反馈:滑动事件 ... 阅读详情

相关推荐

Android自定义View实现动画流式布局及点击添加功能

动画显示流式布局点击动画添加 上一篇已经发表了流式布局点击添加功能这里就不用了,需要的可以去上一篇博客查看 步入正题 在build。gradle中配置以下: //Gson依赖 implementation ‘com.google.code.gson:gson:2.8.5’ //volley请求框架 implementation ‘com.android.volley:volley:1.1.1’ 首...

Mr_Songdada的博客 722

Android 流式布局实现方式

Android 流失布局实现方式

唐诺 1744

流式布局(MFlowLayout)在Android中的使用

通过使用MFlowLayout,我们可以轻松实现流式布局,并在Android应用程序中创建自适应和灵活的界面。本文介绍了如何引入MFlowLayout依赖、在布局文件中使用MFlowLayout、动态添加子视图以及设置子视图的点击事件。在本文中,我们将介绍如何在Android应用程序中使用MFlowLayout,并提供相应的源代码示例。如果我们想要为MFlowLayout中的子视图设置点击事件,只需为每个子视图添加相应的点击监听器即可。在点击事件处理方法中,我们可以编写相应的逻辑来处理用户的点击操作。

OwxLinux的博客 404

Android 自定义View --- 流式布局FlowLayout

测量子View的方法是View.measure(int widthMeasureSpec, int heightMeasureSpec),widthMeasureSpec和heightMeasureSpec参数可以通过getChildMeasureSpec(int spec, int padding, int childDimension)方法获取,spec是View的MeasureSpec,可以是width或height;//全部子View布局完后,清除子View的保存。//更新这一行已使用的最大高度。

a18211246446的博客 2015

Android常用的流式布局实现,带源代码

流式布局可以自动根据内容的大小和容器的宽度,将内容动态地排列在多行中,以实现更好的展示效果。上面的代码中,我们可以看到每个标签都是一个TextView,并且通过设置背景样式、文字颜色和间距等属性来美化标签的显示效果。至此,我们就实现了在Android中常见的热门标签的流式布局。通过自定义的FlowLayout类,我们可以非常方便地实现标签的动态排列和展示。使用该自定义的FlowLayout,我们可以很方便地实现热门标签的流式布局。下面我将介绍一种实现流式布局的常见方法,并提供相应的源代码作为参考。

ScriptCharm的博客 315

自定义Android View实现流式布局单元测试

在本文中,我们将讨论如何编写单元测试来验证自定义的Android View实现流式布局。流式布局是一种常见的布局方式,它可以自动调整子视图的位置以适应可用空间,并且可以在一行放置多个子视图。现在我们已经有了自定义的流式布局视图,我们可以开始编写单元测试来验证它的行为。在Android中,我们可以使用JUnit和AndroidJUnit框架来编写单元测试。在开始编写单元测试之前,我们首先需要实现自定义的流式布局视图。然后,我们可以创建一个新的Java类来编写我们的单元测试。

BgScratch的博客 77

android 自定义view实现流式布局

页面效果实现 import android.content.Context; import android.util.AttributeSet; import android.view.View; import android.view.ViewGroup; import java.util.ArrayList; import java.util.List; /** * @description:自定义流式布局 * @date: 2019/9/11 11:14 * @author:..

72的博客 277

PointPainting 复现

三维目标检测

weixin_58207716的博客 4532

android 自定义View之继承ViewGroup实现流式布局

主要实现效果如下:接下来讲述如何实现:通过自定义ViewGroup实现:1:onMeasure:测量view的宽高--     在重写的onMeasure方法中,会传入2个参数,他们分别代表“宽的测量规格”,“高的测量规格”,如下所示(spec:规格)protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {测量规...

Cdaimadada的博客 982

别只刷题了!我用834分经验告诉你,华为HCIP大数据考试(H13-723)这样准备更高效

本文分享了华为HCIP大数据认证(H13-723)834分通关的高效备考经验。通过分析考试动态、题库验证技巧和章节优先级策略,帮助考生超越单纯刷题,系统化掌握核心知识点。特别强调实时流处理和离线批处理等重点章节,提供黄金90分钟临场发挥策略,助力考生一次性通过考试。

weixin_38168786的博客 458

火山引擎之火山方舟知识库+OpenWebUI,搭建独属于自己的AI智能客服

创建接入点,接入点名称可按个人需求而定,比如Doubao-1.5-pro-32k,在添加模型选择Doubao-1.5-pro-32k,点击确定(PS:有些模型不支持知识库,若发现后续无法选择,请重新创建推理接入点。选择应用广场,创建零代码应用,在创建好的应用设置内编辑相关信息,并选择推理接入点,即先前建好的推理接入点;此处的模型名称是火山的模型ID名称,可在OpenWebUI设置-模型 中修改名称。至此所需的apikey和模型ID和请求的api地址(可选配置,非本文重点参数)。进入火山官网,注册账号。

AmaZInGvCH的博客 2651

android自定义View实现流式布局

//先来一张效果图   //自定义的控件 import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.View; import android.widget.LinearLayout; import android.widge...

72的博客 672

Unity集成抖音小游戏:从IL2CPP配置到SDK接入全流程解析

本文详细解析了使用Unity开发抖音小游戏的完整流程。从关键的IL2CPP编译后端配置、PlayerSettings设置,到StarkSDK的接入与资源优化(如AutoStreaming),再到激励视频广告、录屏分享等核心功能的代码实现,提供了从环境准备到打包上传的全方位实战指南,帮助开发者高效完成技术适配。

weixin_27943395的博客 690

Android中自定义view实现流式布局

实现效果: 一.布局文件 &lt;comp.bwei.flowlayout.FlowLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="5dp"&gt; &lt;TextView and...

jzw_8899174的博客 410

Halcon手眼标定实战:九点标定法从入门到精通(附完整代码)

本文详细介绍了Halcon环境下九点标定法的完整实现流程,从基础概念到实战技巧,帮助开发者快速掌握手眼标定技术。通过精确采集图像坐标与机械坐标,计算仿射变换矩阵,实现相机与机械臂坐标系的精确映射,适用于工业自动化中的平面定位场景。

v4w5x6的博客 410

2024年Unity 面试题 |五萬字 二佰道| Unity面试题大全,面试题总结【全网最全,收藏一篇足够面试】

正所谓 金三银四 ,又到了找工作的大好时机了,不知道大家有没有意向找一份更好的工作呢~ 之前写了很多Unity的学习和实例文章,但是面试题部分还没有一个系统的整理。 那本篇文章就来整理一下Unity中一些常见的面试题,说不准就会面试的时候就会遇到! 本篇文章会将Unity所有方面的面试资料都融会贯通,绝对是2022年Unity面试领域最实用的文章啦!

努力前行,总会成为自己心中的那道光 17万+

Android 自定义View实现流式布局——彩色背景

效果图: 概述 1.流式布局原理: 在布局内,随意摆放任意个view,每行所摆放的view个数,根据实施计算出来的宽度,一旦当前要摆放的view宽度和之前摆放的所有view宽度加在一起,超过了布局的宽度,那么就把该view换行摆放 2.应用场景: 一般,像这种流式布局会应用在一些热门标签,热门推荐之类的应用上 3.测量模式: 谈到FlowLayout流式布局,不得不提及他的测量模...

baipenggui_bo 1149

调节桌面图标大小的方法(编程)

如果你对其他操作系统或编程语言有类似的需求,可以根据具体的情况进行相应的调整和搜索相关的库和方法。在编程中,我们可以使用各种桌面应用程序来调节桌面图标的大小。库提供的函数,我们获取了桌面图标的窗口句柄,并使用Windows消息发送方式设置图标的大小。你可以根据自己的需求修改代码中的图标大小值,并在运行代码后观察桌面图标的变化。函数并传入所需的图标大小,这里设置为48x48像素。首先,我们需要使用Python的第三现的方法。首先,我们需要使用Python的第三方库。首先,我们需要使用实现的方法。

CyberFlare的博客 438

Android 自定义View修炼-Android中常见的热门标签的流式布局的实现

一、概述:在日常的app使用中,我们会在android 的app中看见 热门标签等自动换行的流式布局,今天,我们就来看看如何 自定义一个类似热门标签那样的流式布局吧(源码下载在下面最后给出哈) 类似的自定义布局。下面我们就来详细介绍流式布局的应用特点以及用的的技术点: 1.流式布局的特点以及应用场景 特点:当上面一行的空间不够容纳新的TextView时候, 才开辟下一行的空间 ...

weixin_30553837的博客 94

数学建模学习(5):最全概率分析之图表绘制详解,内容比较多,建议收藏

(1) 绘制正整数频率使用 tabulate(X) (2)

全栈川川 4591

win10 跳过U8环境检测的IE WebControls.rar

win10 安装u8的时候 提示IE WebControls 不通过,这个工具可以欺骗u8的检查。 跳过U8环境检测的IE WebControls。提示导入失败后,重新检测通过。

Android自定义View实现流式布局

实现效果如图大概流程图实现分析1.在FlowLayout的构造里面获取自定义属性,让其支持横向间距和纵向间距 public FlowLayout(Context context, AttributeSet attrs) { super(context, attrs); TypedArray typedArray = context.obtainStyledAttri

Hello_word1024的博客 812

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

【流式布局】Android自定义View--简单实现

蛮简单的,核心代码总共不到100行就可以实现,想要实现其他功能也可以在此基础上拓展

qq_46205625的博客 553

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

Android自定义View实现流式布局(热门标签效果)

来源:http://www.jianshu.com/p/0e12a1214e62 效果图 思维导图 一、流式布局的实现 实现原理:采用面向对象思想将整个布局分为很多行的对象,每个行对象管理自己行内的孩子,这里通过集合来管理。内部类Line的实现 1.1 定义行的基本属性List:管理行中的孩子 maxWidth:行的最大宽度 usedWidth:使用的宽度 height:行的高度 spac

springreef的博客 953

Android中的自定义View(二)之 流式布局实现

我们在上一篇文章《Android中的自定义View(一)》中介绍过自定义View的几种方式,并通过示例一演示了“直接继承View”的自定义View的使用情况。今天接着来介绍自定义View里稍为复杂的“直接继承ViewGroup”的使用情况。一般地,直接继承ViewGroup的自定义View需要我们自己去处理ViewGroup的measure和layout这两个过程,并同时处理子元素的measure...

子云心的博客 730

FlowLayout(流式布局)的实现

文章目录前言代码实现(Flowlayout)使用方法1. 编写 item 布局2. 编写 Adapter3. 主活动中使用 FlowLayout参考 前言 最近在做的项目决定用流式布局来展示历史记录,刚好自己也想学习自定义 ViewGroup,所以就参考了其他的一些文章,写了一个 FlowLayout(流式布局),效果如下: 代码实现(Flowlayout) 只有一个 FlowLayout 类,...

FengZH的博客 1万+
上一篇: Android 使用ActivityOptions实现Activity转场动画
下一篇: Android 冷启动实现APP秒开
JohanMan
博客等级 码龄10年 72粉丝 131原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值