Android进阶教程之ViewGroup自定义布局

所属分类: 软件编程 / Android 阅读数: 45
收藏 0 赞 0 分享

前言

在我们的实际应用中, 经常需要用到自定义控件,比如自定义圆形头像,自定义计步器等等。但有时我们不仅需要自定义控件,举个例子,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 自定义球型水波纹带圆弧进度效果(实例代码)

最近小编接到一个这样的需求,需要实现一个圆形水波纹,带进度,两层水波纹需要渐变显示,且外围有一个圆弧进度。今天小编给大家分享实例代码,感兴趣的朋友一起看看吧
收藏 0 赞 0 分享

Flutter 实现下拉刷新上拉加载的示例代码

这篇文章主要介绍了Flutter 实现下拉刷新上拉加载的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Windows实现Flutter环境搭建及配置这一篇就够了

这篇文章主要介绍了Windows实现Flutter环境搭建及配置这一篇就够了,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

Android利用碎片fragment实现底部标题栏(Github模板开源)

Fragment可以作为Activity的组成部分,一个Activity可以有多个Fragment,这篇文章主要介绍了Android利用碎片fragment实现底部标题栏(Github模板开源),需要的朋友可以参考下
收藏 0 赞 0 分享

android studio 的下拉菜单Spinner使用详解

这篇文章主要介绍了android studio 的下拉菜单Spinner使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
收藏 0 赞 0 分享

解析Android 8.1平台SystemUI 导航栏加载流程

这篇文章主要介绍了Android 8.1平台SystemUI 导航栏加载流程,非常不错,具有一定的参考借鉴价值,需要的朋友可以参考下
收藏 0 赞 0 分享

Android仿微信录音功能

这篇文章主要为大家详细介绍了Android仿微信录音功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android仿微信键盘切换效果

这篇文章主要为大家详细介绍了Android仿微信键盘切换效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android超清晰6.0权限申请AndPermission

这篇文章主要介绍了Android超清晰6.0权限申请AndPermission,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享

Android仿微信录制语音功能

这篇文章主要介绍了Android仿微信录制语音功能,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
收藏 0 赞 0 分享
查看更多