自定义控件(商品属性选择)

之前在我的另外一个帐号中,发了一篇博文

博客地址http://blog.csdn.net/u012790647/article/details/16007559

不涉及版权的情况下,某些源码不是你的也不是我的,源码是共享的。交流才能进步。。。。。不重复造*创新才是王道

先上图:这是本博文的自定义控件

自定义控件(商品属性选择)自定义控件(商品属性选择)

使用的就是这篇博文将要写的一个自定义view,MyButton这个控件可以参考sdk中:

LabelView 

/*
 * Copyright (C) 2007 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.example.android.apis.view;

// Need the following import to get access to the app resources, since this
// class is in a sub-package.
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

import com.example.android.apis.R;


/**
 * Example of how to write a custom subclass of View. LabelView
 * is used to draw simple text views. Note that it does not handle
 * styled text or right-to-left writing systems.
 *
 */
public class LabelView extends View {
    private Paint mTextPaint;
    private String mText;
    private int mAscent;
    
    /**
     * Constructor.  This version is only needed if you will be instantiating
     * the object manually (not from a layout XML file).
     * @param context
     */
    public LabelView(Context context) {
        super(context);
        initLabelView();
    }

    /**
     * Construct object, initializing with any attributes we understand from a
     * layout file. These attributes are defined in
     * SDK/assets/res/any/classes.xml.
     * 
     * @see android.view.View#View(android.content.Context, android.util.AttributeSet)
     */
    public LabelView(Context context, AttributeSet attrs) {
        super(context, attrs);
        initLabelView();

        TypedArray a = context.obtainStyledAttributes(attrs,
                R.styleable.LabelView);

        CharSequence s = a.getString(R.styleable.LabelView_text);
        if (s != null) {
            setText(s.toString());
        }

        // Retrieve the color(s) to be used for this view and apply them.
        // Note, if you only care about supporting a single color, that you
        // can instead call a.getColor() and pass that to setTextColor().
        setTextColor(a.getColor(R.styleable.LabelView_textColor, 0xFF000000));

        int textSize = a.getDimensionPixelOffset(R.styleable.LabelView_textSize, 0);
        if (textSize > 0) {
            setTextSize(textSize);
        }

        a.recycle();
    }

    private final void initLabelView() {
        mTextPaint = new Paint();
        mTextPaint.setAntiAlias(true);
        // Must manually scale the desired text size to match screen density
        mTextPaint.setTextSize(16 * getResources().getDisplayMetrics().density);
        mTextPaint.setColor(0xFF000000);
        setPadding(3, 3, 3, 3);
    }

    /**
     * Sets the text to display in this label
     * @param text The text to display. This will be drawn as one line.
     */
    public void setText(String text) {
        mText = text;
        requestLayout();
        invalidate();
    }

    /**
     * Sets the text size for this label
     * @param size Font size
     */
    public void setTextSize(int size) {
        // This text size has been pre-scaled by the getDimensionPixelOffset method
        mTextPaint.setTextSize(size);
        requestLayout();
        invalidate();
    }

    /**
     * Sets the text color for this label.
     * @param color ARGB value for the text
     */
    public void setTextColor(int color) {
        mTextPaint.setColor(color);
        invalidate();
    }

    /**
     * @see android.view.View#measure(int, int)
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(measureWidth(widthMeasureSpec),
                measureHeight(heightMeasureSpec));
    }

    /**
     * Determines the width of this view
     * @param measureSpec A measureSpec packed into an int
     * @return The width of the view, honoring constraints from measureSpec
     */
    private int measureWidth(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text
            result = (int) mTextPaint.measureText(mText) + getPaddingLeft()
                    + getPaddingRight();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }

        return result;
    }

    /**
     * Determines the height of this view
     * @param measureSpec A measureSpec packed into an int
     * @return The height of the view, honoring constraints from measureSpec
     */
    private int measureHeight(int measureSpec) {
        int result = 0;
        int specMode = MeasureSpec.getMode(measureSpec);
        int specSize = MeasureSpec.getSize(measureSpec);

        mAscent = (int) mTextPaint.ascent();
        if (specMode == MeasureSpec.EXACTLY) {
            // We were told how big to be
            result = specSize;
        } else {
            // Measure the text (beware: ascent is a negative number)
            result = (int) (-mAscent + mTextPaint.descent()) + getPaddingTop()
                    + getPaddingBottom();
            if (specMode == MeasureSpec.AT_MOST) {
                // Respect AT_MOST value if that was what is called for by measureSpec
                result = Math.min(result, specSize);
            }
        }
        return result;
    }

    /**
     * Render the text
     * 
     * @see android.view.View#onDraw(android.graphics.Canvas)
     */
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawText(mText, getPaddingLeft(), getPaddingTop() - mAscent, mTextPaint);
    }
}


