仿淘寶京東商品規格屬性選擇的最簡單實作
商城裡面的規格選擇,網上大部分是自定義控件實作的,顯得很是麻煩,而我的實作方式是大家最常用的控件RecyclerView,特點是性能好,簡單。廢話不多說,先看實作的效果圖:
上圖效果的實作主要是 RecyclerView和flowlayout(流式布局).
RecyclerView設定最大高度
如圖規格多的時候,RecyclerView要有個最大高度,我們設定
android:maxHeight="300dp"
是沒有效果的,因為RecyclerView沒有maxHigh這個屬性,那怎麼實作這個效果呢?通過檢視源碼,
@Override
protected void onMeasure(int widthSpec, int heightSpec) {
...
if (mLayout.mAutoMeasure) {
...
// now we can get the width and height from the children.
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
if (mLayout.shouldMeasureTwice()) {
...
// now we can get the width and height from the children.
mLayout.setMeasuredDimensionFromChildren(widthSpec, heightSpec);
}
} else {
...
}
}
當RecyclerView的LayoutManager#isAutoMeasureEnabled()傳回true時,RecyclerView高度取決于children view的布局高度,并非取決于RecyclerView自身的測量高度。
下面是setMeasuredDimensionFromChildren(int widthSpec, int heightSpec)源碼
void setMeasuredDimensionFromChildren(int widthSpec, int heightSpec) {
final int count = getChildCount();
if (count == 0) {
mRecyclerView.defaultOnMeasure(widthSpec, heightSpec);
return;
}
int minX = Integer.MAX_VALUE;
int minY = Integer.MAX_VALUE;
int maxX = Integer.MIN_VALUE;
int maxY = Integer.MIN_VALUE;
for (int i = 0; i < count; i++) {
View child = getChildAt(i);
final Rect bounds = mRecyclerView.mTempRect;
getDecoratedBoundsWithMargins(child, bounds);
if (bounds.left < minX) {
minX = bounds.left;
}
if (bounds.right > maxX) {
maxX = bounds.right;
}
if (bounds.top < minY) {
minY = bounds.top;
}
if (bounds.bottom > maxY) {
maxY = bounds.bottom;
}
}
mRecyclerView.mTempRect.set(minX, minY, maxX, maxY);
setMeasuredDimension(mRecyclerView.mTempRect, widthSpec, heightSpec);
}
該方法計算了RecyclerView目前所有Child View的布局範圍mRecyclerView.mTempRect,最後調用了public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec),并将得出的布局範圍mRecyclerView.mTempRect、RecyclerView的測量參數widthSpec、heightSpec作為參數傳入,以此來決定RecyclerView最終寬高值。
最終解決方法
是以,我們隻需要重寫LayoutManager的public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec)方法即可為RecyclerView設定最大寬高。
` @Override
public void setMeasuredDimension(Rect childrenBounds, int wSpec, int hSpec) {
super.setMeasuredDimension(childrenBounds, wSpec, View.MeasureSpec.makeMeasureSpec(DeviceUtil.dp2px(mContext,246), AT_MOST));
}`
屬性的标簽實作
标簽的實作用的是flowlayout,用法很簡單,這裡就不在描述了。
至此,如圖的效果就實作了,還有不懂的可看demo代碼。
檢視源碼