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 ...
随机推荐
- jackson 的UnrecognizedPropertyException错误
阅读更多 前段时间,使用jackson封装了json字符串转换为javabean的方法,代码如下: public static <T> T renderJson2Object(String ...
- mybatis 从数据库查询的信息不完整解决办法
List<Product> products = productService.getProductListWithPage(productQuery); 今天碰到一个很奇怪的现象,上面的 ...
- USACO 刷题记录bzoj
bzoj 1606: [Usaco2008 Dec]Hay For Sale 购买干草——背包 #include<cstdio> #include<cstring> #incl ...
- 带接口的webservice 的发布
1.接口:(打上service注解) package ws.qlq.a; import javax.jws.WebService; /** * 面向接口的webservice发布方式 * * */ @ ...
- 【Visual Studio】以管理员的身份运行软件
- nslookup命令详解【转】
转自:http://blog.chinaunix.net/uid-28933499-id-3750357.html NSlookup命令的用法 用了域名服务器后,经常要查询域名的解析情况,nslook ...
- pcm2aac
1.下载faac源代码:http://downloads.sourceforge.net/faac/faac-1.28.zip 2.在VAWARE上进行交叉编译,安装. ./configure --t ...
- template相关
template模板是c++中支持多态的工具,使用模板可以使用户为类或函数声明一种一般的模式,使得该模板试用于任意类型的参数. 函数模板: 定义如下: template <typename T& ...
- Alfred添加百度搜索
Alfred默认的搜索只有 google; amazon和wikipakia, 我想加个百度搜索,怎么添加呢? 1.首先添加百度搜索,添加http://www.baidu.com/s?wd={quer ...
- NOIP 2016 天天爱跑步 80分暴力
题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...