【Android开发—电商系列】(二):仿淘宝商品属性标签页

一睹为快

      这里写图片描述

需求

1.动态加载属性,如尺码,颜色,款式等

由于每件商品的属性是不确定的,有的商品的属性是颜色和尺码,有的是口味,有的是大小,所以这些属性不能直接写死到页面上。

2.动态加载属性下的标签

每个属性下的标签个数也不是一定的,比如有的商品的尺码是是S,M,XL,有的是均码,也就是每种属性的具体的内容是不一定的。

技术点

自定义ViewGroup,使其中的TextView可以依据内容长短自动换行,如下图所示

     这里写图片描述

实现

布局

通过ListView来显示商品所有属性,每种属性作为ListView的Item。

 <!-- 商品规格列表 -->
    <LinearLayout 
        android:layout_width="match_parent"
        android:layout_height="match_parent"        
        android:background="#FFFFFFFF"
        >
         <ListView 
             android:id="@+id/lv_property"           
             android:layout_width="fill_parent"
             android:layout_height="match_parent"
             android:layout_marginLeft="5dp"
              android:layout_marginRight="5dp"
             android:divider="#C0C0C0"
             android:dividerHeight="0.5px"
             android:listSelector="#00000000">

        </ListView> 
    </LinearLayout>

自定义ViewGroup

普通的LinearLayout只能横向和纵向显示控件,但是当一行显示不够时,无法自动换行,需要我们自定义布局容器。

package jczb.shoping.common;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;

public class MyViewGroup extends ViewGroup {

     private final static int VIEW_MARGIN=15;

     public MyViewGroup(Context context, AttributeSet attrs){
         super(context, attrs);
     }

     public MyViewGroup(Context context) {
         super(context);
     }
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int stages = 1;
        int stageHeight = 0;
        int stageWidth = 0;

        int wholeWidth = MeasureSpec.getSize(widthMeasureSpec);

        for (int i = 0; i < getChildCount(); i++) {
            final View child = getChildAt(i);
            // measure
            measureChild(child, widthMeasureSpec, heightMeasureSpec);
            stageWidth += (child.getMeasuredWidth() + VIEW_MARGIN);
            stageHeight = child.getMeasuredHeight();
            if (stageWidth >= wholeWidth) {
                stages++;
                //reset stageWidth
                stageWidth = child.getMeasuredWidth();
            }

        }

        int wholeHeight = (stageHeight + VIEW_MARGIN) * stages;

        // report this final dimension
        setMeasuredDimension(resolveSize(wholeWidth, widthMeasureSpec),
                resolveSize(wholeHeight, heightMeasureSpec));
     }
     private int jiange = 10;//按钮之间的间隔
     @Override
     protected void onLayout(boolean arg0, int arg1, int arg2, int arg3, int arg4) {

         final int count = getChildCount();
         int row=0;// which row lay you view relative to parent
         int lengthX=arg1 ;    // right position of child relative to parent
         int lengthY=arg2;    // bottom position of child relative to parent
         for(int i=0;i<count;i++){

             final View child = this.getChildAt(i);
             int width = child.getMeasuredWidth();
             int height = child.getMeasuredHeight();
             if(i == 0){
                 lengthX+=width+VIEW_MARGIN;//第一个的时候不需要加
             }else{
                 lengthX+=width+VIEW_MARGIN +jiange;//按钮之间的间隔
             }

             lengthY=row*(height+VIEW_MARGIN)+VIEW_MARGIN+height+arg2;
             //if it can"t drawing on a same line , skip to next line
             if(lengthX>arg3){
                 lengthX=width+VIEW_MARGIN+arg1;
                 row++;
                 lengthY=row*(height+VIEW_MARGIN)+VIEW_MARGIN+height+arg2;
             }
             child.layout(lengthX-width, lengthY-height, lengthX, lengthY);
         }
     }
}

ListView的Adapter

package jczb.shoping.adapter;

import java.util.ArrayList;
import java.util.HashMap;

import jczb.shoping.common.MyViewGroup;
import jczb.shoping.ui.R;
import android.content.Context;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.LinearLayout.LayoutParams;
import android.widget.TableLayout;
import android.widget.TextView;

public class PropertyAdapter extends BaseAdapter {

    private Context mContext;
    private ArrayList<HashMap<String,Object>> mList;
    private ArrayList<HashMap<String,TextView[]>> mViewList;
    private Drawable drawableNormal ;
    private Drawable drawablePressed;
    private Handler mHandler;

    //用于保存用户的属性集合
    private HashMap<String,String> selectProMap=new HashMap<String, String>();
    /**
     * 返回选中的属性
     * @return
     */
    public HashMap<String, String> getSelectProMap() {
        return selectProMap;
    }

    public void setSelectProMap(HashMap<String, String> selectProMap) {
        this.selectProMap = selectProMap;
    }