然后在其基础上扩展,今天写的这个,关于写的一个自定义控件。

在进入商品详细画面后,会呈现出这个商品的相关颜色,尺码属性。最近公司闲的蛋疼,叫加上这个功能,加了也一直放着不知道肿么?,于是这几天就弄了下,虽说是个自定义控件但感觉高级不了哪里去,但也是辛勤劳动成果。贴上来,或许某些情况下还用的着。并不是100%原创,在customLinearlayout也参考过别人的代码(http://blog.csdn.net/long704480904/article/details/9011115)、所谓不重复造*嘛,就看你怎么发挥了。参考也说的理直气壮,嘿嘿,自我嘲讽一下。

先说下图片中的Button(extends View )


package com.example.androidcustomwidget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.Style;
import android.graphics.Path;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;

/**
 * 
 * 自定义控件
 */
public class MyButton extends View {

	/**
	 * 画笔,包含了画几何图形、文本等的样式和颜色信息
	 */
	private Paint mPaint;
	/**
	 * 控件文本
	 */
	private String _text = "二零一三年";
	/**
	 * 字体颜色
	 */
	private int textColor = Color.BLACK;
	/**
	 * 字体大小
	 */
	private float textSize = 30;// 在MEIZU MX2上必须要设置这个值才行 一般手机上只要20就够大了。。。。。
	/**
	 * 存储当前按下状态
	 */
	private boolean _isPress = false;
	/**
	 * 存储当前选中状态
	 */
	private boolean _isChecked = false;

	/**
	 * 控件的id 该自定义控件的事件处理已经在onTouchEvent里面处理,再调用回调,可以不要id属性
	 */
	private int m_id;

	/**
	 * 选中状态改变后,触发回调
	 */
	private ChangedCheckCallBackAttri mCallback;
	private int _mAscent;

	private int mWidth = 0;
	private int mHeight = 0;

	public int getmWidth() {
		return mWidth;
	}

	public void setmWidth(int mWidth) {
		this.mWidth = mWidth;
	}

	public int getmHeight() {
		return mHeight;
	}

	public void setmHeight(int mHeight) {
		this.mHeight = mHeight;
	}

	public MyButton(Context context, String name) {
		super(context);

		mPaint = new Paint();
		setPadding(10, 5, 10, 5);
		mPaint.setColor(textColor);
		mPaint.setTextSize(textSize);
		mPaint.setAntiAlias(true);
		mPaint.setDither(true);
		this.setText(name);
		// mPaint.setTypeface(Typeface.DEFAULT_BOLD) ;//设置字体
	}

	public MyButton(Context context, AttributeSet attrs) {
		super(context, attrs);

		mPaint = new Paint();
		mPaint.setAntiAlias(true);// 抗锯齿
		mPaint.setDither(true);// 图像抖动处理
		setPadding(10, 5, 10, 5);

		// TypedArray是一个用来存放由context.obtainStyledAttributes获得的属性的数组
		// 在使用完成后,一定要调用recycle方法
		// 属性的名称是styleable中的名称+“_”+属性名称
		TypedArray array = context.obtainStyledAttributes(attrs,
				R.styleable.MyButton);
		// String strText = array.getText(R.styleable.jwradiobtn_text, "");
		CharSequence text = array.getText(R.styleable.MyButton_android_text);
		if (text != null)
			_text = text.toString();

		textColor = array.getColor(R.styleable.MyButton_textColor, Color.BLACK); // 提供默认值,放置未指定
		textSize = array.getDimension(R.styleable.MyButton_textSize, 20);
		mPaint.setColor(textColor);
		mPaint.setTextSize(textSize);

		array.recycle(); // 一定要调用,否则这次的设定会对下次的使用造成影响
	}

	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);

		if (_text != null && !_text.equals("")) {
			mPaint.setTextSize(textSize);
			mPaint.setColor(textColor);
			mPaint.setTextAlign(Align.CENTER);// 文字居中显示
			mPaint.setStrokeWidth(0);
			FontMetrics fontMetrics = mPaint.getFontMetrics();
			float fontHeight = fontMetrics.bottom - fontMetrics.top;// 文本高度
			float baseY = this.getHeight() - (this.getHeight() - fontHeight)
					/ 2 - fontMetrics.bottom;
			canvas.drawText(_text, this.getWidth() / 2, baseY, mPaint);// (this.getHeight()
																		// -
																		// fontHeight)/
																		// 2
																		// __额外
			// 设置了mPaint.setTextAlign(Align.CENTER);//文字居中显示
			// 所以canvas.drawText(text,x,y,paint);中,x,为横坐标中点位置
		}

		if (_isPress) {
			// 按下时边框绘制橘黄色
			mPaint.setColor(Color.rgb(255, 165, 0));
			mPaint.setStyle(Style.STROKE); // 设置填充
			mPaint.setStrokeWidth(5);
			canvas.drawRect(1, 1, this.getWidth() - 1, this.getHeight() - 1,
					mPaint); // 绘制矩形
			return;
		}

		if (_isChecked) {
			// 选中时边框绘制红色
			// Canvas中含有很多画图的接口,利用这些接口,我们可以画出我们想要的图形
			// mPaint = new Paint();
			mPaint.setColor(Color.RED);
			mPaint.setStyle(Style.STROKE); // 设置填充
			mPaint.setStrokeWidth(5);
			canvas.drawRect(1, 1, this.getWidth() - 1, this.getHeight() - 1,
					mPaint); // 绘制矩形

			// 绘制右下角的三角形
			mPaint.setStyle(Style.FILL);
			Path path = new Path();
			path.moveTo(this.getWidth(), this.getHeight());
			path.lineTo(this.getWidth(), this.getHeight() - 15);
			path.lineTo(this.getWidth() - 15, this.getHeight());
			canvas.drawPath(path, mPaint);
		} else {
			// 选中时边框绘制黑色
			mPaint.setColor(Color.BLACK);
			mPaint.setStyle(Style.STROKE); // 设置填充
			mPaint.setStrokeWidth(1);
			canvas.drawRect(0, 0, this.getWidth(), this.getHeight(), mPaint); // 绘制矩形
		}
	}

	@Override
	public boolean dispatchTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		// if (event.getAction() == MotionEvent.ACTION_DOWN)
		// return true;

		return super.dispatchTouchEvent(event);
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		Log.e("JWRadioBtn", "JWRadioBtn_onTouchEvent:" + event.getAction());
		switch (event.getAction()) {

		case MotionEvent.ACTION_DOWN:
			_isPress = true;
			this.invalidate();// 重绘,执行onDraw
			return true;// 要返回true,后面的action_up和move才能执行

		case MotionEvent.ACTION_UP:

			if (mCallback != null) {

				mCallback.ChangedCheck(this);
			}
			_isPress = false;
			setChecked(!_isChecked);
			break;

		case MotionEvent.ACTION_MOVE:
			break;

		default:
			_isPress = false;
			this.invalidate();// 重绘,执行onDraw
			break;
		}
		return super.onTouchEvent(event);
	}

	/**
	 * @see android.view.View#measure(int, int)
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// setMeasuredDimension(measureWidth(widthMeasureSpec),
		// measureHeight(heightMeasureSpec));

		setMeasuredDimension(resolveSize(mWidth, widthMeasureSpec),
				resolveSize(mHeight, widthMeasureSpec));
	}

	/**
	 * Determines the width of this view
	 * 
	 * @param measureSpec
	 *            A measureSpec packed into an int
	 * @return The width of the view, honoring constraints from measureSpec
	 */
	private int measureWidth(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		if (specMode == MeasureSpec.EXACTLY) {
			// We were told how big to be
			result = specSize;
		} else {
			// Measure the text
			result = (int) mPaint.measureText(_text) + getPaddingLeft()
					+ getPaddingRight();
			if (specMode == MeasureSpec.AT_MOST) {
				// Respect AT_MOST value if that was what is called for by
				// measureSpec
				result = Math.min(result, specSize);
			}
		}

		return result;
	}

	/**
	 * Determines the height of this view
	 * 
	 * @param measureSpec
	 *            A measureSpec packed into an int
	 * @return The height of the view, honoring constraints from measureSpec
	 */
	private int measureHeight(int measureSpec) {
		int result = 0;
		int specMode = MeasureSpec.getMode(measureSpec);
		int specSize = MeasureSpec.getSize(measureSpec);

		_mAscent = (int) mPaint.ascent();
		if (specMode == MeasureSpec.EXACTLY) {
			// We were told how big to be
			result = specSize;
		} else {
			// Measure the text (beware: ascent is a negative number)
			result = (int) (-_mAscent + mPaint.descent()) + getPaddingTop()
					+ getPaddingBottom();
			if (specMode == MeasureSpec.AT_MOST) {
				// Respect AT_MOST value if that was what is called for by
				// measureSpec
				result = Math.min(result, specSize);
			}
		}

		return result;
	}

	public void setChecked(boolean value) {
		_isChecked = value;
		this.invalidate();

		// if (mCallback != null)
		// mCallback.ChangedCheck();
	}

	/**
	 * 
	 * @return 控件状态 true:选中 false :未被选中
	 */
	public boolean getChecked() {
		return _isChecked;
	}

	public void setText(String value) {
		_text = value;
		this.invalidate();
	}

	public String getText() {
		return _text;
	}

	public void setTextColor(int value) {
		textColor = value;
		this.invalidate();
	}

	public int getTextColor() {
		return textColor;
	}

	public void setTextSize(float value) {
		textSize = value;
		this.invalidate();
	}

	public float getTextSize() {
		return textSize;
	}

	public void setId(int id) {

		this.m_id = id;
	}

	public int getId() {

		return this.m_id;
	}

	/**
	 * 获取控件宽度
	 * 
	 * @return 文本总宽度 + padding消耗值
	 */
	public int getRealWidth() {
		if (this.getWidth() == 0) {
			Rect rect = new Rect();
			mPaint.getTextBounds(_text, 0, _text.length(), rect);

			return rect.width() + this.getPaddingLeft()
					+ this.getPaddingRight();
		} else {
			return this.getWidth();
		}
	}

	/**
	 * 获取控件高度
	 * 
	 * @return 文本高度+ pading消耗值
	 */
	public int getRealHeight() {
		if (this.getHeight() == 0) {
			Rect rect = new Rect();
			mPaint.getTextBounds(_text, 0, _text.length(), rect);

			return rect.height() + this.getPaddingTop()
					+ this.getPaddingBottom();
		} else {
			return this.getHeight();
		}
	}

	/**
	 * 接口用于回调
	 */
	public interface ChangedCheckCallBackAttri {
		void ChangedCheck(MyButton attributeBtn);
	}

	public void setCallback(ChangedCheckCallBackAttri callBack) {
		this.mCallback = callBack;
	}

}



