服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Android - Android实现多维商品属性SKU选择

Android实现多维商品属性SKU选择

2022-08-13 11:24胡逸枫 Android

这篇文章主要为大家详细介绍了Android实现多维商品属性SKU选择,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

前言:

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

Android实现多维商品属性SKU选择

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

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/**
   * 测量子view大小 根据子控件设置宽和高
   */
  @Override
  protected 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);
 
  }
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
@Override
  protected 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;
    // 存储每一行所有的childView
    List<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保存下一行的childView
        mAllViews.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++)
    {
      // 每一行的所有的views
      lineViews = mAllViews.get(i);
      // 当前行的最大高度
      lineHeight = mLineHeight.get(i);
 
      // 遍历当前行所有的View
      for (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,bottom
        int 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三个方法)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
/**
 * 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;
  }
 
  @Override
  public int getItemLayoutId(int viewType) {
    return R.layout.item_skuattrs;
  }
 
  @Override
  public 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  取消CANCEL
    private 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;
    }
 
    @Override
    public 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;
    }
 
    @Override
    public 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];//拿到所有属性TextView
            String 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++) {//拿到每行属性Item
        TextView textView = childrenViews[i][j];//拿到所有属性TextView
        String 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:地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

原文链接:https://blog.csdn.net/u012860273/article/details/54666672?utm_source=blogxgwz3

延伸 · 阅读

精彩推荐