首先了解下, 自定义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扫码加群, 小伙伴们在等着你哦!
关注我的公众号, 每天都能一起玩耍哦!