前言:
最近又做到这一块的需求,以前也做过类似仿淘宝的属性选择,当时在网上下载的demo参考,最多也支持两组商品属性,用的两个gridview结合,扩展性很差,这次不打算用之前的代码,所以重新自己写了一个demo**(文末附上项目地址)**

如图所示,界面UI这一块肯定不用gridview,那样太过繁琐,所以采用recyclerview,item里面渲染ViewGroup,根据数据源的数量,往ViewGroup里面添加Textview。这样就可以解决它的每个属性按钮宽高自适应。
这里重点是重写ViewGroup里面的onMeasure和onLayout方法:

    /*** 测量子view大小 根据子控件设置宽和高*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){super.onMeasure(widthMeasureSpec, heightMeasureSpec);// 获得它的父容器为它设置的测量模式和大小int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);int modeWidth = MeasureSpec.getMode(widthMeasureSpec);int modeHeight = MeasureSpec.getMode(heightMeasureSpec);// 如果是warp_content情况下,记录宽和高int width = 0;int height = 0;/*** 记录每一行的宽度,width不断取最大宽度*/int lineWidth = 0;/*** 每一行的高度,累加至height*/int lineHeight = 0;int cCount = getChildCount();// 遍历每个子元素for (int i = 0; i < cCount; i++){View child = getChildAt(i);// 测量每一个child的宽和高measureChild(child, widthMeasureSpec, heightMeasureSpec);// 得到child的布局管理器MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();// 当前子空间实际占据的宽度int childWidth = child.getMeasuredWidth() + lp.leftMargin+ lp.rightMargin;// 当前子空间实际占据的高度int childHeight = child.getMeasuredHeight() + lp.topMargin+ lp.bottomMargin;/*** 如果加入当前child,则超出最大宽度,则的到目前最大宽度给width,类加height 然后开启新行*/if (lineWidth + childWidth > sizeWidth){width = Math.max(lineWidth, childWidth);// 取最大的lineWidth = childWidth; // 重新开启新行,开始记录// 叠加当前高度,height += lineHeight;// 开启记录下一行的高度lineHeight = childHeight;} else// 否则累加值lineWidth,lineHeight取最大高度{lineWidth += childWidth;lineHeight = Math.max(lineHeight, childHeight);}// 如果是最后一个,则将当前记录的最大宽度和当前lineWidth做比较if (i == cCount - 1){width = Math.max(width, lineWidth);height += lineHeight;}}setMeasuredDimension((modeWidth == MeasureSpec.EXACTLY) ? sizeWidth: width, (modeHeight == MeasureSpec.EXACTLY) ? sizeHeight: height);}
