Android-->自定义ViewGroup, 银行卡片布局

这里写图片描述

首先了解下, 自定义View的三部曲.

1:onMeasure方法

此方法主要目的, 就是根据xml的
android:layout_width="wrap_content"
android:layout_height="wrap_content"

wrap_content match_parent 这2个属性, 来确定测量自身的大小.
当然, 这2个值, 只是parent告诉你, 需要按照此规则来测量, 如果你是一个坏孩子, 那么可以无视测量规则, 任意设置一个宽度和高度, 比如: setMeasuredDimension(1万, 2万) 就是如此简单;

2:onLayout方法

如果你是自定义View, 此方法可以不必override
如果你是自定义的ViewGroup, 那么就必须override, 此方法的目的就是由你决定child view在界面上的位置.

3:onDraw方法

在这个方法里面, 你可以展开你天才般的做图功能, 想画啥就画啥. 美美的view, 就这样出来了.
友情提示:如果你是自定义的ViewGroup, 还需要调用setWillNotDraw(false)方法, 否则onDraw方法不会执行哦


本文由于是自定义的ViewGroup, 所以重点是在onLayout方法里面;

不着急, 分析一波:
此需求, 说难不难, 说易不易.
易: 因为只要重写onLayout方法就行.
难: 你需要有一套规则限制onLayout方法.(如果你的规则很简单, 那么相当容易. 反之…)

1: 在默认情况下, 所有卡片按照层级和一定的偏移距离进行布局(相当于FrameLayout+marginTop的组合)
2: 当手指往下滑动的时候, 最顶层的卡片优先滑动到一定距离, 然后倒数第二层的卡片再滑动.以此类推
3: 当手指快速滑动的时候, 根据滑动方向,进行fling操作, 卡片自动折叠或展开.

需求就这么点.


这里说一下我相当的思路, 如果你有更简洁的思路, 欢迎交流.

假设卡片的高度(cardHeight)一定, 宽度一定. 相邻之间卡片默认状态时偏移的高度(offsetTop);
这种情况下, onLayout之后, 卡片的布局就是默认看到的状态了.

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
     int top = 0;
     int childCount = getChildCount();
    for (int i = 0; i < childCount; i++) {
               View childAt = getChildAt(i);
               int layoutTop = top + offsetTop;
               childAt.layout(getPaddingLeft(), layoutTop, getMeasuredWidth() - getPaddingRight(), layoutTop + childAt.getMeasuredHeight());
               top += offsetTop;
           }
}

这样就完成了第一阶段了.

当手指滑动的时候, 比如向下滑动了dy.
我这里的思路就是, 把dy平分给每一个卡片的top上. 并且显示每一个卡片允许分到的最大top值;
这样, 在onLayout的时候, 加上这个top就行了.

//翻译成代码, 就是
    /**
     * 默认状态是, 每个View之间的间隔
     */
    public final int DEFAULT_MIN_OFFSET = (int) (40 * density());
    /**
     * 每一个View, 最多可以消耗多少距离
     */
    public final int DEFAULT_MAX_OFFSET = (int) (80 * density());

 private void refreshLayout() {
      int top = getPaddingTop();
      int childCount = getChildCount();

      //计算每个item view,能够消耗的高度
      for (int i = 0; i < childCount; i++) {
          View childAt = getChildAt(i);
          int needOffset = (childCount - 1 - i) * DEFAULT_MAX_OFFSET;
          if (currentOffset > needOffset) {
              needOffset = Math.min(currentOffset - needOffset, DEFAULT_MAX_OFFSET);

              if (i == 0) {
                  //如果是第一个item, 限制能够消耗的高度
                  //needOffset = Math.min(DEFAULT_MIN_OFFSET, needOffset);
                  needOffset = 0;
              }
          } else {
              needOffset = 0;
          }
          childAt.setTag(needOffset);
      }

      //开始布局item 
      for (int i = 0; i < childCount; i++) {
          View childAt = getChildAt(i);
          int offsetTop = getViewTop(childAt);
          int layoutTop = top + offsetTop;
          childAt.layout(getPaddingLeft(), layoutTop, getMeasuredWidth() - getPaddingRight(), layoutTop + childAt.getMeasuredHeight());
          top += DEFAULT_MIN_OFFSET + offsetTop;
      }
  }

联系作者

请使用QQ扫码加群, 小伙伴们在等着你哦!

关注我的公众号, 每天都能一起玩耍哦!

猜你喜欢

转载自blog.csdn.net/angcyo/article/details/78028173