首页 > 系统 > Android > 正文

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

2019-10-21 21:37:05
字体:
来源:转载
供稿:网友

前言:

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

Android,商品属性,SKU

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

/**   * 测量子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);  }
@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三个方法)

/** * 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:地址

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持VEVB武林网。


注:相关教程知识阅读请移步到Android开发频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表