android用sku算法仿淘宝选择颜色分类弹框。

  当规格超出边界会自动换行,点击规格会根据算法判断关联规格,无则灰显,全部选中后则变化图片。代码是kotlin和java混合。

效果如下,当一行显示不下所有规格时,会自动换行。用的夜神模拟器,分辨率有点怪。



里面用到的图片都是百度随意找的,侵删。

前面根据各自接口获取数据添加进

testData.productStocks
testData.getAttributes()

 下面是主要代码 

//选择参数弹框
fun showBottomSheetDialog(view: View) {
    if (mUiData.getBottomSheetDialog() == null) {
        mUiData.getSelectedEntities().clear()
        val view = layoutInflater.inflate(R.layout.dialog_integral_mall_choose_format, null)
        val recyclerView: RecyclerView = view.findViewById(R.id.dimcfRecyler)//列表
        dimcfChooseText = view.findViewById(R.id.dimcfChooseText)
        dimcfMoney = view.findViewById(R.id.dimcfMoney)
        dimcfPoints = view.findViewById(R.id.dimcfPoints)
        dimcfIv = view.findViewById(R.id.dimcfIv)
        ivMinus = view.findViewById(R.id.ivMinus)
        ivPlus = view.findViewById(R.id.ivPlus)
        tvAmount = view.findViewById(R.id.tvAmount)
        GlideImageUtil.loadWebImage(this,
                GlideImageUtil.compressImage(userImag, "300"), dimcfIv)
        rlConfirm = view.findViewById(R.id.rlConfirm)
        rlConfirm?.setOnClickListener {
            //根据业务需求进入下一步
        }

        rlConfirm?.isClickable = false
        dimcfMoney?.text = getPrice(minProPrice1.toDouble())

        setDialogIv(tvAmount?.text.toString())
        ivPlus?.setOnClickListener {
            if (tvAmount?.text.toString().isBlank()) {
                Snackbar.make(view, "购买数量不能为空", Snackbar.LENGTH_LONG).show()
                return@setOnClickListener
            }
            var s = Integer.parseInt(tvAmount?.text.toString())
            s++
            tvAmount?.setText("$s")
            tvAmount?.setSelection(tvAmount?.text.toString().length)
            setDialogIv("$s")
        }
        ivMinus?.setOnClickListener {
            if (tvAmount?.text.toString().isBlank()) {
                Snackbar.make(view, "购买数量不能为空", Snackbar.LENGTH_LONG).show()
                return@setOnClickListener
            }
            var s = Integer.parseInt(tvAmount?.text.toString())
            s--
            tvAmount?.setText("$s")
            tvAmount?.setSelection(tvAmount?.text.toString().length)
            setDialogIv("$s")
        }
        tvAmount?.setOnKeyListener(object : View.OnKeyListener {
            override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean {
                if (keyCode == KeyEvent.KEYCODE_ENTER && event?.getAction() == KeyEvent.ACTION_DOWN) {
                    if (tvAmount?.text.toString().isBlank()) {
                        Snackbar.make(view, "请输入购买数量", Snackbar.LENGTH_LONG).show()
                    } else {
                        var s = Integer.parseInt(tvAmount?.text.toString())
                        if (s <= 1) {
                            s = 1
                        } else if (s >= 999) {
                            s = 999
                        }
                        tvAmount?.setText("$s")
                        setDialogIv("$s")
                    }
                    return true
                }
                return false
            }
        })
        tvAmount?.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(p0: Editable?) {

            }

            override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {

            }

            override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                if (p0?.length != 0) {
                    ss = Integer.parseInt(p0?.toString())
                    if (ss <= 1) {
                        ss = 1
                        var msg = Message()
                        msg.what = 1
                        handler.sendMessage(msg)
                    } else if (ss >= 999) {
                        ss = 999
                        var msg = Message()
                        msg.what = 1
                        handler.sendMessage(msg)
                    }
                    setDialogIv("$ss")
                }
            }
        })

        dimcfPoints?.text = "积分可兑换" + minUsedIntegral1
        val skuAdapters = SkuAdapters(testData.attributes, this, mUiData)
        // 设置adapter
        recyclerView.adapter = skuAdapters
        // 设置布局管理器
        recyclerView.layoutManager = mLayoutManager
        // SKU 计算
        mUiData.setResult(Sku.skuCollection(testData.productStocks))


        mUiData.bottomSheetDialog = BottomSheetDialog(this);
        mUiData.bottomSheetDialog.setContentView(view)
        mUiData.bottomSheetDialog.getDelegate().findViewById<View>(android.support.design.R.id.design_bottom_sheet)?.setBackgroundColor(getResources().getColor(R.color.transparent));
        val parent: View = view.getParent() as View//获取ParentView
        val behavior = BottomSheetBehavior.from(parent)
        view.measure(0, 0)
        behavior.peekHeight = view.getMeasuredHeight()
        val params: CoordinatorLayout.LayoutParams = parent.layoutParams as CoordinatorLayout.LayoutParams
        params.gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
        parent.layoutParams = params
        var bottomSheetBehavior = BottomSheetBehavior.from(parent);
        mUiData.bottomSheetDialog.setOnDismissListener(object : DialogInterface.OnDismissListener {
            override fun onDismiss(dialog: DialogInterface?) {
                bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
            }
        })
        mUiData.bottomSheetDialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN and WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
        mUiData.getBottomSheetDialog().show()

    } else {
        mUiData.bottomSheetDialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN and WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
        mUiData.getBottomSheetDialog().show()
    }
}
以上是弹框内的代码,目前看不出什么东西,主要让我们看下
 val skuAdapters = SkuAdapters(testData.attributes, this, mUiData)和
  mUiData.setResult(Sku.skuCollection(testData.productStocks))
