Android 仿淘宝选中商品不同尺寸的按钮组

文章转载自 http://blog.csdn.net/qq_30552993/article/details/52304744

今天刚好有个同学他想做一个仿淘宝中的选中商品不同尺寸,比如衣服有L、M、XL等等的款式。这时候我们就需要一个button组来进行了,当时这个时候里面的尺寸可能有很多,那怎么办呢?这里我们就肯定要做个自适应的按钮组了,要不然弄出来也没用。废话不多说,先上个效果图:


是不是感觉起来效果蛮不错的呢?偷笑偷笑偷笑

现在我们就来说说里面的一些原理把!说句实话,我也不是大神,这个也是查询网上的一些原理问题弄出来的,希望大家不要嫌弃哦!么么哒!

一、原理:

1.其实这里我们用到的是一个ViewGroup控件组,把这些按钮加进去就有这种效果了!不过这里要继承ViewGroup(命名为:GoodsViewGroup)重写里面的一些方法。

2.主要的方法有:

GoodsViewGroup按钮组的控件大小

[java]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)  


里面的按钮每个的位置坐标

[java]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. protected void onLayout(boolean changed, int l, int t, int r, int b)   

这两个方法的具体使用大家可以网上查阅资料,这里就不多说了!


二、代码:

[java]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Created by ShaoLin on 2016/8/22. 
  3.  * 这里是类似淘宝中商品尺寸按钮组(这里做了支持button,textview) 
  4.  */  
  5. public class GoodsViewGroup<X extends TextView> extends ViewGroup {  
  6.   
  7.     public static final String BTN_MODE = "BTNMODE"//按钮模式  
  8.     public static final String TEV_MODE = "TEVMODE"//文本模式  
  9.   
  10.     private static final String TAG = "IViewGroup";  
  11.     private final int HorInterval = 10;    //水平间隔  
  12.     private final int VerInterval = 10;    //垂直间隔  
  13.   
  14.     private int viewWidth;   //控件的宽度  
  15.     private int viewHeight;  //控件的高度  
  16.   
  17.     private ArrayList<String> mTexts = new ArrayList<>();  
  18.     private Context mContext;  
  19.     private int textModePadding = 15;  
  20.   
  21.     //正常样式  
  22.     private float itemTextSize = 18;  
  23.     private int itemBGResNor = R.drawable.goods_item_btn_normal;  
  24.     private int itemTextColorNor = Color.parseColor("#000000");  
  25.   
  26.     //选中的样式  
  27.     private int itemBGResPre = R.drawable.goods_item_btn_selected;  
  28.     private int itemTextColorPre = Color.parseColor("#ffffff");  
  29.   
  30.     public GoodsViewGroup(Context context) {  
  31.         this(context, null);  
  32.     }  
  33.   
  34.     public GoodsViewGroup(Context context, AttributeSet attrs) {  
  35.         super(context, attrs);  
  36.         mContext = context;  
  37.     }  
  38.   
  39.     /** 
  40.      * 计算控件的大小 
  41.      */  
  42.     @Override  
  43.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  44.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  45.         viewWidth = measureWidth(widthMeasureSpec);  
  46.         viewHeight = measureHeight(heightMeasureSpec);  
  47.         Log.e(TAG, "onMeasure:" + viewWidth + ":" + viewHeight);  
  48.         // 计算自定义的ViewGroup中所有子控件的大小  
  49.         measureChildren(widthMeasureSpec, heightMeasureSpec);  
  50.         // 设置自定义的控件MyViewGroup的大小  
  51.         setMeasuredDimension(viewWidth, getViewHeight());  
  52.     }  
  53.   
  54.   
  55.     private int measureWidth(int pWidthMeasureSpec) {  
  56.         int result = 0;  
  57.         int widthMode = MeasureSpec.getMode(pWidthMeasureSpec);  
  58.         int widthSize = MeasureSpec.getSize(pWidthMeasureSpec);  
  59.         switch (widthMode) {  
  60.             /** 
  61.              * mode共有三种情况,取值分别为MeasureSpec.UNSPECIFIED, MeasureSpec.EXACTLY, 
  62.              * MeasureSpec.AT_MOST。 
  63.              * 
  64.              * 
  65.              * MeasureSpec.EXACTLY是精确尺寸, 
  66.              * 当我们将控件的layout_width或layout_height指定为具体数值时如andorid 
  67.              * :layout_width="50dip",或者为FILL_PARENT是,都是控件大小已经确定的情况,都是精确尺寸。 
  68.              * 
  69.              * 
  70.              * MeasureSpec.AT_MOST是最大尺寸, 
  71.              * 当控件的layout_width或layout_height指定为WRAP_CONTENT时 
  72.              * ,控件大小一般随着控件的子空间或内容进行变化,此时控件尺寸只要不超过父控件允许的最大尺寸即可 
  73.              * 。因此,此时的mode是AT_MOST,size给出了父控件允许的最大尺寸。 
  74.              * 
  75.              * 
  76.              * MeasureSpec.UNSPECIFIED是未指定尺寸,这种情况不多,一般都是父控件是AdapterView, 
  77.              * 通过measure方法传入的模式。 
  78.              */  
  79.             case MeasureSpec.AT_MOST:  
  80.             case MeasureSpec.EXACTLY:  
  81.                 result = widthSize;  
  82.                 break;  
  83.         }  
  84.         return result;  
  85.     }  
  86.   
  87.     private int measureHeight(int pHeightMeasureSpec) {  
  88.         int result = 0;  
  89.         int heightMode = MeasureSpec.getMode(pHeightMeasureSpec);  
  90.         int heightSize = MeasureSpec.getSize(pHeightMeasureSpec);  
  91.         switch (heightMode) {  
  92.             case MeasureSpec.UNSPECIFIED:  
  93.                 result = getSuggestedMinimumHeight();  
  94.                 break;  
  95.             case MeasureSpec.AT_MOST:  
  96.             case MeasureSpec.EXACTLY:  
  97.                 result = heightSize;  
  98.                 break;  
  99.         }  
  100.         return result;  
  101.     }  
  102.   
  103.     /** 
  104.      * 覆写onLayout,其目的是为了指定视图的显示位置,方法执行的前后顺序是在onMeasure之后,因为视图肯定是只有知道大小的情况下, 
  105.      * 才能确定怎么摆放 
  106.      */  
  107.     @Override  
  108.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  109.         // 遍历所有子视图  
  110.         int posLeft = HorInterval;  
  111.         int posTop = VerInterval;  
  112.         int posRight;  
  113.         int posBottom;  
  114.         for (int i = 0; i < getChildCount(); i++) {  
  115.             View childView = getChildAt(i);  
  116.             // 获取在onMeasure中计算的视图尺寸  
  117.             int measureHeight = childView.getMeasuredHeight();  
  118.             int measuredWidth = childView.getMeasuredWidth();  
  119.             if (posLeft + getNextHorLastPos(i) > viewWidth) {  
  120.                 posLeft = HorInterval;  
  121.                 posTop += (measureHeight + VerInterval);  
  122.             }  
  123.             posRight = posLeft + measuredWidth;  
  124.             posBottom = posTop + measureHeight;  
  125.             childView.layout(posLeft, posTop, posRight, posBottom);  
  126.             posLeft += (measuredWidth + HorInterval);  
  127.         }  
  128.     }  
  129.   
  130.     //获取控件的自适应高度  
  131.     private int getViewHeight() {  
  132.         int viewwidth = HorInterval;  
  133.         int viewheight = VerInterval;  
  134.         if (getChildCount() > 0) {  
  135.             viewheight = getChildAt(0).getMeasuredHeight() + VerInterval;  
  136.         }  
  137.         for (int i = 0; i < getChildCount(); i++) {  
  138.             View childView = getChildAt(i);  
  139.             // 获取在onMeasure中计算的视图尺寸  
  140.             int measureHeight = childView.getMeasuredHeight();  
  141.             int measuredWidth = childView.getMeasuredWidth();  
  142.             if (viewwidth + getNextHorLastPos(i) > viewWidth) {  
  143.                 viewwidth = HorInterval;  
  144.                 viewheight += (measureHeight + VerInterval);  
  145.             } else {  
  146.                 viewwidth += (measuredWidth + HorInterval);  
  147.             }  
  148.         }  
  149.         return viewheight;  
  150.     }  
  151.   
  152.     private int getNextHorLastPos(int i) {  
  153.         return getChildAt(i).getMeasuredWidth() + HorInterval;  
  154.     }  
  155.   
  156.     private OnGroupItemClickListener onGroupItemClickListener;  
  157.   
  158.     public void setGroupClickListener(OnGroupItemClickListener listener) {  
  159.         onGroupItemClickListener = listener;  
  160.         for (int i = 0; i < getChildCount(); i++) {  
  161.             final X childView = (X) getChildAt(i);  
  162.             final int itemPos = i;  
  163.             childView.setOnClickListener(new OnClickListener() {  
  164.                 @Override  
  165.                 public void onClick(View view) {  
  166.                     onGroupItemClickListener.onGroupItemClick(itemPos);  
  167.                     chooseItemStyle(itemPos);  
  168.                 }  
  169.             });  
  170.         }  
  171.     }  
  172.   
  173.     //选中那个的样式  
  174.     public void chooseItemStyle(int pos) {  
  175.         clearItemsStyle();  
  176.         if (pos < getChildCount()) {  
  177.             X childView = (X) getChildAt(pos);  
  178.             childView.setBackgroundResource(itemBGResPre);  
  179.             childView.setTextColor(itemTextColorPre);  
  180.             setItemPadding(childView);  
  181.         }  
  182.     }  
  183.   
  184.     private void setItemPadding(X view) {  
  185.         if (view instanceof Button) {  
  186.             view.setPadding(textModePadding, 0, textModePadding, 0);  
  187.         } else {  
  188.             view.setPadding(textModePadding, textModePadding, textModePadding, textModePadding);  
  189.         }  
  190.     }  
  191.   
  192.     //清除Group所有的样式  
  193.     private void clearItemsStyle() {  
  194.         for (int i = 0; i < getChildCount(); i++) {  
  195.             X childView = (X) getChildAt(i);  
  196.             childView.setBackgroundResource(itemBGResNor);  
  197.             childView.setTextColor(itemTextColorNor);  
  198.             setItemPadding(childView);  
  199.         }  
  200.     }  
  201.   
  202.     public void addItemViews(ArrayList<String> texts, String mode) {  
  203.         mTexts = texts;  
  204.         removeAllViews();  
  205.         for (String text : texts) {  
  206.             addItemView(text, mode);  
  207.         }  
  208.     }  
  209.   
  210.     private void addItemView(String text, String mode) {  
  211.         X childView = null;  
  212.         switch (mode) {  
  213.             case BTN_MODE:  
  214.                 childView = (X) new Button(mContext);  
  215.                 break;  
  216.             case TEV_MODE:  
  217.                 childView = (X) new TextView(mContext);  
  218.                 break;  
  219.         }  
  220.         childView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,  
  221.                 LayoutParams.WRAP_CONTENT));  
  222.         childView.setTextSize(itemTextSize);  
  223.         childView.setBackgroundResource(itemBGResNor);  
  224.         setItemPadding(childView);  
  225.         childView.setTextColor(itemTextColorNor);  
  226.         childView.setText(text);  
  227.         this.addView(childView);  
  228.     }  
  229.   
  230.     public String getChooseText(int itemID) {  
  231.         if (itemID >= 0) {  
  232.             return mTexts.get(itemID);  
  233.         }  
  234.         return null;  
  235.     }  
  236.   
  237.     public void setItemTextSize(float itemTextSize) {  
  238.         this.itemTextSize = itemTextSize;  
  239.     }  
  240.   
  241.     public void setItemBGResNor(int itemBGResNor) {  
  242.         this.itemBGResNor = itemBGResNor;  
  243.     }  
  244.   
  245.     public void setItemTextColorNor(int itemTextColorNor) {  
  246.         this.itemTextColorNor = itemTextColorNor;  
  247.     }  
  248.   
  249.     public void setItemBGResPre(int itemBGResPre) {  
  250.         this.itemBGResPre = itemBGResPre;  
  251.     }  
  252.   
  253.     public void setItemTextColorPre(int itemTextColorPre) {  
  254.         this.itemTextColorPre = itemTextColorPre;  
  255.     }  
  256.   
  257.     public interface OnGroupItemClickListener {  
  258.         void onGroupItemClick(int item);  
  259.     }  
  260. }  

