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

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

博客地址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


### 回答1: libview是一个自定义控件库,它提供了丰富的自定义控件和视图组件,帮助开发人员快速构建高质量的用户界面。 首先,libview包含了各种常用的自定义控件,如自定义按钮、进度条、开关等。这些控件都具有高度的可定制性,可以根据开发者的需求进行样式、颜色、尺寸等方面的定制。开发者可以根据应用的UI设计需求,使用这些自定义控件来创建独特的用户界面。 其次,libview还提供了一些强大的视图组件,如自定义列表视图、网格视图等。这些视图组件可以帮助开发人员快速展示大量的数据,并支持通过滑动、点击等交互方式进行操作。通过使用这些视图组件,开发人员可以方便地实现各种列表展示需求,如商品列表、新闻列表等。 另外,libview还为用户提供了一些高级功能,如动画效果、手势识别等。开发者可以使用这些功能来提升用户体验,给应用界面增加更多交互和动感。例如,可以使用动画效果来实现页面切换的平滑过渡,通过手势识别实现图片放大缩小等功能。 总之,libview作为一个自定义控件库,为开发者提供了丰富的控件和视图组件,帮助他们快速构建独特、高质量的用户界面。无论是简单的控件需求还是复杂的界面交互,libview都能够提供有效的解决方案,为开发者节省时间和精力,快速完成应用的开发。 ### 回答2: libview是一个自定义控件库,它是为了帮助开发者更轻松地创建和定制自己的Android应用程序而设计的。 首先,libview提供了丰富多样的自定义控件,如按钮、文本框、图片视图等,开发者可以根据自己的需求选择合适的控件来构建界面。这些控件都经过优化和改进,以确保在不同设备上都能正常高效地运行,并且能够适应不同的屏幕大小和分辨率。 其次,libview还提供了丰富的控件属性和样式,开发者可以根据自己的喜好和设计需求来自定义控件的外观和行为。例如,可以设置按钮的大小、颜色、边框等属性,或者自定义文本框的输入限制和提示信息。这样可以大大简化开发流程,提高开发效率。 此外,libview还支持控件的交互和动画效果。开发者可以为控件添加点击事件、滑动效果等,以增加用户的交互体验。同时,还可以通过动画效果使界面更加生动和有趣,例如淡入淡出、旋转等动态效果,从而吸引用户的注意力。 总结起来,libview自定义控件库是一个功能强大、易于使用的工具,它能帮助开发者快速构建出美观、交互丰富的Android应用程序。无论是初学者还是经验丰富的开发者,都可以从中受益,并且轻松实现自己的创意和设计。 ### 回答3: libview是一个自定义控件库,可以帮助开发者快速构建各种自定义控件。它提供了多种常用的控件组件,如按钮、文本框、列表等,并且支持用户自定义控件的外观和交互行为。 libview的设计初衷是为了解决开发者在开发过程中频繁重复编写自定义控件的问题。它封装了一系列常用控件的基本功能和样式,开发者只需根据自己的需求进行简单配置和定制,就能够快速生成自己想要的控件。 libview还提供了一系列强大的功能和特性,例如事件监听、动画效果、状态切换等。开发者可以通过这些功能来实现丰富多样的控件交互和视觉效果。 此外,libview还支持控件的扩展和自定义。开发者可以基于已有的控件进行二次开发,以满足特定的需求。同时,libview还提供了丰富的文档和示例代码,方便开发者学习和使用。 总之,libview是一个方便易用的自定义控件库,可以帮助开发者快速构建各种自定义控件,并且提供了丰富的功能和特性,让开发者可以更加灵活地定制和扩展控件的外观和行为。无论是新手还是经验丰富的开发者,都能够轻松地使用libview来提升开发效率和用户体验。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值