android 自定义view

来源:互联网 发布:淘宝黑搜原理 编辑:程序博客网 时间:2024/06/03 23:50
在继承View类时,需要重写两个方法,分别是onMeasure和onLayout。
1,在方法onMeasure中调用setMeasuredDimension方法

void android.view.View.setMeasuredDimension(int measuredWidth, int measuredHeight)

public class MyTestView extends View {private Bitmap backGround;private Context mContext;public MyTestView(Context context) {super(context);init(context);// TODO Auto-generated constructor stub}public MyTestView(Context context, AttributeSet attrs) {super(context, attrs);init(context);// TODO Auto-generated constructor stub}public MyTestView(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);init(context);// TODO Auto-generated constructor stub}private void init(Context mContext){mContext = mContext;backGround = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.jiaoyu);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {System.out.println("widthMeasureSpec"+widthMeasureSpec+"    heightMeasureSpec"+heightMeasureSpec);setMeasuredDimension(measureWidth(widthMeasureSpec), measureHeight(heightMeasureSpec));}private int measureWidth(int widthMeasureSpec) {int result = 0;int model = MeasureSpec.getMode(widthMeasureSpec);int size = MeasureSpec.getSize(widthMeasureSpec);if (model == MeasureSpec.EXACTLY) {result = size;} else {if (backGround != null) {result = backGround.getWidth() + getPaddingLeft()+ getPaddingRight();}if (model == MeasureSpec.AT_MOST) {result = Math.min(result, size);}}return result;}private int measureHeight(int heightMeasureSpec){int result = 0;int model = MeasureSpec.getMode(heightMeasureSpec);int size = MeasureSpec.getSize(heightMeasureSpec);if (model == MeasureSpec.EXACTLY) {result = size;} else {if (backGround != null) {result = backGround.getHeight() + getPaddingTop()+ getPaddingBottom();}if (model == MeasureSpec.AT_MOST) {result = Math.min(result, size);}}return result;}@Overrideprotected void onLayout(boolean changed, int left, int top, int right,int bottom) {// TODO Auto-generated method stubsuper.onLayout(changed, left, top, right, bottom);}protected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);this.setBackgroundResource(R.color.red);canvas.save();canvas.translate(15, 0);canvas.drawBitmap(backGround, 0, 0, new Paint());canvas.restore();}}

解析View.MeasureSpec类

android.view.View.MeasureSpec

MeasureSpec对象,封装了layout规格说明,并且从父view传递给子view。每个MeasureSpec对象代表了width或height的规格。

MeasureSpec对象包含一个size和一个mode,其中mode可以取以下三个数值之一:

    UNSPECIFIED,1073741824 [0x40000000],未加规定的,表示没有给子view添加任何规定。
    EXACTLY,0 [0x0],精确的,表示父view为子view确定精确的尺寸。

    AT_MOST,-2147483648 [0x80000000],子view可以在指定的尺寸内尽量大。


view在测量显示的时候是受到父View的限制的,如果父View的宽高设置为wrap_content,那么就对子View的显示没有什么限制,可以让子View按照最大的尺寸显示,如果父View的尺寸限定了,那么子View的显示的大小一定不会超过父view,如果超过的话会被截掉。

MeasureSpec,是从父view传给子View的,所以MeasureSpec中规定了子View显示的最大区域。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    android:layout_width="wrap_content"        android:layout_height="wrap_content" >    <com.fy.communityapp.view.MyTestView        android:layout_width="fill_parent"        android:layout_centerInParent="true"        android:layout_height="fill_parent"        android:paddingLeft="10dp"        android:visibility="gone"        android:paddingRight="20dp"        >       </com.fy.communityapp.view.MyTestView></RelativeLayout>

如果我们给RelativeLayout设定宽高为 match-parent或者wrap_content,那么MyTestView的宽显示的最大区域都为整个屏幕的宽度(高度同理),如过 宽度设定为一个固定的值的话,那么子View       MyTestView   显示的最大宽度也为这个值。

int model = MeasureSpec.getMode(heightMeasureSpec);
int size = MeasureSpec.getSize(heightMeasureSpec);
而我们在计算的时候 这个size就是RelativeLayout测量出的MyTestView显示的最大宽度,这个最大宽度是不会超过父View的宽度的


例如:
if (model == MeasureSpec.EXACTLY) {result = size;} else {if (backGround != null) {result = backGround.getHeight() + getPaddingTop()+ getPaddingBottom();}if (model == MeasureSpec.AT_MOST) {result = Math.min(result, size);}}
如果你给MyTestView设定的固定的值比父view设定的固定的值要大,那么MyTestView最多显示父View宽度的空间,如果设定的固定的值比父view设定的固定的值要小,那么显示的是MyTestView设定的值。
如果 MyTestView设定的宽为match-parent的话,那么显示的也是屏幕的宽度,如果设定的是wrap_content,那么MyTestView所能显示的最大宽度为屏幕宽,但是显示的是MyTestView的所能显示的宽度就是以下计算结果
if (backGround != null) {result = backGround.getHeight() + getPaddingTop()+ getPaddingBottom();}if (model == MeasureSpec.AT_MOST) {result = Math.min(result, size);}

得到的值,肯定是比size要小的。

那么这个MyTestView的所能显示的宽度,是如何计算的呢?
包括你显示的Text或者图片的宽度+paddingLeft+paddingRight 
就是MyTestView所能显示的宽度了。
2、onDraw()
如果我们自定义的控件中画一个图

如果我们给MyTestView设定了属性Padding的话,就像我们代码中一样,paddingleft是10,paddingRight是20,那么我们如果直接用
protected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);this.setBackgroundResource(R.color.red);canvas.drawBitmap(backGround, 0, 0, new Paint());}
那么显示的时候宽度虽然算上paddingleft和paddingRight了但是,图像是在画的时候,是在最左边画起的如图


右边红色的宽度就是paddingLeft+paddingRight

如果想要我们的左填充起到应有的效果的话,那么我们就移动canvas   15是10dp转换后的px值
protected void onDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.onDraw(canvas);this.setBackgroundResource(R.color.red);canvas.save();canvas.translate(15, 0);canvas.drawBitmap(backGround, 0, 0, new Paint());canvas.restore();}
这样就得到我们想要的结果了,左边padding10dp,右边padding20dp

参考:自定义ViewGroup    http://blog.csdn.net/loongggdroid/article/details/17515113


0 0
原创粉丝点击