效果图:
一、原理:
1.其实这里我们用到的是一个ViewGroup控件组,把这些按钮加进去就有这种效果了!不过这里要继承ViewGroup(命名为:GoodsViewGroup)重写里面的一些方法。
2.主要的方法有:
GoodsViewGroup按钮组的控件大小
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)
里面的按钮每个的位置坐标
protected void onLayout(boolean changed, int l, int t, int r, int b)
这两个方法的具体使用大家可以网上查阅资料,这里就不多说了!
二、代码:
/**
* Created by ShaoLin on 2016/8/22.
* 这里是类似淘宝中商品尺寸按钮组(这里做了支持button,textview)
*/
public class GoodsViewGroup<X extends TextView> extends ViewGroup {
public static final String BTN_MODE = "BTNMODE"; //按钮模式
public static final String TEV_MODE = "TEVMODE"; //文本模式
private static final String TAG = "IViewGroup";
private final int HorInterval = 50; //水平间隔
private final int VerInterval = 20; //垂直间隔
private int viewWidth; //控件的宽度
private int viewHeight; //控件的高度
private ArrayList<String> mTexts = new ArrayList<>();
private Context mContext;
private int textModePadding = 30;
private int textModePaddingLeft = 50;
private int textModePaddingTop = 25;
private int textModePaddingRight = 50;
private int textModePaddingBottom = 25;
//正常样式
private float itemTextSize = 12;
private int itemBGResNor = R.drawable.goods_item_btn_normal;
private int itemTextColorNor = Color.parseColor("#000000");
//选中的样式
private int itemBGResPre = R.drawable.goods_item_btn_selected;
private int itemTextColorPre = Color.parseColor("#ffffff");
public GoodsViewGroup(Context context) {
this(context, null);
}
public GoodsViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
}
/**
* 计算控件的大小
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
viewWidth = measureWidth(widthMeasureSpec);
viewHeight = measureHeight(heightMeasureSpec);
Log.e(TAG, "onMeasure:" + viewWidth + ":" + viewHeight);
// 计算自定义的ViewGroup中所有子控件的大小
measureChildren(widthMeasureSpec, heightMeasureSpec);
// 设置自定义的控件MyViewGroup的大小
setMeasuredDimension(viewWidth, getViewHeight());
}
private int measureWidth(int pWidthMeasureSpec) {
int result = 0;
int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);
int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);
switch (widthMode) {
/**
* mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY,
* MeasureSpec.AT_MOST。
*
*
* MeasureSpec.EXACTLY是精确尺寸,
* 当我们将控件的layout_width或layout_height指定为具体数值时如andorid
* :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。
*
*
* MeasureSpec.AT_MOST是最大尺寸,
* 当控件的layout_width或layout_height指定为WRAP_CONTENT时
* ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可
* 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。
*
*
* MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView,
* 通过measure方法传入的模式。
*/
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = widthSize;
break;
}
return result;
}
private int measureHeight(int pHeightMeasureSpec) {
int result = 0;
int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);
int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);
switch (heightMode) {
case MeasureSpec.UNSPECIFIED:
result = getSuggestedMinimumHeight();
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
result = heightSize;
break;
}
return result;
}
/**
* 覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下,
* 才能确定怎么摆放
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
// 遍历所有子视图
int posLeft = HorInterval;
int posTop = VerInterval;
int posRight;
int posBottom;
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
// 获取在onMeasure中计算的视图尺寸
int measureHeight = childView.getMeasuredHeight();
int measuredWidth = childView.getMeasuredWidth();
if (posLeft + getNextHorLastPos(i) > viewWidth) {
posLeft = HorInterval;
posTop += (measureHeight + VerInterval);
}
posRight = posLeft + measuredWidth;
posBottom = posTop + measureHeight;
childView.layout(posLeft, posTop, posRight, posBottom);
posLeft += (measuredWidth + HorInterval);
}
}
/**
* 获取控件的自适应高度
*
* @return
*/
private int getViewHeight() {
int viewwidth = HorInterval;
int viewheight = VerInterval;
if (getChildCount() > 0) {
viewheight = getChildAt(0).getMeasuredHeight() + VerInterval;
}
for (int i = 0; i < getChildCount(); i++) {
View childView = getChildAt(i);
// 获取在onMeasure中计算的视图尺寸
int measureHeight = childView.getMeasuredHeight();
int measuredWidth = childView.getMeasuredWidth();
//------------当前按钮按钮是否在水平上够位置(2017/7/10)------------
if (viewwidth + getNextHorLastPos(i) > viewWidth) {
//------------修正没有计算所在行第一个所需宽度(2017/7/10)------------
viewwidth = (measuredWidth + HorInterval * 2);
viewheight += (measureHeight + VerInterval);
} else {
viewwidth += (measuredWidth + HorInterval);
}
}
return viewheight;
}
/**
* 当前按钮所需的宽度
* @param i
* @return
*/
private int getNextHorLastPos(int i) {
return getChildAt(i).getMeasuredWidth() + HorInterval;
}
private OnGroupItemClickListener onGroupItemClickListener;
public void setGroupClickListener(OnGroupItemClickListener listener) {
onGroupItemClickListener = listener;
for (int i = 0; i < getChildCount(); i++) {
final X childView = (X) getChildAt(i);
final int itemPos = i;
childView.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View view) {
onGroupItemClickListener.onGroupItemClick(itemPos);
chooseItemStyle(itemPos);
}
});
}
}
//选中那个的样式
public void chooseItemStyle(int pos) {
clearItemsStyle();
if (pos < getChildCount()) {
X childView = (X) getChildAt(pos);
childView.setBackgroundResource(itemBGResPre);
childView.setTextColor(itemTextColorPre);
setItemPadding(childView);
}
}
private void setItemPadding(X view) {
if (view instanceof Button) {
view.setPadding(textModePadding, 0, textModePadding, 0);
} else {
view.setPadding(textModePaddingLeft, textModePaddingTop, textModePaddingRight, textModePaddingBottom);
}
}
//清除Group所有的样式
private void clearItemsStyle() {
for (int i = 0; i < getChildCount(); i++) {
X childView = (X) getChildAt(i);
childView.setBackgroundResource(itemBGResNor);
childView.setTextColor(itemTextColorNor);
setItemPadding(childView);
}
}
public void addItemViews(ArrayList<String> texts, String mode) {
mTexts = texts;
removeAllViews();
for (String text : texts) {
addItemView(text, mode);
}
}
private void addItemView(String text, String mode) {
X childView = null;
switch (mode) {
case BTN_MODE:
childView = (X) new Button(mContext);
break;
case TEV_MODE:
childView = (X) new TextView(mContext);
break;
}
childView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
LayoutParams.WRAP_CONTENT));
childView.setTextSize(itemTextSize);
childView.setBackgroundResource(itemBGResNor);
setItemPadding(childView);
childView.setTextColor(itemTextColorNor);
childView.setText(text);
this.addView(childView);
}
public String getChooseText(int itemID) {
if (itemID >= 0) {
return mTexts.get(itemID);
}
return null;
}
public void setItemTextSize(float itemTextSize) {
this.itemTextSize = itemTextSize;
}
public void setItemBGResNor(int itemBGResNor) {
this.itemBGResNor = itemBGResNor;
}
public void setItemTextColorNor(int itemTextColorNor) {
this.itemTextColorNor = itemTextColorNor;
}
public void setItemBGResPre(int itemBGResPre) {
this.itemBGResPre = itemBGResPre;
}
public void setItemTextColorPre(int itemTextColorPre) {
this.itemTextColorPre = itemTextColorPre;
}
public interface OnGroupItemClickListener {
void onGroupItemClick(int item);
}
}
上面提供了可以设置按钮组的item的一些样式,还有这个GoodsViewGroup为什么要写成GoodsViewGroup<X extends TextView>这样呢?其实这里我是想做一个泛型,可以使用与Button跟TextView,而这里的Button本生就是继承TextView所以在代码中还要进行一个判断,可以看上面方法setItemPadding(X view)。那到了这里,有些好友可能就会问,为什么要搞两个呢?
其实这里因为TextView的不会自动有设置padding的,而button是有自动设置padding。这个时候你就要看看你是先要那种效果!不过通过我的代码中如果是选择TextView的话,这里也设置了一个padding给他,不然会很难看!
两种模式的写法:
1.Button :
GoodsViewGroup<Button> mGroup;
mGroup.addItemViews(viewtexts, GoodsViewGroup.BTN_MODE);
2.TextView
GoodsViewGroup<TextView> mGroup;
mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);
三、Drawable文件:上面涉及到的按钮选中与正常的两个Drawable
1.goods_item_btn_normal.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="#F5F5F5" />
<corners android:radius="15dp" />
</shape>
</item>
</layer-list>
2.goods_item_btn_selected.xml
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid android:color="@color/colorAccent" />
<corners android:radius="15dp" />
</shape>
</item>
</layer-list>
四、例子:
final ArrayList<String> viewtexts = new ArrayList<>();
viewtexts.add("基础信息");
viewtexts.add("通讯信息");
viewtexts.add("后备电源");
headViewHolde.viewGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);
headViewHolde.viewGroup.chooseItemStyle(0);
headViewHolde.viewGroup.setGroupClickListener(new GoodsViewGroup.OnGroupItemClickListener() {
@Override
public void onGroupItemClick(int item) {
Toast.makeText(mContext, viewtexts.get(item), Toast.LENGTH_SHORT).show();
}
});
xml页面
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/white"
android:layout_marginTop="10dp"
android:orientation="vertical">
<com.distributionsysten.view.GoodsViewGroup
android:id="@+id/viewGroup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp">
</com.distributionsysten.view.GoodsViewGroup>
</LinearLayout>