先看效果圖:
實現思路:
1.外層是一個自定義的 FrameLayout,通過重寫 onMeasure() 和 onLayout() 方法,動態計算其內部子view展開和摺疊時的高度。
2.內部子 view 是一個自定義的 CardView(可以方便的處理圓角和陰影)。
核心代碼:
其實現主要是由兩個方法: onMeasure() 和 onLayout(), onMeasure() 計算佈局需要的總高度(未進行寬度處理),onLayout() 進行內部子view的擺放,具體實現如下:
外部自定義 FrameLayout 的 onMeasure() :
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
if (getChildCount() < 1) {
return;
}
CollapsibleCardView collapsibleCardView = ((CollapsibleCardView) getChildAt(getChildCount() - 1));
// compute height.
final LayoutParams lp = (LayoutParams) collapsibleCardView.getLayoutParams();
int marginTop = lp.topMargin;
int marginBottom = lp.bottomMargin;
int paddingTop = getPaddingTop();
int paddingBottom = getPaddingBottom();
int mHeaderViewHeight = collapsibleCardView.getViewHeader().getMeasuredHeight();
int mContentViewHeight = collapsibleCardView.getViewContent().getMeasuredHeight();
int totalHeight = paddingTop + marginTop
+ mHeaderViewHeight * (getChildCount() - 1)
+ collapsibleCardView.getMeasuredHeight()
+ paddingBottom + marginBottom;
if (hasExpandView()) {
totalHeight -= collapsibleCardView.getViewHeader().getMeasuredHeight();
totalHeight += collapsibleCardView.getMeasuredHeight() + dp2px(cardStackViewSpacing);
}
setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), totalHeight);
}
外部自定義 FrameLayout 的 onLayout() :
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
if (getChildCount() < 1) {
return;
}
CollapsibleCardView collapsibleCardView = (CollapsibleCardView) getChildAt(0);
final LayoutParams lp = (LayoutParams) collapsibleCardView.getLayoutParams();
int marginStart = lp.getMarginStart();
int marginTop = lp.topMargin;
int childLeft = getPaddingLeft();
int childTop = getPaddingTop();
for (int i = 0; i < getChildCount(); i++) {
CollapsibleCardView child = (CollapsibleCardView) getChildAt(i);
final int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
child.layout(childLeft + marginStart,
childTop + marginTop,
childLeft + marginStart + childWidth,
childTop + marginTop + childHeight);
if (child.isExpand()) {
childTop += childHeight + dp2px(cardStackViewSpacing);
} else {
childTop += child.getViewHeader().getMeasuredHeight();
}
}
}
待完善事項:
1.當佈局過高時,需要在外部再添加 NestedScrollView 包裹(這個應該可以封裝起來的)。
2.內部子view展開摺疊沒有動畫效果可以配置
3.內部子view展開摺疊被遮擋的時候需要外部 NestedScrollView 進行滾動處理。
具體代碼 demo 地址:https://github.com/QQQQQQY/CardStackView