android软件开发之仿淘宝选择规格的实现

版权声明: https://blog.csdn.net/qq_41760133/article/details/82773235

  在一些app开发项目中选择商品规格这个功能最容易遇到问题,想要实现需要的全部功能,但一直没有成功,所以就去找了个Demo,学习界面UI采用recyclerview,item里面渲染ViewGroup,根据数据源的数量,往ViewGroup里面添加Textview。这样就可以解决它的每个属性按钮宽高自适应。下面来详细分享一下源码:

/**

* 测量子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

ListlineViews = 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三个方法)

public class GoodsAttrsAdapter extends BaseRecyclerAdapter {

private SKUInterface myInterface;

private SimpleArrayMap saveClick;

private List stockGoodsList;//商品数据集合

private String[] selectedValue; //选中的属性

private TextView[][] childrenViews; //二维 装所有属性

private final int SELECTED = 0x100;

private final int CANCEL = 0x101;

public GoodsAttrsAdapter(Context ctx, List list, List 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());

Listchildrens = 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 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) {

});

}

}

}

}

}

}

  好了,到这里就算是结束了,如果还是存在有疑问的地方,大家可以留言咨询。

  本文由专业的郑州app开发公司燚轩科技整理发布,原创不易,如需转载请注明出处!

猜你喜欢

转载自blog.csdn.net/qq_41760133/article/details/82773235