    public PropertyAdapter(Handler handler,Context context,ArrayList<HashMap<String,Object>> list){
        super();
        this.mHandler=handler;
        this.mContext=context;
        this.mList=list;
        mViewList=new ArrayList<HashMap<String,TextView[]>>();
        drawableNormal=mContext.getResources().getDrawable(R.drawable.tv_property_label);
    }

    @Override
    public int getCount() {
        // TODO Auto-generated method stub
        return mList.size();
    }

    @Override
    public Object getItem(int position) {
        // TODO Auto-generated method stub
        return mList.get(position);
    }

    @Override
    public long getItemId(int position) {
        // TODO Auto-generated method stub
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder holder = null; 
        if (convertView == null) {
            // 获取list_item布局文件的视图
            convertView = LayoutInflater.from(this.mContext).inflate(R.layout.lv_property_item, null,true);
            holder = new ViewHolder(); 

            // 获取控件对象
            holder.tvPropName= (TextView) convertView
                    .findViewById(R.id.tv_property_name);
            //holder.llPropContents=(LinearLayout)convertView.findViewById(R.id.ll_property_content);
            //holder.tlPropContents=(TableLayout)convertView.findViewById(R.id.ll_property_content);
            // 设置控件集到convertView
            holder.vgPropContents= (MyViewGroup) convertView.findViewById(R.id.myviewgroup);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag(); 
        }
        if (this.mList != null) {
            //HashMap<String,TextView[]> mapView=new HashMap<String, TextView[]>();
            ArrayList<String> lables = (ArrayList<String>) this.mList.get(position).get("lable");
            String type = (String) this.mList.get(position).get(
                    "type");
            holder.tvPropName.setText(type);//规格名称
            //动态加载标签
            //判断布局中的子控件是否为0,如果不为0,就不添加了,防止ListView滚动时重复添加
            if(holder.vgPropContents.getChildCount()==0){
                TextView[]  textViews = new TextView[lables.size()];
                //设置每个标签的文本和布局
                //TableRow tr=new TableRow(mContext);

                 for (int i = 0; i < lables.size(); i++) {
                     TextView textView = new TextView(mContext);                     textView.setGravity(17);
                     textView.setPadding(25,15,25,15);               
                     textViews[i] = textView;
                     textViews[i].setBackgroundResource(R.drawable.tv_property_label);
                     textViews[i].setText(lables.get(i));
                     textViews[i].setTag(i);

                     //textViews[i].setBackgroundColor(Color.parseColor("#EE5500"));
                     //tr.addView(textViews[i]);
                    // holder.llPropContents.addView(textViews[i]);
                     holder.vgPropContents.addView(textViews[i]);
                 }
                 //holder.tlPropContents.addView(tr);
                 //绑定标签的Click事件
                 for(int j=0;j<textViews.length;j++){
                     textViews[j].setTag(textViews);
                     textViews[j].setOnClickListener(new LableClickListener(type));
                 }

                 //把控件存起来
//               mapView.put(type, textViews);
//               mViewList.add(mapView);
            }
            /**判断之前是否已选中标签*/
            if(selectProMap.get(type)!=null){
                for(int h=0;h<holder.vgPropContents.getChildCount();h++){
                    TextView v=(TextView) holder.vgPropContents.getChildAt(h);
                    if(selectProMap.get(type).equals(v.getText().toString())){
                        v.setBackgroundColor(Color.parseColor("#EE5500"));
                        v.setTextColor(Color.parseColor("#FFFFFF"));
                        selectProMap.put(type, v.getText().toString());
                    }
                }
            }

        }
        return convertView;
    }
    /*定义item对象*/
    public class ViewHolder {

        TextView tvPropName;    
        LinearLayout llPropContents;
        MyViewGroup vgPropContents;
        TableLayout tlPropContents;
   }
     class LableClickListener implements OnClickListener{
        private String type; 
        public LableClickListener(String type){

            this.type=type;
        }
        @Override
        public void onClick(View v) {
            TextView[] textViews=(TextView[])v.getTag();
            TextView tv=(TextView)v;
            for(int i=0;i<textViews.length;i++){
                //让点击的标签背景变成橙色,字体颜色变为白色
                if(tv.equals(textViews[i])){
                    textViews[i].setBackgroundColor(Color.parseColor("#EE5500"));
                    textViews[i].setTextColor(Color.parseColor("#FFFFFF"));
                    selectProMap.put(type, textViews[i].getText().toString());
                }else{
                    //其他标签背景变成白色,字体颜色为黑色
                    //textViews[i].setBackgroundDrawable(drawableNormal);
                    textViews[i].setBackgroundResource(R.drawable.tv_property_label);
                    textViews[i].setTextColor(Color.parseColor("#000000"));
                }
            }

        }

     } 

}

总结

  这里关键就是实现自定义的ViewGroup,重写onMeasure和onLayout方法,判断新添加的控件有没有超出屏幕的宽度来决定是否要换行。

文章导航