主要的几个方法:public void onDraw(Canvas canvas)、public boolean onTouchEvent(MotionEvent event)、protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

	/**
	 * 接口用于回调
	 */
	public interface ChangedCheckCallBackAttri {
		void ChangedCheck(MyButton attributeBtn);
	}

	public void setCallback(ChangedCheckCallBackAttri callBack) {
		this.mCallback = callBack;
	}

回调接口主要用于在view被选中的时候,处理一些相关操作,比如我在AttributeMyWidget中的操作:

attriBtn.setCallback(new ChangedCheckCallBackAttri() {

				@Override
				public void ChangedCheck(MyButton attributeBtn) {

					if (attributeBtn.getTag() == null) {
						return;
					}
					int index = Integer.valueOf(attributeBtn.getTag()
							.toString());
					if (index != selectedIndex) {

						MyButton btn = radioBtnList.get(selectedIndex);
						btn.setChecked(false);

						selectedIndex = index;

					}

					Toast.makeText(context,
							"你点击了" + attriDetailList.get(index).get("name"),
							Toast.LENGTH_SHORT).show();
					// String attId = getAttriDetail();
					// if (attId.equals("")) {
					// return;
					// }
					//
					// // 重选属性时,回调,更新库存,价格数据显示
					// AttributeMyWidget.this.modifyedListener.modifyed(attId,
					// flag);
				}
			});

