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;
  }
 }

再运行一下看看:

成功了有木有!

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。

(0)

相关推荐

  • Android应用开发中自定义ViewGroup的究极攻略

    支持margin,gravity以及水平,垂直排列 最近在学习android的view部分,于是动手实现了一个类似ViewPager的可上下或者左右拖动的ViewGroup,中间遇到了一些问题(例如touchEvent在onInterceptTouchEvent和onTouchEvent之间的传递流程),现在将我的实现过程记录下来. 首先,要实现一个ViewGroup,必须至少重写onLayout()方法(当然还有构造方法啦:)).onLayout()主要是用来安排子View在我们这个ViewG

  • Android自定义ViewGroup之实现FlowLayout流式布局

    整理总结自鸿洋的博客:http://blog.csdn.net/lmj623565791/article/details/38352503/  一.FlowLayout介绍  所谓FlowLayout,就是控件根据ViewGroup的宽,自动的往右添加,如果当前行剩余空间不足,则自动添加到下一行.有点像所有的控件都往左飘的感觉,第一行满了,往第二行飘~所以也叫流式布局.Android并没有提供流式布局,但是某些场合中,流式布局还是非常适合使用的,比如关键字标签,搜索热词列表等,比如下图: git

  • Android自定义ViewGroup的实现方法

    在android中提供了常见的几种ViewGroup的实现,包括LinearLayout.Relativeayout.FrameLayout等.这些ViewGroup可以满足我们一般的开发需求,但是对于界面要求复杂的,这几个布局就显得捉襟见肘了.所以自定义的ViewGroup在我们接触过的应用中比比皆是. 要想实现一个自定义的ViewGroup,第一步是学会自定义属性,这些自定义的属性将让我们配置布局文件的时候更加的灵活.自定义属性是在value目录下声明一个attrs.xml文件. <?xml

  • Android App开发中自定义View和ViewGroup的实例教程

    View Android所有的控件都是View或者View的子类,它其实表示的就是屏幕上的一块矩形区域,用一个Rect来表示,left,top表示View相对于它的parent View的起点,width,height表示View自己的宽高,通过这4个字段就能确定View在屏幕上的位置,确定位置后就可以开始绘制View的内容了. View绘制过程 View的绘制可以分为下面三个过程: Measure View会先做一次测量,算出自己需要占用多大的面积.View的Measure过程给我们暴露了一个

  • Android自定义ViewGroup实现可滚动的横向布局(2)

    上一篇文章自定义viewgroup(1)地址:http://www.jb51.net/article/100608.htm 这里直接代码: package com.example.libingyuan.horizontallistview.ScrollViewGroup; import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android

  • Android自定义ViewGroup实现带箭头的圆角矩形菜单

    本文和大家一起做一个带箭头的圆角矩形菜单,大概长下面这个样子: 要求顶上的箭头要对准菜单锚点,菜单项按压反色,菜单背景色和按压色可配置. 最简单的做法就是让UX给个三角形的图片往上一贴,但是转念一想这样是不是太low了点,而且不同分辨率也不太好适配,干脆自定义一个ViewGroup吧! 自定义ViewGroup其实很简单,基本都是按一定的套路来的. 一.定义一个attrs.xml 就是声明一下你的这个自定义View有哪些可配置的属性,将来使用的时候可以自由配置.这里声明了7个属性,分别是:箭头宽

  • Android自定义ViewGroup实现标签浮动效果

    前面在学习鸿洋大神的一些自定义的View文章,看到了自定义ViewGroup实现浮动标签,初步看了下他的思路以及结合自己的思路完成了自己的浮动标签的自定义ViewGroup.目前实现的可以动态添加标签.可点击.效果图如下: 1.思路  首先在onMeasure方法中测量ViewGroup的宽和高,重点是处理当我们自定义的ViewGroup设置为wrap_content的情况下,如何去测量其大小的问题.当我们自定义的ViewGroup设置为wrap_content时,我们需要让子View先去测量自

  • Android动画效果之自定义ViewGroup添加布局动画(五)

    前言: 前面几篇文章介绍了补间动画.逐帧动画.属性动画,大部分都是针对View来实现的动画,那么该如何为了一个ViewGroup添加动画呢?今天结合自定义ViewGroup来学习一下布局动画.本文将通过对自定义图片选择控件设置动画为例来学习布局动画. 自定义一个显示多行图片的ViewGroup: 这里不再对自定义控件做解说,想了解的可以看下以下几篇文章  •Android自定义控件之基本原理(一)  •Android自定义控件之自定义属性(二)  •Android自定义控件之自定义组合控件(三)

  • Android自定义ViewGroup实现受边界限制的滚动操作(3)

    上一篇文章<自定义viewgroup(2)>地址:http://www.jb51.net/article/100610.htm 代码 package com.example.libingyuan.horizontallistview.ScrollViewGroup; import android.content.Context; import android.util.AttributeSet; import android.util.DisplayMetrics; import androi

  • Android自定义ViewGroup实现堆叠头像的点赞Layout

    简介 这样的点赞列表怎么样?之前做社区的时候也有类似的点赞列表,但是没有这样重叠,一个小小的改变,个人感觉逼格提高不少. 这个很有规则,就是后一个头像会覆盖一部分到前一个头像上,头像多了就像一串糖葫芦了. 这个实现起来不难,自定义ViewGroup,关键重写onLayout方法. 关于自定义控件的基础知识可以看一看这个,整理的很详细: https://github.com/GcsSloop/AndroidNote 实现 自定义属性 属性名 说明 默认值 vertivalSpace 行距 4dp

随机推荐