现在我们就来说说里面的一些原理把!
一、原理:
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 = 10; //水平间隔 private final int VerInterval = 10; //垂直间隔 private int viewWidth; //控件的宽度 private int viewHeight; //控件的高度 private ArrayList<String> mTexts = new ArrayList<>(); private Context mContext; private int textModePadding = 15; //正常样式 private float itemTextSize = 18; 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);} } //获取控件的自适应高度 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(); if (viewwidth + getNextHorLastPos(i) > viewWidth) {viewwidth = HorInterval;viewheight += (measureHeight + VerInterval); } else {viewwidth += (measuredWidth + HorInterval); }}return viewheight; } 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() {@Overridepublic 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(textModePadding, textModePadding, textModePadding, textModePadding);} } //清除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
给他,不然会很难看!GoodsViewGroup<Button> mGroup;mGroup.addItemViews(viewtexts, GoodsViewGroup.BTN_MODE);2.TextView
GoodsViewGroup<TextView> mGroup;mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);三、Drawable文件:上面涉及到的按钮选中与正常的两个Drawable
<?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="15.0dip" /></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="#FE4F00" /> <corners android:radius="15.0dip" /></shape> </item></layer-list>四、例子:
/** * Created by ShaoLin on 2016/8/22. */public class ButtonGroupActivity extends Activity implements GoodsViewGroup.OnGroupItemClickListener, View.OnClickListener { private GoodsViewGroup<TextView> mGroup; private Button mSubmitBtn; private ArrayList<String> viewtexts = new ArrayList<>(); private int chooseID = -1; private String chooseText; @Override protected void onCreate(Bundle savedInstanceState) {setContentView(R.layout.activity_buttongroup);mGroup = (GoodsViewGroup) findViewById(R.id.viewGroup);mSubmitBtn = (Button) findViewById(R.id.submitBtn);String text;for (int i = 0; i < 10; i++) { text = "L" + i; viewtexts.add(text);}mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);mGroup.setGroupClickListener(this);mSubmitBtn.setOnClickListener(this);super.onCreate(savedInstanceState); } @Override public void onGroupItemClick(int item) {chooseID = item;chooseText = mGroup.getChooseText(item); } @Override public void onClick(View view) {if (chooseID >= 0) { showToast("ID:" + chooseID + ";text:" + chooseText);} else { showToast("请选择");} } private void showToast(String text) {Toast.makeText(ButtonGroupActivity.this, text, Toast.LENGTH_SHORT).show(); }}activity_buttongroup.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/linear_ayout" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <com.example.jisuanqi.GoodsViewGroupandroid:id="@+id/viewGroup"android:layout_width="match_parent"android:layout_height="wrap_content"> </com.example.jisuanqi.GoodsViewGroup> <Buttonandroid:id="@+id/submitBtn"android:text="确定"android:layout_width="match_parent"android:layout_height="wrap_content" /></LinearLayout>总结