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

 更新时间:2017年10月20日 09:30:46   作者:FlowLeaf  
这篇文章主要介绍了 Android自定义ViewGroup实现堆叠头像的点赞Layout,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

简介

这里写图片描述

这样的点赞列表怎么样?之前做社区的时候也有类似的点赞列表,但是没有这样重叠,一个小小的改变,个人感觉逼格提高不少。

这个很有规则,就是后一个头像会覆盖一部分到前一个头像上,头像多了就像一串糖葫芦了。

这个实现起来不难,自定义ViewGroup,关键重写onLayout方法。

关于自定义控件的基础知识可以看一看这个,整理的很详细: https://github.com/GcsSloop/AndroidNote

实现

自定义属性

属性名 说明 默认值
vertivalSpace 行距 4dp
pileWidth 重叠宽度 10dp

onMeasure方法,每行的宽度不再是child的宽度和了,而是要减掉重叠部分的宽度和

@Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    int widthSpecMode = MeasureSpec.getMode(widthMeasureSpec);
    int widthSpecSize = MeasureSpec.getSize(widthMeasureSpec);
    int heightSpecMode = MeasureSpec.getMode(heightMeasureSpec);
    int heightSpecSize = MeasureSpec.getSize(heightMeasureSpec);

    //AT_MOST
    int width = 0;
    int height = 0;
    int rawWidth = 0;//当前行总宽度
    int rawHeight = 0;// 当前行高

    int rowIndex = 0;//当前行位置
    int count = getChildCount();
    for (int i = 0; i < count; i++) {
      View child = getChildAt(i);
      if(child.getVisibility() == GONE){
        if(i == count - 1){
          //最后一个child
          height += rawHeight;
          width = Math.max(width, rawWidth);
        }
        continue;
      }

      //这里调用measureChildWithMargins 而不是measureChild
      measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
      MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();

      int childWidth = child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin;
      int childHeight = child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
      if(rawWidth + childWidth - (rowIndex > 0 ? pileWidth : 0)> widthSpecSize - getPaddingLeft() - getPaddingRight()){
        //换行
        width = Math.max(width, rawWidth);
        rawWidth = childWidth;
        height += rawHeight + vertivalSpace;
        rawHeight = childHeight;
        rowIndex = 0;
      } else {
        rawWidth += childWidth;
        if(rowIndex > 0){
          rawWidth -= pileWidth;
        }
        rawHeight = Math.max(rawHeight, childHeight);
      }

      if(i == count - 1){
        width = Math.max(rawWidth, width);
        height += rawHeight;
      }

      rowIndex++;
    }

    setMeasuredDimension(
        widthSpecMode == MeasureSpec.EXACTLY ? widthSpecSize : width + getPaddingLeft() + getPaddingRight(),
        heightSpecMode == MeasureSpec.EXACTLY ? heightSpecSize : height + getPaddingTop() + getPaddingBottom()
    );
  }

onLayout 每一行,第一个正常放,之后的重叠放

@Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {
    int viewWidth = r - l;
    int leftOffset = getPaddingLeft();
    int topOffset = getPaddingTop();
    int rowMaxHeight = 0;
    int rowIndex = 0;//当前行位置
    View childView;
    for( int w = 0, count = getChildCount(); w < count; w++ ){
      childView = getChildAt(w);
      if(childView.getVisibility() == GONE) continue;

      MarginLayoutParams lp = (MarginLayoutParams) childView.getLayoutParams();
      // 如果加上当前子View的宽度后超过了ViewGroup的宽度,就换行
      int occupyWidth = lp.leftMargin + childView.getMeasuredWidth() + lp.rightMargin;
      if(leftOffset + occupyWidth + getPaddingRight() > viewWidth){
        leftOffset = getPaddingLeft(); // 回到最左边
        topOffset += rowMaxHeight + vertivalSpace; // 换行
        rowMaxHeight = 0;

        rowIndex = 0;
      }

      int left = leftOffset + lp.leftMargin;
      int top = topOffset + lp.topMargin;
      int right = leftOffset+ lp.leftMargin + childView.getMeasuredWidth();
      int bottom = topOffset + lp.topMargin + childView.getMeasuredHeight();
      childView.layout(left, top, right, bottom);

      // 横向偏移
      leftOffset += occupyWidth;
      // 试图更新本行最高View的高度
      int occupyHeight = lp.topMargin + childView.getMeasuredHeight() + lp.bottomMargin;
      if(rowIndex != count - 1){
        leftOffset -= pileWidth;//这里控制重叠位置
      }
      rowMaxHeight = Math.max(rowMaxHeight, occupyHeight);
      rowIndex++;
    }
  }

效果图

这里写图片描述

因为这个一般只会显示一行,所以暂时没有通过setAdapter方式去设置数据源。

下载

https://github.com/LineChen/PileLayout

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • Android购物分类效果实现

    Android购物分类效果实现

    这篇文章主要为大家详细介绍了Android购物分类效果的实现代码,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-11-11
  • 你该知道的Gradle配置知识总结

    你该知道的Gradle配置知识总结

    这篇文章主要给大家介绍了关于Gradle配置的相关资料,文中通过示例代码介绍的非常详细,对各位Android开发者们具有一定的参考学习价值,需要的朋友可以参考学习,下面随着小编来一起学习学习吧。
    2017-10-10
  • Android Touch事件分发过程详解

    Android Touch事件分发过程详解

    这篇文章主要介绍了Android Touch事件分发过程,详细描述了Android Touch事件的主要处理流程,有助于深入理解Android程序设计,需要的朋友可以参考下
    2014-09-09
  • 详解Android TextView属性ellipsize多行失效的解决思路

    详解Android TextView属性ellipsize多行失效的解决思路

    这篇文章主要介绍了Android TextView属性ellipsize多行失效的解决思路,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-07-07
  • 谈谈Android Fragments 详细使用

    谈谈Android Fragments 详细使用

    本篇文章主要介绍了Android Fragments 详细使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2016-12-12
  • Android View源码解读 DecorView与ViewRootImpl浅谈

    Android View源码解读 DecorView与ViewRootImpl浅谈

    这篇文章主要解读了Android View源码,为大家详细介绍DecorView与ViewRootImpl,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-02-02
  • 解决Android MediaRecorder录制视频过短问题

    解决Android MediaRecorder录制视频过短问题

    本文主要介绍Android MediaRecorder,在使用MediaRecorder时经常会遇到视频录制太短问题,这里提供解决问题的实例代码以供大家参考
    2016-07-07
  • 36个Android开发常用经典代码大全

    36个Android开发常用经典代码大全

    本篇文章主要介绍了36个Android开发常用经典代码片段,都是实用的代码段,具有一定的参考价值,感兴趣的小伙伴们可以参考一下。
    2016-11-11
  • 使用AndroidStudio上传忽略文件至SVN Server的解决办法

    使用AndroidStudio上传忽略文件至SVN Server的解决办法

    这篇文章主要介绍了使用AndroidStudio上传忽略文件至SVN Server的解决办法 的相关资料,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2016-06-06
  • android自定义控件实现简易时间轴(1)

    android自定义控件实现简易时间轴(1)

    这篇文章主要为大家详细介绍了android自定义控件实现简易时间轴,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01

最新评论