Android 自定义View(一)

43 阅读3分钟

                   精确值模式,当我们将控件的layout_width属性或者layout_height属性指定为具体数值时,或者为match_parent属性时,系统使用的是EXACTLY模式。

         (2)AT_MOST


The child can be as large as it wants up to the specified size.

                   最大值模式,当控件的layout_width属性或者layout_height属性为wrap_content时,控件大小一般随着控件的子控件或内容的变化而变化,此时控件的尺寸大小只要不超过父控件允许的最大尺寸即可。

         (3)UNSPECTIFIED


The parent has not imposed any constraint on the child. It can be whatever size it wants.

                    它不指定测量模式,View想多大就多大,一般用作Android系统内部,或者ListView和ScrollView等滑动控件。

             注意:

       View类默认的onMeasure()方法只支持EXACTLY模式,所以如果在自定义控件的时候不重写onMeasure()方法的话,就只能使用EXACTLY模式。而如果要让自定义View支持wrap_content属性,那么必须重写onMeasure()方法来指定wrap_content时的大小,否则它会默认填充整个父布局,重写onMeasure()方法的目的,就是为了能给View一个wrap_content属性下的默认大小。

    1.2 View的绘制

           当测量好以后,我们就可以简单地重写onDraw()方法,并在Canvas对象上来绘制所需要的图形。要想在Android的界面中绘制相应的图像,就必须在Canvas上进行绘制。Canvas就好比是一块画布,使用Paint(相当于画笔)就可以在上面作画了,通常需要继承View并重写它的onDraw()方法来完成绘图。

          onDraw()方法中有一个参数,就是Canvas canvas对象。使用这个对象,就可以进行绘制了。而在其他地方,通常需要使用代码来创建一个Canvas对象。代码如下:

          Canvas canvas=new Canvas(bitmap);

          传进去的bitmap对象的过程称之为装载画布。传进去的bitmap与创建的canvas对象紧紧的联系在一起,bitmap存储所有绘制在canvas上的像素信息,通过canvas.drwaXXX方法,可以进行一系列的绘图操作。

         下面通过代码来实践一下吧。

         布局文件activity_main.xml


<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:orientation="vertical"

    tools:context="com.example.myview.MainActivity" >



    <com.example.myview.MyCustomView

        android:id="@+id/my_view"

        android:layout_width="wrap_content"

        android:layout_height="wrap_content" />



</LinearLayout>

        MyCustomView.java


package com.example.myview;



import android.content.Context;

import android.graphics.Canvas;

import android.graphics.Color;

import android.graphics.Paint;

import android.os.Message;

import android.util.AttributeSet;

import android.util.DisplayMetrics;

import android.view.Display;

import android.view.View;

import android.view.WindowManager;



public class MyCustomView extends View implements Runnable{

	private Paint mPaint;

	private Context mContext;// 上下文环境引用

	private int radiu;



	public MyCustomView(Context context) {

		super(context);

		// TODO 自动生成的构造函数存根

	}



	public MyCustomView(Context context, AttributeSet attributeSet) {

		super(context, attributeSet);

		mContext = context;

		// 初始化画笔

		initPaint();

	}



	/**

	 * 初始化画笔

	 */

	private void initPaint() {

		// TODO 自动生成的方法存根

		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);

		mPaint.setAntiAlias(true);// 抗锯齿效果

		mPaint.setStyle(Paint.Style.STROKE);

		mPaint.setColor(Color.CYAN);

		mPaint.setStrokeWidth(5);

	}



	@Override

	protected void onDraw(Canvas canvas) {

		// TODO 自动生成的方法存根

		super.onDraw(canvas);

		canvas.drawCircle(MeasureUtil.getScreenWidth(mContext)/2,

				MeasureUtil.getScreenHeight(mContext)/2, radiu, mPaint);



	}



	@Override

	public void run() {

		// TODO 自动生成的方法存根

		while (true) {

			if (radiu <=200) {

				radiu += 10;

				//刷新View

				postInvalidate();

              

			} else {

				radiu = 0;

			}

			try {

				Thread.sleep(200);

			} catch (InterruptedException e) {

				// TODO 自动生成的 catch 块

				e.printStackTrace();

			}

		}

	}

}



其中上面的是第28行,有一个initPaint()方法,其在初始化构造的方法里,我们去初始化画笔,尽量不要在onDraw()方法里去初始化画笔,因为我们的图,不只一次会调用到OnDraw()方法,这样就会重复的去初始化对象,耗内存和时间。

onDraw()方法中,只画了一个圆,圆的半径使用的是屏幕的宽度的一半。当然2D画图有丰富的API,可以绘制出更丰富的图,通过这个圆,我们可以类似的做一个下载进度条的功能。

MeasureUtil.java


package com.example.myview;



import android.content.Context;

import android.view.Window;

import android.view.WindowManager;



public class MeasureUtil {

	public static int getScreenWidth(Context mContext) {

		int width = mContext.getResources().getDisplayMetrics().widthPixels;

		return width;

	}

	public static int getScreenHeight(Context mContext) {

		int height = mContext.getResources().getDisplayMetrics().heightPixels;

		return height;

	}

	

}



MainActivity.java


public class MainActivity extends Activity implements OnClickListener {

	private MyCustomView myCustomView;

	@Override

	protected void onCreate(Bundle savedInstanceState) {

		super.onCreate(savedInstanceState);

		setContentView(R.layout.activity_main);

		myCustomView = (MyCustomView) findViewById(R.id.my_view);	

		new Thread(myCustomView).start();



	}

}



后面还有3篇文章,会对3种自定义控件方法进行实践。