欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2022-05-27 10:23:57
前言: 最近又做到这一块的需求,以前也做过类似仿淘宝的属性选择,当时在网上下载的demo参考,最多也支持两组商品属性,用的两个gridview结合,扩展性很差,这次不打算...

前言:

最近又做到这一块的需求,以前也做过类似仿淘宝的属性选择,当时在网上下载的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:地址

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