@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b){mAllViews.clear();mLineHeight.clear();int width = getWidth();int lineWidth = 0;int lineHeight = 0;// 存储每一行所有的childViewList<View> lineViews = new ArrayList<>();int cCount = getChildCount();// 遍历所有的孩子for (int i = 0; i < cCount; i++){View child = getChildAt(i);MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();int childWidth = child.getMeasuredWidth();int childHeight = child.getMeasuredHeight();// 如果已经需要换行if (childWidth + lp.leftMargin + lp.rightMargin + lineWidth > width){// 记录这一行所有的View以及最大高度mLineHeight.add(lineHeight);// 将当前行的childView保存,然后开启新的ArrayList保存下一行的childViewmAllViews.add(lineViews);lineWidth = 0;// 重置行宽lineViews = new ArrayList<>();}/*** 如果不需要换行,则累加*/lineWidth += childWidth + lp.leftMargin + lp.rightMargin;lineHeight = Math.max(lineHeight, childHeight + lp.topMargin+ lp.bottomMargin);lineViews.add(child);}// 记录最后一行mLineHeight.add(lineHeight);mAllViews.add(lineViews);int left = 0;int top = 0;// 得到总行数int lineNums = mAllViews.size();for (int i = 0; i < lineNums; i++){// 每一行的所有的viewslineViews = mAllViews.get(i);// 当前行的最大高度lineHeight = mLineHeight.get(i);// 遍历当前行所有的Viewfor (int j = 0; j < lineViews.size(); j++){View child = lineViews.get(j);if (child.getVisibility() == View.GONE){continue;}MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();//计算childView的Marginleft,top,right,bottomint lc = left + lp.leftMargin;int tc = top + lp.topMargin;int rc =lc + child.getMeasuredWidth();int bc = tc + child.getMeasuredHeight();child.layout(lc, tc, rc, bc);left += child.getMeasuredWidth() + lp.rightMargin+ lp.leftMargin;}left = 0;top += lineHeight;}}

接下来是SKU的算法,因为本人的学生时期数学没有好好学习,幂集什么的,都不是很懂。所以在这里用了另外一种方法,把选项状态(三种:不能选择,可以选择,已选中)依次对属性按钮做出修改,这里虽然做了一些不必要的循环判断,但胜在功能的实现,如果大家有更好的想法,望不吝赐教。

贴上adapter代码(重点initOptions、canClickOptions和getSelected三个方法

/*** Created by 胡逸枫 on 2017/1/16.*/
public class GoodsAttrsAdapter extends BaseRecyclerAdapter<GoodsAttrsBean.AttributesBean> {private SKUInterface myInterface;private SimpleArrayMap<Integer, String> saveClick;private List<GoodsAttrsBean.StockGoodsBean> stockGoodsList;//商品数据集合private String[] selectedValue;   //选中的属性private TextView[][] childrenViews;    //二维 装所有属性private final int SELECTED = 0x100;private final int CANCEL = 0x101;public GoodsAttrsAdapter(Context ctx, List<GoodsAttrsBean.AttributesBean> list, List<GoodsAttrsBean.StockGoodsBean> stockGoodsList) {super(ctx, list);this.stockGoodsList = stockGoodsList;saveClick = new SimpleArrayMap<>();childrenViews = new TextView[list.size()][0];selectedValue = new String[list.size()];for (int i = 0; i < list.size(); i++) {selectedValue[i] = "";}}public void setSKUInterface(SKUInterface myInterface) {this.myInterface = myInterface;}@Overridepublic int getItemLayoutId(int viewType) {return R.layout.item_skuattrs;}@Overridepublic void bindData(RecyclerViewHolder holder, int position, GoodsAttrsBean.AttributesBean item) {TextView tv_ItemName = holder.getTextView(R.id.tv_ItemName);SKUViewGroup vg_skuItem = (SKUViewGroup) holder.getView(R.id.vg_skuItem);tv_ItemName.setText(item.getTabName());List<String> childrens = item.getAttributesItem();int childrenSize = childrens.size();TextView[] textViews = new TextView[childrenSize];for (int i = 0; i < childrenSize; i++) {LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);params.setMargins(5, 5, 5, 0);TextView textView = new TextView(mContext);textView.setGravity(Gravity.CENTER);textView.setPadding(15, 5, 15, 5);textView.setLayoutParams(params);textView.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));textView.setText(childrens.get(i));textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));textViews[i] = textView;vg_skuItem.addView(textViews[i]);}childrenViews[position] = textViews;initOptions();canClickOptions();getSelected();}private int focusPositionG, focusPositionC;private class MyOnClickListener implements View.OnClickListener {//点击操作 选中SELECTED   取消CANCELprivate int operation;private int positionG;private int positionC;public MyOnClickListener(int operation, int positionG, int positionC) {this.operation = operation;this.positionG = positionG;this.positionC = positionC;}@Overridepublic void onClick(View v) {focusPositionG = positionG;focusPositionC = positionC;String value = childrenViews[positionG][positionC].getText().toString();switch (operation) {case SELECTED:saveClick.put(positionG, positionC + "");selectedValue[positionG] = value;myInterface.selectedAttribute(selectedValue);break;case CANCEL:saveClick.put(positionG, "");for (int l = 0; l < selectedValue.length; l++) {if (selectedValue[l].equals(value)) {selectedValue[l] = "";break;}}myInterface.uncheckAttribute(selectedValue);break;}initOptions();canClickOptions();getSelected();}}class MyOnFocusChangeListener implements View.OnFocusChangeListener {private int positionG;private int positionC;public MyOnFocusChangeListener(int positionG, int positionC) {this.positionG = positionG;this.positionC = positionC;}@Overridepublic void onFocusChange(View v, boolean hasFocus) {String clickpositionC = saveClick.get(positionG);if (hasFocus) {v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.pink));if (TextUtils.isEmpty(clickpositionC)) {((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));} else if (clickpositionC.equals(positionC + "")) {} else {((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));}} else {v.setBackgroundColor(ContextCompat.getColor(mContext, R.color.saddlebrown));if (TextUtils.isEmpty(clickpositionC)) {((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));} else if (clickpositionC.equals(positionC + "")) {} else {((TextView) v).setTextColor(ContextCompat.getColor(mContext, R.color.white));}}}}/*** 初始化选项(不可点击,焦点消失)*/private void initOptions() {for (int y = 0; y < childrenViews.length; y++) {for (int z = 0; z < childrenViews[y].length; z++) {//循环所有属性TextView textView = childrenViews[y][z];textView.setEnabled(false);textView.setFocusable(false);textView.setTextColor(ContextCompat.getColor(mContext, R.color.gray));//变灰}}}/*** 找到符合条件的选项变为可选*/private void canClickOptions() {for (int i = 0; i < childrenViews.length; i++) {for (int j = 0; j < stockGoodsList.size(); j++) {boolean filter = false;List<GoodsAttrsBean.StockGoodsBean.GoodsInfoBean> goodsInfo = stockGoodsList.get(j).getGoodsInfo();for (int k = 0; k < selectedValue.length; k++) {if (i == k || TextUtils.isEmpty(selectedValue[k])) {continue;}if (!selectedValue[k].equals(goodsInfo.get(k).getTabValue())) {filter = true;break;}}if (!filter) {for (int n = 0; n < childrenViews[i].length; n++) {TextView textView = childrenViews[i][n];//拿到所有属性TextViewString name = textView.getText().toString();//拿到属性名称if (goodsInfo.get(i).getTabValue().equals(name)) {textView.setEnabled(true);//符合就变成可点击textView.setFocusable(true); //设置可以获取焦点//不要让焦点乱跑if (focusPositionG == i && focusPositionC == n) {textView.setTextColor(ContextCompat.getColor(mContext, R.color.dodgerblue));textView.requestFocus();} else {textView.setTextColor(ContextCompat.getColor(mContext, R.color.white));}textView.setOnClickListener(new MyOnClickListener(SELECTED, i, n) {});textView.setOnFocusChangeListener(new MyOnFocusChangeListener(i, n) {});}}}}}}/*** 找到已经选中的选项,让其变红*/private void getSelected() {for (int i = 0; i < childrenViews.length; i++) {for (int j = 0; j < childrenViews[i].length; j++) {//拿到每行属性ItemTextView textView = childrenViews[i][j];//拿到所有属性TextViewString value = textView.getText().toString();for (int m = 0; m < selectedValue.length; m++) {if (selectedValue[m].equals(value)) {textView.setTextColor(ContextCompat.getColor(mContext, R.color.red));textView.setOnClickListener(new MyOnClickListener(CANCEL, i, j) {});}}}}}
}

下载链接:
GitHub

CSDN下载地址

Android多维商品属性SKU选择相关推荐

  1. Android 选择商品属性sku

    Android 选择商品属性sku 最近项目中使用SKU属性查询,类似淘宝京东商品的选择,在网上查询了弄了几个源码看看,发现还是实现不了多属性选择问题,再原基础上改动相当费事,所以想干脆自己处理这个问 ...

  2. 微信小程序实战篇:商品属性联动选择(案例)

    本期的微信小程序实战篇来做一个电商网站经常用到的-商品属性联动选择的效果,素材参考了一点点奶茶. 效果演示: 商品属性联动.gif 代码示例 1.commodity.xml <!-- <v ...

  3. 笛卡尔积处理商品属性sku

    笛卡尔积 笛卡尔积是指在数学中,两个集合X和Y的笛卡尔积(Cartesian product),又称直积,表示为X*Y,第一个对象是X的成员而第二个对象是Y的所有可能有序对的其中一个成员.假设集合A= ...

  4. 产品和商品的区别 sku spu的区别 什么事关键属性?什么事商品属性?

    产品 淘宝标准 化产品,由类目+关键属性唯一确定.如:手机类目,关键属性是品牌和型号,Nokia N95就是一个产品,nokia是品牌,N95是型号. 产品除了关键属性还包括销售属性和非关键属性. 参 ...

  5. sku展示php,前端如何展示商品属性:SKU多维属性状态判断算法的应用

    作者 | 周琪力 编辑 | 尾尾 本文为前端之巅周琪力原创,未经作者许可禁止转载. 问题描述 这个问题来源于选择商品属性的场景.比如我们买衣服.鞋子这类物件,一般都需要我们选择合适的颜色.尺码等属性 ...

  6. jquery仿淘宝SKU选择商品属性代码

    jquery仿淘宝SKU选择商品属性代码 下载地址:https://www.yujianni.top/news/comp_artinfo.html?id=103

  7. 前端如何展示商品属性:SKU多维属性状态判断算法的应用-Vue 实现

    由于公司开发了一个电商项目,涉及到前台商品属性的展示,所以百度上找了一下!找到了 周琪力写的一个算法例子,因为作者只有jQuery 实现demo, 自己仿照 demo 实现了一个 vue 的! 周琪力 ...

  8. 仿淘宝、京东多重商品属性组合Sku标签

    一.概述 首先声明,在这个Demo中我用到了zhy大神的自定义控件Android TagFlowLayout完全解析 一款针对Tag的布局,我只是在他的基础上对源码进行了一些修改,可以运用到我的项目中 ...

  9. Material之Behavior实现支付宝密码弹窗 仿淘宝/天猫商品属性选择

    版权声明:转载必须注明本文转自严振杰的博客: http://blog.csdn.net/yanzhenjie1003 今天的效果在支付宝.淘宝.京东等电商App中很常见.比如支付宝输入密码弹窗.商城下 ...

最新文章

  1. count时结果 hive_hive的count(distinct id)测试--慎用
  2. 《C++编程风格(修订版)》——1.1 抽象
  3. 4j是合法python数字类型_python数字类型
  4. 设计模式C++实现 —— 策略模式
  5. python 隐马尔科夫_机器学习算法之——隐马尔可夫(Hidden Markov ModelsHMM)原理及Python实现...
  6. 【华为云技术分享】LiteOS无法直接烧录或者烧录失败解决方法--ST-Link
  7. python学到哪知道baseline_Python NLTK学习6(创建词性标注器)
  8. 关于php车服务论文,「PHP」行车服务app后端代码简析
  9. Android Studio 添加javah工具
  10. 【现代卫星导航系统】之北斗卫星导航系统
  11. layui上传文件请求接口异常_解决layui table表单提示数据接口请求异常的问题
  12. 古今地名对照总表 按笔划数排序 强烈推荐的资料
  13. vue echarts 条纹柱状横向图
  14. Python中面向对象(类,对象,魔法,打印)
  15. python魔法方法指南_2011年最热门的20种方法指南
  16. 【FPGA】Verilog 实践:狄摩根定律 | 布尔方程 | 1bit 比较器
  17. 更换系统的jdk版本
  18. yocs_velocity_smoother速度平滑库知识
  19. AB实验平台在贝壳找房的设计与实践
  20. 计算机屏幕尺寸不是全屏,电脑屏幕有黑边撑不满怎么办_电脑屏幕不能全屏显示的解决方法...

热门文章

  1. The server is invalid. Error occurred reading server credential. Required file or directory ‘serverO
  2. [Day 7]JS FA、用户交互、JS动画的实现(二)
  3. echart地图加载中国地图,可切换省市地图
  4. 电容笔和触控笔哪个好?非常值得入手的平价电容笔推荐
  5. 被关在寝室的某个下午
  6. 公司企业邮箱怎么注册开通?
  7. aptx与ldac音质区别_ldac_aptx和aptx hd功能介绍及区别介绍
  8. 【路由器】OpenWrt 简介和安装
  9. ye我们胜利了的shooow
  10. ye lynn yama Loafer 已发送,请注意查收