先来看下adapter里
entity.status=0 //可点击可选
entity.status=1//已选可取消
entity.status=2 //因为算法规则不可选
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.tv_title.text=data?.get(position)?.name
    holder.flowlayout.removeAllViews()
    var layoutp:LinearLayout.LayoutParams= LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,DensityUtil.dip2px(mContext,35f))
    layoutp.setMargins(DensityUtil.dip2px(mContext, 5f), 0, DensityUtil.dip2px(mContext, 5f), 0);
    for (i in 0..data?.get(position)?.getAttributeMembers().size!!.minus(1)) {
        var button = Button(mContext)
        button.setTextSize(TypedValue.COMPLEX_UNIT_SP, 12f)
        button.setBackgroundResource(R.drawable.integral_choose)
        button.setTextColor(mContext.resources.getColor(R.color.text_gray6))
        when (data?.get(position)?.getAttributeMembers().get(i).getStatus()) {
            //可选未选中
            0 -> {
                button.setAlpha(1f)
                button.setBackgroundResource(R.drawable.integral_choose)
            }
            //选中
            1 -> {
                button.setAlpha(1f)
                button.setTextColor(mContext.resources.getColor(R.color.white))
                button.setBackgroundResource(R.drawable.login_btn_bg)
            }
            //不可选
            2 -> {
                button.setAlpha(0.4f)
                button.setBackgroundResource(R.drawable.integral_choose)
            }
        }
        button.setPadding(DensityUtil.dip2px(mContext,10f),0,DensityUtil.dip2px(mContext,10f),0)
        button.setText(data?.get(position)?.getAttributeMembers().get(i).name)
        button.setLines(1)
        button.setOnClickListener {
            if (data.get(position).attributeMembers.get(i).getStatus() == 2) {
                return@setOnClickListener
            }
            for (entity in data.get(position).attributeMembers) {
                if (entity == data.get(position).attributeMembers.get(i)) {
                    if (entity.status==1){
                        entity.setStatus(0)
                    }else
                    entity.setStatus(1)
                } else {
                    entity.setStatus(if (entity.getStatus() == 2) 2 else 0)
                }
            }
            mUiData?.getSelectedEntities()?.clear()
            var str=""
            for (j in 0..data?.size.minus(1)) {
                for (entity in data.get(j).attributeMembers) {
                    if (entity.status == 1) {
                        //添加选中的规格
                        mUiData?.getSelectedEntities()?.add(entity)
                        str+="'"+entity.name+"' "
                    }
                }
            }
            onItemClickListener?.onItemConfig(str, mUiData?.getSelectedEntities().size,data.size)
            if (mUiData?.getSelectedEntities().size == data.size) {
                for (h in 0..mUiData?.getSelectedEntities().size.minus(2)) {
                    for (k in 0..mUiData?.getSelectedEntities().size.minus(2 + h)) {
                        var cacheEntity: ProductModel.AttributesEntity.AttributeMembersEntity
                        if (mUiData?.getSelectedEntities()[k].attributeGroupId > mUiData?.getSelectedEntities()[k + 1].attributeGroupId) {
                            //交换数据
                            cacheEntity = mUiData?.getSelectedEntities()[k]
                            mUiData?.getSelectedEntities()[k] = mUiData?.getSelectedEntities()[k + 1]
                            mUiData?.getSelectedEntities()[k + 1] = cacheEntity
                        }
                    }
                }

                var   buffer1 = StringBuffer()
                for (selectedEntity in mUiData?.getSelectedEntities()) {
                    buffer1?.append(selectedEntity.attributeMemberId.toString() + ";")
                }

             var sku: BaseSkuModel = mUiData.result.get(buffer1?.substring(0, buffer1?.length?.minus(1)!!))!!
                onItemClickListener?.onItemUpdata(sku.url,sku.proPrice,sku.usedIntegral)
            }
            for (j in 0..data?.size.minus(1)) {
                for (entity in data.get(j).attributeMembers) {
                    // 冒泡排序
                    val cacheSelected = ArrayList<ProductModel.AttributesEntity.AttributeMembersEntity>()
                    cacheSelected.add(entity)
                    cacheSelected.addAll(mUiData?.getSelectedEntities()!!)
                    if (cacheSelected.size <= 1) {

                    } else {
                        for (h in 0..cacheSelected.size.minus(2)) {
                            for (k in 0..cacheSelected.size.minus(2 + h)) {
                                var cacheEntity: ProductModel.AttributesEntity.AttributeMembersEntity
                                if (cacheSelected[k].attributeGroupId > cacheSelected[k + 1].attributeGroupId) {
                                    //交换数据
                                    cacheEntity = cacheSelected[k]
                                    cacheSelected[k] = cacheSelected[k + 1]
                                    cacheSelected[k + 1] = cacheEntity
                                }
                            }
                        }
                        for (h in 0..cacheSelected.size.minus(2)) {
                            for (k in 0..cacheSelected.size.minus(2 + h)) {
                                if ((k + 1) >= cacheSelected.size) {

                                } else if (cacheSelected[k].attributeGroupId == cacheSelected[k + 1].attributeGroupId) {
                                    cacheSelected.removeAt(k + 1)
                                }
                            }
                        }
                    }

                    buffer = StringBuffer()
                    for (selectedEntity in cacheSelected) {
                        buffer?.append(selectedEntity.attributeMemberId.toString() + ";")
                    }
                    //TODO 检查数据
                    if (mUiData?.getResult()?.get(buffer?.substring(0, buffer?.length?.minus(1)!!)) != null) {
                        entity.setStatus(if (entity.getStatus() == 1) 1 else 0)
                    } else {
                        entity.setStatus(2)
                    }
                }
            }
            notifyDataSetChanged()
        }
        holder.flowlayout.addView(button,layoutp)
    }
}
以下是
Sku算法。

