Android 进阶自定义 ViewGroup 自定义布局
前言
在我们的实际应用中, 经常需要用到自定义控件,比如自定义圆形头像,自定义计步器等等。但有时我们不仅需要自定义控件,举个例子,FloatingActionButton 大家都很常用,所以大家也很经常会有一种需求,点击某个 FloatingActionButton 弹出更多 FloatingActionButton ,这个需求的一般思路是写 n 个 button 然后再一个个的去设置动画效果。但这实在是太麻烦了,所以网上有个 FloatingActionButtonMenu 这个开源库,这就是利用到了自定义布局 「ViewGroup」,现在就让我给他家介绍下,如何自定义布局 「layout」。
难点
相比于自定义 View ,自定义 ViewGroup 的难点在于,子控件位置的确定和布局大小的确定。不像 单个 View 子要花粉好模式,测量好宽度就搞定了,ViewGroup 的长宽根据子 View 的数量和单个的大小变化而变化。这就是最大的坎,所以该如何确定 ViewGroup 的大小呢?
步骤
这里 我为大家设计一个 类似 LinearLayout 线性布局的 ViewGroup 作为范例。
首先,如果是一个 LinearLayout 那么当设置 wrap_content 时,他就会以子空间中最宽的那个为它的宽度。同时在高度方面会是所有子控件高度的总和。所以我们先写两个方法,分别用于测量 ViewGroup 的宽度和高度。
private int getMaxWidth(){
int count = getChildCount();
int maxWidth = 0;
for (int i = 0 ; i < count ; i ++){
int currentWidth = getChildAt(i).getMeasuredWidth();
if (maxWidth < currentWidth){
maxWidth = currentWidth;
}
}
return maxWidth;
}
private int getTotalHeight(){
int count = getChildCount();
int totalHeight = 0;
for (int i = 0 ; i < count ; i++){
totalHeight += getChildAt(i).getMeasuredHeight();
}
return totalHeight;
}
对于 ViewGroup 而言我们可以粗略的分为两种模式:固定长宽模式(match_parent),自适应模式(wrap_content),根据这两种模式,就可以对 ViewGroup 的绘制进行划分。这里关于 measureChildren 这个方法,他是用于将所有的子 View 进行测量,这会触发每个子 View 的 onMeasure 函数,但是大家要注意要与 measureChild 区分,measureChild 是对单个 view 进行测量
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
measureChildren(widthMeasureSpec, heightMeasureSpec);
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int width = MeasureSpec.getSize(widthMeasureSpec);
int heightMode= MeasureSpec.getMode(heightMeasureSpec);
int height = MeasureSpec.getSize(heightMeasureSpec);
if (widthMode == MeasureSpec.AT_MOST && heightMode == MeasureSpec.AT_MOST){
int groupWidth = getMaxWidth();
int groupHeight= getTotalHeight();
setMeasuredDimension(groupWidth, groupHeight);
}else if (widthMode == MeasureSpec.AT_MOST){
setMeasuredDimension(getMaxWidth(), height);
}else if (heightMode == MeasureSpec.AT_MOST){
setMeasuredDimension(width, getTotalHeight());
}
}
重写 onLayout
整完上面这些东西,我们的布局大小七十九已经出来了,然我们在活动的布局文件里面加上它,并添加上几个子 View 然后运行一下,先看看效果:
<com.entry.android_view_user_defined_first.views.MyLinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorAccent">
<Button
android:layout_width="100dp"
android:layout_height="50dp"
android:text="qwe"/>
<Button
android:layout_width="250dp"
android:layout_height="150dp"
android:text="qwe"/>
<Button
android:layout_width="200dp"
android:layout_height="75dp"
android:text="qwe"/>
</com.entry.android_view_user_defined_first.views.MyLinearLayout>
运行效果如下:
我们看见布局出来了,大小好像也没啥问题,但是子 View 呢??! 这么没看见子 View 在看看代码,系统之前然我们重写的 onLayout() 还是空着的呀!!也就是说,子 View 的大小和位置根本就还没有进行过设定!让我们来重写下 onLayout() 方法。
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int count = getChildCount();
int currentHeight = 0;
for (int i = 0 ; i < count ; i++){
View view = getChildAt(i);
int height = view.getMeasuredHeight();
int width = view.getMeasuredWidth();
view.layout(l, currentHeight, l + width, currentHeight + height);
currentHeight += height;
}
}
再运行一下看看:
成功了有木有!
由于本文是自己学习过程的总结,如果文中有错误,希望大家能在评论区指出
最后,祝大家编程愉快!
Android 进阶自定义 ViewGroup 自定义布局的更多相关文章
- Android动画效果之自定义ViewGroup添加布局动画
前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通 ...
- 【Android - 进阶】之自定义视图浅析
1 概述 Android自定义View / ViewGroup的步骤大致如下: 1) 自定义属性: 2) 选择和设置构造方法: 3) 重写onMeasure()方法: 4) 重写onDra ...
- 自定义ViewGroup添加布局动画
声明几个属性值: <declare-styleable name="GridImageViewGroup"> <attr name="childVert ...
- Android进阶之绘制-自定义View完全掌握(三)
自定义View系列的第三篇博客,我们来学习如何实现自定义下拉框. 今天的程序,我们来实现这样的一个效果. 布局非常简单,我们直接开始编码. 修改activity_main.xml文件的代码. < ...
- Android进阶AIDL使用自定义类型
原文首发于微信公众号:jzman-blog,欢迎关注交流! 上篇文章中主要介绍从 AIDL 的使用方式以及 Android 开发中不同进程之间的通信,遗留的问题是如何在 AIDL 中使用自定义类型,具 ...
- Android之探究viewGroup自定义子属性参数的获取流程
通常会疑惑,当使用不同的布局方式时,子view得布局属性就不太一样,比如当父布局是LinearLayout时,子view就能有效的使用它的一些布局属性如layout_weight.weightSum. ...
- Android进阶之绘制-自定义View完全掌握(四)
前面的案例中我们都是使用系统的一些控件通过组合的方式来生成我们自定义的控件,自定义控件的实现还可以通过自定义类继承View来完成.从该篇博客开始,我们通过自定义类继承View来实现一些我们自定义的控件 ...
- Android进阶之绘制-自定义View完全掌握(一)
Android的UI设计可以说是决定一个app质量的关键因素,因为人们在使用app的时候,最先映入眼帘的就是app的界面了,一个美观.充实的界面能够给用户带来非常好的体验,会在用户心中留下好的印象. ...
- Android进阶之绘制-自定义View完全掌握(五)
在自定义类继承View实现自定义控件的过程中,我们还应该对一些自定义属性有所了解. 我们通过一个案例来学习一下. 新建一个android项目,然后我们创建一个类MyAttributeView继承Vie ...
随机推荐
- URL短网址生成算法原理和php实现案例
短网址(Short URL),顾名思义就是在形式上比较短的网址. 短链接的好处:1.内容需要:2.用户友好:3.便于管理为什么要这样做的,原因我想有这样几点:微博限制字数为140字一条,那么如果我们需 ...
- 【HDOJ5521】Meeting(最短路)
题意:有n个点,m个点集,每个点集中有e[i]个点,同一点集的点互相之间到达需要t[i]单位的时间,求min(max(dis(1,i),dis(i,n))),i属于[1,n] 输出最小值并増序输出所有 ...
- repeater绑定数组、哈希表、字典 ArrayList/HashTable,Dictionary为datasource
原文发布时间为:2009-11-19 -- 来源于本人的百度文章 [由搬家工具导入] repeater绑定数组、哈希表、字典datasource为ArrayList/HashTable,Diction ...
- PE笔记之NT头PE扩展头
typedef struct _IMAGE_OPTIONAL_HEADER { // // Standard fields. // WORD Ma ...
- linux私房菜-读书笔记
第零章:计算机概论 计算机:接受用户输入指令和数据,经过中央处理器的数据和逻辑单元运算处理器处理后,以产生或存储成有用的信息. 计算机硬件的五大单元:输入单元.输出单元.CPU内部控制单元.算术逻辑单 ...
- layui 的单选框
<div class="layui-form-item"> <label class="layui-form-label">是否通过&l ...
- Win7下VS2010、IIS7配置常见问题收集
一 在Win7下应按什么次序安装vs2010和iis7 win7推荐先安装iis7,再安装vs2010:如果次序反了,必须注册iis才可以用. IIS中ASP.NET的版本号此时可选的有1.1.2.0 ...
- POJ 1239 Increasing Sequences [DP]
题意:略. 思路:进行两次dp. 第一次dp从前向后,用dp[x]表示从第x位向前dp[x]位可构成一个数字,且与前面的数组符合题意要求.最后求的dp[n]即为最后一个数字的长度. 而题目还有要求,所 ...
- 基于WPF系统框架设计(10)-分页控件设计
背景 最近要求项目组成员开发一个通用的分页组件,要求是这个组件简单易用,通用性,兼容现有框架MVVM模式,可是最后给我提交的成果勉强能够用,却欠少灵活性和框架兼容性. 设计的基本思想 传入数据源,总页 ...
- html中常用的标签小结
内容详细标签: <h1>~<h6>标题标签<pre>格式化文本<u>下划线(underline)<i>斜体字(italics)<cit ...