因为是动态添加View所以在添加的同时给每个View给了tag,在回调时候就派上用场了,这里我根据tag获得他的index进而做更多操作。

还有个问题:

	/**
	 * @see android.view.View#measure(int, int)
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// setMeasuredDimension(measureWidth(widthMeasureSpec),
		// measureHeight(heightMeasureSpec));

		setMeasuredDimension(resolveSize(mWidth, widthMeasureSpec),
				resolveSize(mHeight, widthMeasureSpec));
	}
这里mWidth,mHeight是我固定设定的固定宽高。在创建
public AttributeMyWidget(Context context, int childViewWidth,
			int childViewHeight) {

的时候设定。也可以根据内容来决定其宽高。

说到这里:几者之间关系:MyButton + CustomLinearLayout------>AttributeMyWidget ------>in Activity中new 


接下来是CustomLinearLayout


package com.example.androidcustomwidget;

import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.widget.LinearLayout;

/**
 * 
 * 实现自动换行
 * 
 */
public class CustomLinearLayout extends LinearLayout {

	private Context mContext;

	public CustomLinearLayout(Context context) {
		super(context);
		mContext = context;
	}

	public CustomLinearLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		mContext = context;
	}

	/** 控件总行数 **/
	private int num = 1;
	/** 按钮总行数 **/
	private int columns = 0;

	/** 设置子view的宽度外部设定,需要根据子view的宽度布局换行时会用 **/
	private int mCellWidth = 0;
	/** 设置子view的高度 **/
	private int mCellHeight = 0;
	/** //layout总宽度 **/
	int layoutTotalWidth = 0;

	public int getLayoutTotalWidth() {
		return layoutTotalWidth;
	}

	public void setLayoutTotalWidth(int layoutTotalWidth) {
		this.layoutTotalWidth = layoutTotalWidth;
	}

	public int getmCellWidth() {
		return mCellWidth;
	}

	public void setmCellWidth(int mCellWidth) {
		this.mCellWidth = mCellWidth;
	}

	public int getmCellHeight() {
		return mCellHeight;
	}

	public void setmCellHeight(int mCellHeight) {
		this.mCellHeight = mCellHeight;
	}

	/**
	 * 根据LinearLayout总宽度自动匹配布局
	 */
	public void autoLayout() {

		int cellWidth = 0;// 子空间宽
		int cellHeight = 0;// 子空间高
		int totalWidth = 0;// 每一行总宽度

		int x = 0;
		int y = 0;

		int count = getChildCount();// 5
		for (int j = 0; j < count; j++) {

			View childView = getChildAt(j);// [35,70]
			// 获取子控件Child的宽高[38,31]
			cellWidth = ((MyButton) childView).getRealWidth();
			cellHeight = ((MyButton) childView).getRealHeight();

			// +5 保持+5间距
			int left = x + 5;
			int top = y;
			// childView.layout(x, y, x + cellWidth, y + cellHeight);
			// 布局子控件0
			childView.layout(left, top, left + cellWidth, top + cellHeight);
			x = left + 5;

			if (totalWidth > this.getLayoutTotalWidth()) {
				// 换行
				x = 0;
				totalWidth = 0;
				y += cellHeight + 5;
				num++;
			} else {
				x += cellWidth;
				totalWidth += x;
			}
		}
	}

	/**
	 * 根据子view宽度布局
	 */
	public void byChildWidthLayout(boolean changed, int l, int t, int r, int b) {

		int cellWidth = mCellWidth;
		int cellHeight = mCellHeight;
		columns = (r - l) / cellWidth;
		if (columns < 0) {
			columns = 1;
		}
		int x = 0;
		int y = 0;
		int i = 0;
		int count = getChildCount();
		for (int j = 0; j < count; j++) {
			View childView = getChildAt(j);
			// 获取子控件Child的宽高
			int w = ((MyButton) childView).getmWidth();
			int h = ((MyButton) childView).getmHeight();
			// 计算子控件的顶点坐标
			int left = x + 5;
			int top = y;
			// 布局子控件0
			childView.layout(left, top, left + w, top + h);
			x = left + 5;

			if (i >= (columns - 1)) {
				i = 0;
				x = 0;
				y += cellHeight + 5;
				num++;
			} else {
				i++;
				x += cellWidth;

			}
		}
	}

	/**
	 * 自动换行模式下
	 * 
	 * @param widthMeasureSpec
	 * @param heightMeasureSpec
	 */
	public void onMeasureByChildContent(int widthMeasureSpec,
			int heightMeasureSpec) {

		int count = getChildCount();
		int layoutWidth = 0;
		int childHeight = 0; // 子view的高
		int a = this.getLayoutParams().width;
		int b = this.getLayoutParams().height;
		// Log.e("customlayout 随内容...", "getLayoutParams宽度"+a
		// +"**********************" + "getLayoutParams高度"+ b ) ;
		// 设置子空间Child的宽高
		for (int i = 0; i < count; i++) {
			View childView = getChildAt(i);

			layoutWidth += ((MyButton) childView).getRealWidth();
			childHeight = ((MyButton) childView).getHeight();
		}
		// 设置容器控件所占区域大小

		setMeasuredDimension(resolveSize(layoutWidth, widthMeasureSpec),
				resolveSize(num * childHeight, heightMeasureSpec));

		// layoutTotalWidth = this.getWidth() ;
		Log.e("总宽度", "************************" + layoutTotalWidth);

	}

	/**
	 * 
	 * 子view宽度来
	 * 
	 * @param widthMeasureSpec
	 * @param heightMeasureSpec
	 */
	public void onMeasureByChildWidth(int widthMeasureSpec,
			int heightMeasureSpec) {

		// 创建测量参数
		int cellWidthSpec = MeasureSpec.makeMeasureSpec(mCellWidth,
				MeasureSpec.EXACTLY);
		int cellHeightSpec = MeasureSpec.makeMeasureSpec(mCellHeight,
				MeasureSpec.EXACTLY);
		int count = getChildCount();
		// 设置子空间Child的宽高
		for (int i = 0; i < count; i++) {
			View childView = getChildAt(i);

			childView.measure(cellWidthSpec, cellHeightSpec);
		}
		// 设置容器控件所占区域大小
		setMeasuredDimension(
				resolveSize(mCellWidth * columns + 5, widthMeasureSpec),
				resolveSize(mCellHeight * num + 10, heightMeasureSpec));

	}

	/**
	 * 控制子控件的换行
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		byChildWidthLayout(changed, l, t, r, b);
		// autoLayout();
	}

	/**
	 * 计算控件及子控件所占区域
	 */
	@Override
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
		// onMeasureByChildContent(widthMeasureSpec, heightMeasureSpec);

		onMeasureByChildWidth(widthMeasureSpec, heightMeasureSpec);
	}

}