/**
 * 算法入口
 *
 * @param initData 所有库存的hashMap组合
 * @return 拆分所有组合产生的所有情况(生成客户端自己的字典)
 */
public static Map<String, BaseSkuModel> skuCollection(Map<String, BaseSkuModel> initData) {
    //用户返回数据
    HashMap<String, BaseSkuModel> result = new HashMap<>();
    // 遍历所有库存
    for (String subKey : initData.keySet()) {
        BaseSkuModel skuModel = initData.get(subKey);
        //根据;拆分key的组合
        String[] skuKeyAttrs = subKey.split(";");

        //获取所有的组合
        ArrayList<ArrayList<String>> combArr = combInArray(skuKeyAttrs);

        // 对应所有组合添加到结果集里面
        for (int i = 0; i < combArr.size(); i++) {
            add2SKUResult(result, combArr.get(i), skuModel);
        }
        // 将原始的库存组合也添加进入结果集里面
        String key = TextUtils.join(";", skuKeyAttrs);
        result.put(key, skuModel);
    }
    return result;
}

/**
 * 获取所有的组合放到ArrayList里面
 *
 * @param skuKeyAttrs 单个key被; 拆分的数组
 * @return ArrayList
 */
private static ArrayList<ArrayList<String>> combInArray(String[] skuKeyAttrs) {
    if (skuKeyAttrs == null || skuKeyAttrs.length <= 0)
        return null;
    int len = skuKeyAttrs.length;
    ArrayList<ArrayList<String>> aResult = new ArrayList<>();
    for (int n = 1; n < len; n++) {
        ArrayList<Integer[]> aaFlags = getCombFlags(len, n);
        for (int i = 0; i < aaFlags.size(); i++) {
            Integer[] aFlag = aaFlags.get(i);
            ArrayList<String> aComb = new ArrayList<>();
            for (int j = 0; j < aFlag.length; j++) {
                if (aFlag[j] == 1) {
                    aComb.add(skuKeyAttrs[j]);
                }
            }
            aResult.add(aComb);
        }
    }
    return aResult;
}

