Android实现多维商品属性SKU选择
程序员文章站
2023-09-04 14:26:32
前言:
最近又做到这一块的需求,以前也做过类似仿淘宝的属性选择,当时在网上下载的demo参考,最多也支持两组商品属性,用的两个gridview结合,扩展性很差,这次不打算...
前言:
最近又做到这一块的需求,以前也做过类似仿淘宝的属性选择,当时在网上下载的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:地址
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。