上面提供了可以设置按钮组的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

[html]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <layer-list xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <item>  
  4.         <shape>  
  5.             <solid android:color="#F5F5F5" />  
  6.             <corners android:radius="15.0dip" />  
  7.         </shape>  
  8.     </item>  
  9. </layer-list>  

2.goods_item_btn_selected.xml

[html]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <layer-list xmlns:android="http://schemas.android.com/apk/res/android">  
  3.     <item>  
  4.         <shape>  
  5.             <solid android:color="#FE4F00" />  
  6.             <corners android:radius="15.0dip" />  
  7.         </shape>  
  8.     </item>  
  9. </layer-list>  
四、例子:

ButtonGroupActivity

[java]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. /** 
  2.  * Created by ShaoLin on 2016/8/22. 
  3.  */  
  4. public class ButtonGroupActivity extends Activity implements GoodsViewGroup.OnGroupItemClickListener, View.OnClickListener {  
  5.   
  6.     private GoodsViewGroup<TextView> mGroup;  
  7.     private Button mSubmitBtn;  
  8.     private ArrayList<String> viewtexts = new ArrayList<>();  
  9.   
  10.     private int chooseID = -1;  
  11.     private String chooseText;  
  12.   
  13.     @Override  
  14.     protected void onCreate(Bundle savedInstanceState) {  
  15.         setContentView(R.layout.activity_buttongroup);  
  16.   
  17.         mGroup = (GoodsViewGroup) findViewById(R.id.viewGroup);  
  18.         mSubmitBtn = (Button) findViewById(R.id.submitBtn);  
  19.   
  20.         String text;  
  21.         for (int i = 0; i < 10; i++) {  
  22.             text = "L" + i;  
  23.             viewtexts.add(text);  
  24.         }  
  25.         mGroup.addItemViews(viewtexts, GoodsViewGroup.TEV_MODE);  
  26.         mGroup.setGroupClickListener(this);  
  27.         mSubmitBtn.setOnClickListener(this);  
  28.         super.onCreate(savedInstanceState);  
  29.     }  
  30.   
  31.     @Override  
  32.     public void onGroupItemClick(int item) {  
  33.         chooseID = item;  
  34.         chooseText = mGroup.getChooseText(item);  
  35.     }  
  36.   
  37.     @Override  
  38.     public void onClick(View view) {  
  39.         if (chooseID >= 0) {  
  40.             showToast("ID:" + chooseID + ";text:" + chooseText);  
  41.         } else {  
  42.             showToast("请选择");  
  43.         }  
  44.     }  
  45.   
  46.     private void showToast(String text) {  
  47.         Toast.makeText(ButtonGroupActivity.this, text, Toast.LENGTH_SHORT).show();  
  48.     }  
  49. }  
activity_buttongroup.xml

[html]  view plain   copy
  在CODE上查看代码片 派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  3.     android:id="@+id/linear_ayout"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:orientation="vertical">  
  7.   
  8.     <com.example.jisuanqi.GoodsViewGroup  
  9.         android:id="@+id/viewGroup"  
  10.         android:layout_width="match_parent"  
  11.         android:layout_height="wrap_content">  
  12.     </com.example.jisuanqi.GoodsViewGroup>  
  13.   
  14.     <Button  
  15.         android:id="@+id/submitBtn"  
  16.         android:text="确定"  
  17.         android:layout_width="match_parent"  
  18.         android:layout_height="wrap_content" />  
  19.   

猜你喜欢

转载自blog.csdn.net/daxiangzaici/article/details/52316852