/**
 * 算法拆分组合 用1和0 的移位去做控制
 * (这块需要你打印才能看的出来)
 *
 * @param len
 * @param n
 * @return
 */
private static ArrayList<Integer[]> getCombFlags(int len, int n) {
    if (n <= 0) {
        return new ArrayList<>();
    }
    ArrayList<Integer[]> aResult = new ArrayList<>();
    Integer[] aFlag = new Integer[len];
    boolean bNext = true;
    int iCnt1 = 0;
    //初始化
    for (int i = 0; i < len; i++) {
        aFlag[i] = i < n ? 1 : 0;
    }
    aResult.add(aFlag.clone());
    while (bNext) {
        iCnt1 = 0;
        for (int i = 0; i < len - 1; i++) {
            if (aFlag[i] == 1 && aFlag[i + 1] == 0) {
                for (int j = 0; j < i; j++) {
                    aFlag[j] = j < iCnt1 ? 1 : 0;
                }
                aFlag[i] = 0;
                aFlag[i + 1] = 1;
                Integer[] aTmp = aFlag.clone();
                aResult.add(aTmp);
                if (!TextUtils.join("", aTmp).substring(len - n).contains("0")) {
                    bNext = false;
                }
                break;
            }
            if (aFlag[i] == 1) {
                iCnt1++;
            }
        }
    }
    return aResult;
}
/**
 * 添加到数据集合
 *
 * @param result
 * @param newKeyList
 * @param skuModel
 */