AttributeMyWidget的布局:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#E8E8E8"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/attriname"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:ellipsize="end"
        android:gravity="left|center_vertical"
        android:paddingLeft="5dp"
        android:singleLine="true"
        android:text=""
        android:textColor="#CD2626"
        android:textSize="20sp"
        android:textStyle="bold" />

    <View
        android:layout_width="match_parent"
        android:layout_height="1dp"
        android:background="#B0B0B0" />

    <com.example.androidcustomwidget.CustomLinearLayout
        android:id="@+id/attri_radiogrouplayout"
        android:layout_width="800dp"
        android:layout_height="wrap_content" >
    </com.example.androidcustomwidget.CustomLinearLayout>

</LinearLayout>


最后是MainActivity

package com.example.androidcustomwidget;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;
import android.widget.LinearLayout;

public class MainActivity extends Activity {

	AttributeMyWidget attributeMyWidget;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		LinearLayout layout = (LinearLayout) findViewById(R.id.layout);

		// 魅族Mx2手机分辨率比较大因此,这里我设置了[120,80]的大小,通常情况下的话[70,35就差不多了]
		attributeMyWidget = new AttributeMyWidget(this, 120, 80);
		// attributeMyWidget = new AttributeMyWidget(this,800) ;
		attributeMyWidget.loadAttriData();
		attributeMyWidget.setName("颜色属性");
		layout.addView(attributeMyWidget);

	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

}

源码下载:http://download.csdn.net/detail/xxm282828/6856641


自定义控件(商品属性选择)

上一篇:[开心IT字符串] 反转字符串


下一篇:合并两个排序的链表