Android实现商品规格选择器(邻接矩阵法)

参考网上基于邻接矩阵的商品规格选择器算法的java实现,在安卓app里用的,没有包括adapter的部分,就光是矩阵工具类的部分

原理和效果图 都参考这篇博客

数据结构定义


// 1.某类规格
public static class Spec {
    public String type;
    public List<String> values;
}

例如new Spec("color",["red","blue"])

// 2.某个规格值
public static class OneSpec {
    public String type;
    public String value;
    public int idx = -1;
}

例如new OneSpec("color","red")

// 3.sku对应的规格值
public static class ItemSpecs {
    public String sku;
    public List<OneSpec> specs = new ArrayList<>();
}

例如new ItemSpecs(skuCode,["red","128G"])

// 4.规格选择器工具类
public class ItemSpecsAdjoinMatrix {

    private List<OneSpec> flattenSpecs = new ArrayList<>(); // 所有规格值(构成邻接矩阵的边)
    private int[][] matrix; // 邻接矩阵
    private Map<String, String> skuMap = new HashMap<>(); // 根据规格值的组合来映射sku
    private OneSpec[] selectedSpecArray; // 保存各类规格当前选择的值(每一类至多选一个)
    
}

构造邻接矩阵

根据可选的sku列表、总的规格列表,构造邻接矩阵

设置行号、设置规格组合sku映射表的时候 感觉自己好机智哈哈

public ItemSpecsAdjoinMatrix(List<ItemSpecs> itemSpecs, List<Spec> specs) {
    // 1.初始化为全都不选
    selectedSpecArray = new OneSpec[specs.size()];
    for (int i = 0; i < specs.size(); i++) {
        selectedSpecArray[i] = new OneSpec(specs.get(i).type, "");
    }
    // 2.把规格值“拍扁”保存,并设置在矩阵中的行号
    int idx = 0;
    for (Spec spec : specs) {
        for (String s : spec.values) {
            flattenSpecs.add(new OneSpec(spec.type, s, idx));
            idx++;
        }
    }
    // 3.给商品规格值标记行号,便于通过坐标设置矩阵节点的连通性
    for (ItemSpecs item : itemSpecs) {
        for (OneSpec oneSpec : item.specs) {
            setOneSpecIdx(oneSpec);
        }
    }
    // 4.保存规格组合字符串与sku的映射表
    String[] skuKey = new String[selectedSpecArray.length];
    for (ItemSpecs item : itemSpecs) {
        for (OneSpec oneSpec : item.specs) {
            for (int i = 0; i < specs.size(); i++) {
                if (TextUtils.equals(specs.get(i).type, oneSpec.type)) {
                    skuKey[i] = oneSpec.value;
                }
            }
        }
        StringBuilder str = new StringBuilder();
        for (String key : skuKey) str.append(key);
        skuMap.put(str.toString(), item.sku);
    }
    // 5.初始化矩阵,默认同类型的点联通,其他各点都不连通
    int n = flattenSpecs.size();
    matrix = new int[n][n];
    for (int r = 0; r < n; r++) {
        for (int c = 0; c < n; c++) {
            matrix[r][c] = 0;
            if (TextUtils.equals(flattenSpecs.get(r).type, flattenSpecs.get(c).type)) matrix[r][c] = 1;
        }
    }
    // 6.标记sku对应的联通点
    for (ItemSpecs item : itemSpecs) {
        for (OneSpec rowSpec : item.specs) {
            int r = rowSpec.idx;
            for (OneSpec colSpec : item.specs) {
                int c = colSpec.idx;
                matrix[r][c] = 1;
            }
        }
    }
}
// 其中setOneSpecIdx是根据type和value在flattenSpec找到属性idx
private void setOneSpecIdx(OneSpec oneSpec) {
    for (OneSpec oneSpec1 : flattenSpecs) {
        if (!TextUtils.equals(oneSpec.type, oneSpec1.type)) continue;
        if (!TextUtils.equals(oneSpec.value, oneSpec1.value)) continue;
        oneSpec.idx = oneSpec1.idx;
        break;
    }
}

选择器点击事件处理

// 1.更新已选数组
public String refreshSelectedSpec(OneSpec oneSpec) {
    setOneSpecIdx(oneSpec);
    for (OneSpec spec : selectedSpecArray) {
        if (TextUtils.equals(spec.type, oneSpec.type)) {
            if (TextUtils.equals(spec.value, oneSpec.value)) {
            // 取消选择
                spec.value = "";
                spec.idx = -1;
            } else {
            // 更新选中的规格值
                spec.value = oneSpec.value;
                spec.idx = oneSpec.idx;
            }
            break;
        }
    }
    String str = "";
    for (OneSpec spec : selectedSpecArray) {
        str += spec.value;
    }
    return skuMap.get(str); //返回选中的skucode
}

40a445592b1750004038b450235ec40b.jpg

// 2.根据sku算法获得每个规格值的enabled状态(如上图)
public int[] getEnabledSpecs() {
    int n = flattenSpecs.size();
    int[] tmp = new int[n];
    for (int i = 0; i < n; i++) tmp[i] = 1;
    for (OneSpec spec : selectedSpecArray) {
        int c = spec.idx;
        if (c == -1) continue;
        for (int r = 0; r < n; r++) {
            if (matrix[r][c] == 0) {
                tmp[r] = 0;
            }
        }
    }
    return tmp;
}

然后就给可以根据enabled、selected状态显示控件颜色,根据sku显示商品价格了

猜你喜欢

转载自juejin.im/post/7006531200911147022