private static void add2SKUResult(HashMap<String, BaseSkuModel> result, ArrayList<String> newKeyList, BaseSkuModel skuModel) {
    String key = TextUtils.join(";", newKeyList);
    if (result.keySet().contains(key)) {
        result.get(key).setUsedIntegral(result.get(key).getUsedIntegral() );
        result.get(key).setProPrice(skuModel.getProPrice());
        result.get(key).setUrl(skuModel.getUrl());
    } else {
        result.put(key, new BaseSkuModel(skuModel.getProPrice(), skuModel.getUsedIntegral(),skuModel.getUrl()));
    }
}
//
刚接触的时候 我以为他会组合出所有情况包括顺序变化,然而..有兴趣的人可以自己断点看看。
代码不是很复杂,下面附上activity的全部代码
class SkuActivity : Activity(), SkuAdapters.OnItemClickListener {
    var testData = ProductModel()
    private var ss = 0
    //价格,demo内写死
    var minProPrice1 = "666"
    //可抵扣积分,demo内写死
    var minUsedIntegral1 = "360"
    //主图 当没有图片时 则显示
    var userImag="http://img1.imgtn.bdimg.com/it/u=2764371306,3467823016&fm=214&gp=0.jpg"
    //recyclerView所需的布局
    var mLayoutManager: LinearLayoutManager? = null
    var mUiData: UiData = UiData()
    //弹框内控件
    var dimcfChooseText: TextView? = null
    var dimcfPoints: TextView? = null
    var dimcfMoney: TextView? = null
    var dimcfIv: ImageView? = null
    var ivMinus: ImageView? = null
    var ivPlus: ImageView? = null
    var tvAmount: EditText? = null
    var rlConfirm: RelativeLayout? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.sku_layout)
        //算法匹配规则数据
        getBaseSkuModel()
        //具体规格如颜色尺码
        getAttributesModle()
        mLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
    }

    fun getBaseSkuModel(){
        var str: String = "{" +
                "\"1;7;12\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"1;6;14\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"1;7;11\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"1;6;15\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"1;6;12\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"1;6;13\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }," +
                " \"1;9;12\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"2;8;14\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"1;9;11\": {" +

                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +


                "   \"url\": \"\"" +
                " }," +
                " \"2;8;13\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"1;9;14\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"2;8;12\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +

                " \"url\": \"\"" +
                "   }," +
                "  \"1;9;13\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"2;8;11\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;8;12\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;8;13\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;8;11\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;8;15\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;8;14\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "   }," +
                "   \"1;9;15\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"2;8;15\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"1;7;15\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "  }," +
                "  \"1;6;11\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;7;13\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"1;7;14\": {" +

                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +


                "\"url\": \"\"" +
                "  }," +
                "  \"3;7;15\": {" +

                "\"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"3;9;12\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"3;9;11\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"3;9;15\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +


                " \"url\": \"\"" +
                "   }," +
                "   \"3;9;14\": {" +

                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;9;13\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;7;13\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;7;14\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"3;7;11\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"3;7;12\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;9;13\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;9;12\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;9;15\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;9;14\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;9;11\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "  \"url\": \"\"" +
                "}," +
                "\"1;5;13\": {" +
                "  \"proPrice\": 2000," +
                "  \"usedIntegral\": 2000," +
                "  \"url\": \"http://img3.imgtn.bdimg.com/it/u=2777008330,1289798081&fm=27&gp=0.jpg\"" +
                "}," +
                "\"1;5;15\": {" +
                "  \"proPrice\": 2000," +
                "  \"usedIntegral\": 2000," +
                "  \"url\": \"\"" +
                "}," +
                "\"2;6;13\": {" +
                "  \"proPrice\": 2000," +
                "  \"usedIntegral\": 2000," +
                "  \"url\": \"\"" +
                "}," +
                "\"3;8;12\": {" +
                "  \"proPrice\": 2000," +
                "  \"usedIntegral\": 2000," +
                "  \"url\": \"\"" +
                "}," +
                "\"2;6;14\": {" +
                "  \"proPrice\": 2000," +
                "  \"usedIntegral\": 2000," +
                "  \"url\": \"\"" +
                "   }," +
                "   \"3;8;13\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;6;15\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;8;14\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;8;15\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;5;14\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;5;15\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;5;12\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;5;13\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;8;11\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;7;14\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;5;13\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"2;7;15\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;5;14\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;5;15\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;6;14\": {" +
                " \"proPrice\": 2000," +
                " \"usedIntegral\": 2000," +
                " \"url\": \"\"" +
                "   }," +
                "   \"3;6;15\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"3;6;13\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"3;6;12\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"3;6;11\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;7;11\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"3;5;12\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "\"url\": \"\"" +
                "  }," +
                "  \"2;7;13\": {" +
                "\"proPrice\": 2000," +
                "\"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }," +
                " \"3;5;11\": {" +
                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }," +
                " \"2;7;12\": {" +
                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }," +
                " \"2;5;11\": {" +
                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }," +
                " \"2;6;12\": {" +
                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }," +
                " \"2;6;11\": {" +
                "   \"proPrice\": 2000," +
                "   \"usedIntegral\": 2000," +
                "   \"url\": \"\"" +
                " }" + "}"
        var type: Type = object : TypeToken<BaseSkuModel>() {}.type
        var gson = Gson()

        var json:JsonObject=JsonParser().parse(str).asJsonObject

        val sIterator = json.keySet().iterator()

        while (sIterator.hasNext()) {
            // 获得key
            val key = sIterator.next()
            // 根据key获得value, value也可以是JSONObject,JSONArray,使用对应的参数接收即可
            var baseSkuModel: BaseSkuModel = gson.fromJson(json.get(key).toString(), type)
            testData.productStocks.put(key, baseSkuModel)
        }
    }
    fun getAttributesModle(){

        var str1="[" +
                "{" +
                "         \"specValueList\": [" +
                "           {" +
                "             \"valueName\": \"11\"," +
                "             \"valueTitle\": \"\"," +
                "             \"valueId\": 1," +
                "             \"select\": false" +
                "           }," +
                "           {" +
                "             \"valueName\": \"12\"," +
                "             \"valueTitle\": \"\"," +
                "               \"valueId\": 2," +
                "               \"select\": false" +
                "             }," +
                "             {" +
                "               \"valueName\": \"13\"," +
                "               \"valueTitle\": \"\"," +
                "               \"valueId\": 3," +
                "               \"select\": false" +
                "             }" +
                "           ]," +
                "         \"specId\": 4," +
                "         \"specValues\": null," +
                "         \"specName\": \"尺码\"" +
                "       }," +
                "       {" +
                "         \"specValueList\": [" +
                "           {" +
                "             \"valueName\": \"2\"," +
                "             \"valueTitle\": \"\"," +
                "             \"valueId\": 5," +
                "      \"select\": false" +
                "    }," +
                "    {" +
                "      \"valueName\": \"3\"," +
                "      \"valueTitle\": \"\"," +
                "      \"valueId\": 6," +
                "      \"select\": false" +
                "    }," +
                "    {" +
                "      \"valueName\": \"4\"," +
                "          \"valueTitle\": \"\"," +
                "          \"valueId\": 7," +
                "          \"select\": false" +
                "        }," +
                "        {" +
                "          \"valueName\": \"5\"," +
                "          \"valueTitle\": \"\"," +
                "          \"valueId\": 8," +
                "          \"select\": false" +
                "        }," +
                "          {" +
                "            \"valueName\": \"6\"," +
                "            \"valueTitle\": \"\"," +
                "            \"valueId\": 9," +
                "            \"select\": false" +
                "          }" +
                "        ]," +
                "        \"specId\": 10," +
                "        \"specValues\": null," +
                "        \"specName\": \"尺寸\"" +
                "      }," +
                "       {" +
                "         \"specValueList\": [" +
                "           {" +
                "             \"valueName\": \"80\"," +
                "             \"valueTitle\": \"\"," +
                "             \"valueId\": 11," +
                "             \"select\": false" +
                "           }," +
                "           {" +
                "             \"valueName\": \"85\"," +
                "             \"valueTitle\": \"\"," +
                "               \"valueId\": 12," +
                "               \"select\": false" +
                "             }," +
                "             {" +
                "               \"valueName\": \"90\"," +
                "               \"valueTitle\": \"\"," +
                "               \"valueId\": 13," +
                "               \"select\": false" +
                "             }," +
                "             {" +
                "               \"valueName\": \"95\"," +
                "             \"valueTitle\": \"\"," +
                "             \"valueId\": 14," +
                "             \"select\": false" +
                "           }," +
                "           {" +
                "             \"valueName\": \"100\"," +
                "             \"valueTitle\": \"\"," +
                "             \"valueId\": 15," +
                "             \"select\": false" +
                "           }" +
                "         ]," +
                "           \"specId\": 16," +
                "           \"specValues\": null," +
                "           \"specName\": \"重量\"" +
                "         }" +
                "       ]"
        var json1 =JSONArray(str1)
        for (i in 0..json1.length().minus(1)) {
            val group = ProductModel.AttributesEntity()

            for (j in 0..json1.getJSONObject(i).getJSONArray("specValueList").length().minus(1)) {
                group.attributeMembers.add(j, ProductModel.AttributesEntity.
                        AttributeMembersEntity(json1.getJSONObject(i).getInt("specId"),json1.getJSONObject(i).getJSONArray("specValueList").getJSONObject(j).getInt("valueId"), json1.getJSONObject(i).getJSONArray("specValueList").getJSONObject(j).getString("valueName")))
            }
            group.name = json1.getJSONObject(i).getString("specName")
            testData.getAttributes().add(i, group)
        }
    }
    //选择一项后 参数设置
    override fun onItemConfig(config: String, new: Int, old: Int) {
        if (new == old) {
            rlConfirm?.setBackgroundColor(resources.getColor(R.color.colorPrimary))
            rlConfirm?.isClickable = true
        } else {
            rlConfirm?.setBackgroundColor(resources.getColor(R.color.line))
            rlConfirm?.isClickable = false
        }
        if (config.isEmpty()) {
            dimcfChooseText?.text = "请选择"
        } else {
            dimcfChooseText?.text = "已选择" + config
        }
    }


    //选择完全部参数设置
    override fun onItemUpdata(url1: String, price: Double, integral: Double) {
        var url = url1
        dimcfPoints?.text = "积分可兑换" + integral
        dimcfMoney?.text = getPrice(price)
        if (url.isEmpty()) {
            url = userImag
        }
        GlideImageUtil.loadWebImage(this,
                GlideImageUtil.compressImage(url, "240"), dimcfIv)
    }
    //小数点后数字缩小
    fun getPrice(srt: Double): SpannableStringBuilder {
        var price = "¥" + getBigDecimal(srt)
        val spanBuilder = SpannableStringBuilder(price)
        //style 为0 即是正常的,还有Typeface.BOLD(粗体) Typeface.ITALIC(斜体)等
        //size  为0 即采用原始的正常的 size大小
        spanBuilder.setSpan(TextAppearanceSpan(null, 0, 20, null, null), price.length - 2, price.length, Spanned.SPAN_EXCLUSIVE_INCLUSIVE)
        return spanBuilder
    }

    private fun setDialogIv(s: String) {
        var n = Integer.parseInt(s)
        if (n <= 1) {
            ivMinus?.isClickable = false
            ivMinus?.setImageResource(R.mipmap.jianhao_d)
            ivPlus?.isClickable = true
            ivPlus?.setImageResource(R.mipmap.jiahao)
        } else if (n >= 999) {
            ivPlus?.isClickable = false
            ivPlus?.setImageResource(R.mipmap.jiahao_d)
            ivMinus?.isClickable = true
            ivMinus?.setImageResource(R.mipmap.jianhao)
        } else {
            ivMinus?.isClickable = true
            ivMinus?.setImageResource(R.mipmap.jianhao)
            ivPlus?.isClickable = true
            ivPlus?.setImageResource(R.mipmap.jiahao)
        }
    }

    //选择参数弹框
    fun showBottomSheetDialog(view: View) {
        if (mUiData.getBottomSheetDialog() == null) {
            mUiData.getSelectedEntities().clear()
            val view = layoutInflater.inflate(R.layout.dialog_integral_mall_choose_format, null)
            val recyclerView: RecyclerView = view.findViewById(R.id.dimcfRecyler)//列表
            dimcfChooseText = view.findViewById(R.id.dimcfChooseText)
            dimcfMoney = view.findViewById(R.id.dimcfMoney)
            dimcfPoints = view.findViewById(R.id.dimcfPoints)
            dimcfIv = view.findViewById(R.id.dimcfIv)
            ivMinus = view.findViewById(R.id.ivMinus)
            ivPlus = view.findViewById(R.id.ivPlus)
            tvAmount = view.findViewById(R.id.tvAmount)
            GlideImageUtil.loadWebImage(this,
                    GlideImageUtil.compressImage(userImag, "300"), dimcfIv)
            rlConfirm = view.findViewById(R.id.rlConfirm)
            rlConfirm?.setOnClickListener {
                //根据业务需求进入下一步
            }

            rlConfirm?.isClickable = false
            dimcfMoney?.text = getPrice(minProPrice1.toDouble())

            setDialogIv(tvAmount?.text.toString())
            ivPlus?.setOnClickListener {
                if (tvAmount?.text.toString().isBlank()) {
                    Snackbar.make(view, "购买数量不能为空", Snackbar.LENGTH_LONG).show()
                    return@setOnClickListener
                }
                var s = Integer.parseInt(tvAmount?.text.toString())
                s++
                tvAmount?.setText("$s")
                tvAmount?.setSelection(tvAmount?.text.toString().length)
                setDialogIv("$s")
            }
            ivMinus?.setOnClickListener {
                if (tvAmount?.text.toString().isBlank()) {
                    Snackbar.make(view, "购买数量不能为空", Snackbar.LENGTH_LONG).show()
                    return@setOnClickListener
                }
                var s = Integer.parseInt(tvAmount?.text.toString())
                s--
                tvAmount?.setText("$s")
                tvAmount?.setSelection(tvAmount?.text.toString().length)
                setDialogIv("$s")
            }
            tvAmount?.setOnKeyListener(object : View.OnKeyListener {
                override fun onKey(v: View?, keyCode: Int, event: KeyEvent?): Boolean {
                    if (keyCode == KeyEvent.KEYCODE_ENTER && event?.getAction() == KeyEvent.ACTION_DOWN) {
                        if (tvAmount?.text.toString().isBlank()) {
                            Snackbar.make(view, "请输入购买数量", Snackbar.LENGTH_LONG).show()
                        } else {
                            var s = Integer.parseInt(tvAmount?.text.toString())
                            if (s <= 1) {
                                s = 1
                            } else if (s >= 999) {
                                s = 999
                            }
                            tvAmount?.setText("$s")
                            setDialogIv("$s")
                        }
                        return true
                    }
                    return false
                }
            })
            tvAmount?.addTextChangedListener(object : TextWatcher {
                override fun afterTextChanged(p0: Editable?) {

                }

                override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {

                }

                override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
                    if (p0?.length != 0) {
                        ss = Integer.parseInt(p0?.toString())
                        if (ss <= 1) {
                            ss = 1
                            var msg = Message()
                            msg.what = 1
                            handler.sendMessage(msg)
                        } else if (ss >= 999) {
                            ss = 999
                            var msg = Message()
                            msg.what = 1
                            handler.sendMessage(msg)
                        }
                        setDialogIv("$ss")
                    }
                }
            })

            dimcfPoints?.text = "积分可兑换" + minUsedIntegral1
            val skuAdapters = SkuAdapters(testData.attributes, this, mUiData)
            // 设置adapter
            recyclerView.adapter = skuAdapters
            // 设置布局管理器
            recyclerView.layoutManager = mLayoutManager
            // SKU 计算
            mUiData.setResult(Sku.skuCollection(testData.productStocks))


            mUiData.bottomSheetDialog = BottomSheetDialog(this);
            mUiData.bottomSheetDialog.setContentView(view)
            mUiData.bottomSheetDialog.getDelegate().findViewById<View>(android.support.design.R.id.design_bottom_sheet)?.setBackgroundColor(getResources().getColor(R.color.transparent));
            val parent: View = view.getParent() as View//获取ParentView
            val behavior = BottomSheetBehavior.from(parent)
            view.measure(0, 0)
            behavior.peekHeight = view.getMeasuredHeight()
            val params: CoordinatorLayout.LayoutParams = parent.layoutParams as CoordinatorLayout.LayoutParams
            params.gravity = Gravity.TOP or Gravity.CENTER_HORIZONTAL
            parent.layoutParams = params
            var bottomSheetBehavior = BottomSheetBehavior.from(parent);
            mUiData.bottomSheetDialog.setOnDismissListener(object : DialogInterface.OnDismissListener {
                override fun onDismiss(dialog: DialogInterface?) {
                    bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
                }
            })
            mUiData.bottomSheetDialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN and WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
            mUiData.getBottomSheetDialog().show()

        } else {
            mUiData.bottomSheetDialog.window.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN and WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN)
            mUiData.getBottomSheetDialog().show()
        }
    }


    private var handler = object : Handler() {
        override fun handleMessage(msg: Message?) {
            when (msg?.what) {
                1 -> {
                    tvAmount?.setText("$ss")
                    setDialogIv("$ss")
                    tvAmount?.setSelection(tvAmount?.text.toString().length)
                    removeCallbacksAndMessages(null)
                }
            }
        }
    }

    fun getBigDecimal(double: Double): String {
        val bg = BigDecimal(double)
        val f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).toString()
        return f1
    }
}
具体代码:http://download.csdn.net/download/qq_26602021/10139550

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
以下是一个React组件的代码实现,用于实现前端SKU算法的商品多规格选择功能: ```jsx import React, { useState, useEffect } from "react"; const SKUSelector = ({ skuList }) => { const [selectedValues, setSelectedValues] = useState({}); const [availableOptions, setAvailableOptions] = useState({}); useEffect(() => { // 初始化可选项列表 let options = {}; skuList.forEach((sku) => { sku.attributes.forEach((attr) => { if (!options[attr.name]) { options[attr.name] = [attr.value]; } else if (!options[attr.name].includes(attr.value)) { options[attr.name].push(attr.value); } }); }); setAvailableOptions(options); }, [skuList]); const handleValueChange = (name, value) => { // 更新已选项列表 setSelectedValues({ ...selectedValues, [name]: value }); // 根据已选项列表筛选可选项列表 let options = { ...availableOptions }; for (let attrName in selectedValues) { if (attrName !== name) { skuList.forEach((sku) => { if ( sku.attributes.find((attr) => attr.name === attrName)?.value !== selectedValues[attrName] ) { options[attrName] = options[attrName].filter( (option) => option !== selectedValues[attrName] ); } }); } } setAvailableOptions(options); }; const getAvailableValues = (name) => { // 获取指定规格属性的可选项列表 return availableOptions[name] || []; }; const getSelectedSKU = () => { // 根据已选项列表获取SKU信息 let selectedSKU = null; skuList.forEach((sku) => { let matches = true; sku.attributes.forEach((attr) => { if (selectedValues[attr.name] !== attr.value) { matches = false; } }); if (matches) { selectedSKU = sku; } }); return selectedSKU; }; return ( <div> {skuList.length > 0 ? ( skuList[0].attributes.map((attr) => ( <div key={attr.name}> <label>{attr.name}:</label> <select value={selectedValues[attr.name] || ""} onChange={(e) => handleValueChange(attr.name, e.target.value)} > <option value="">请选择</option> {getAvailableValues(attr.name).map((option) => ( <option key={option} value={option}> {option} </option> ))} </select> </div> )) ) : ( <div>暂无商品信息</div> )} {getSelectedSKU() ? ( <div> <p>已选规格:{JSON.stringify(selectedValues)}</p> <p>剩余库存:{getSelectedSKU().stock}</p> </div> ) : ( <div>请选择完整规格属性</div> )} </div> ); }; export default SKUSelector; ``` 该组件接受一个SKU列表作为props,每个SKU包含一个属性列表和一个库存数量。在组件中,首先使用useEffect钩子初始化可选项列表,然后使用useState钩子管理已选项列表和可选项列表的状态。 当用户选择某个规格属性值时,组件会根据已选项列表筛选可选项列表,并更新已选项列表。当用户选择所有规格属性值后,组件会根据已选项列表获取相应的SKU信息,并显示剩余库存量。 该组件仅为示例代码,具体实现方式可能因业务需求而异。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值