当前位置: 移动技术网 > 移动技术>移动开发>Android > Android实现多维商品属性SKU选择

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

2019年08月01日  | 移动技术网移动技术  | 我要评论

前言:

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

如图所示,界面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:地址

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

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网