自定义View

先创建一个自定义MyView1,继承View,实现构造方法。

public class MyView1 extends View{
private Bitmap bitmap;
	public MyView1(Context context, AttributeSet attrs) {
		super(context, attrs);
		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		// TODO Auto-generated constructor stub
	}

	public MyView1(Context context) {
		super(context);
		bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		Paint paint=new Paint();//按Java的理解,可以理解为画笔
		paint.setTextSize(30);//设置画笔大小
		canvas.drawText("Hello", 20, 20, paint);//绘制文字
		//canvas.drawRect(20, 50, 60, 100, paint);//绘制矩形方法一
		RectF rect = new RectF(20, 50, 60, 100);//绘制矩形方法二
		//canvas.drawRect(rect, paint);//根据需求选方法
		canvas.drawRoundRect(rect, 15, 15, paint);//绘制圆角矩形
		canvas.drawCircle(50, 150, 50, paint);//绘制圆形
		canvas.drawBitmap(bitmap, 0, 200, paint);//绘制图片,注意要在构造方法中创建bitmap
	}
}

使用View可以用代码直接加载也可以通过XMl布局文件加载,要使用自定义属性,记得添加命名空间
xmlns:nt="http://schemas.android.com/apk/res/com.example.xin.view"

<pre name="code" class="html"><RelativeLayout 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"
    xmlns:nt="http://schemas.android.com/apk/res/com.example.xin.view"
    tools:context="com.example.xin.view.MainActivity" >

    <com.example.xin.view.MyView1 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"/>
    <com.example.xin.view2.MyView2
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"/>
    <com.example.xin.view3.MyView3
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    <com.example.xin.view3.MyView4
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:visibility="gone"/>

</RelativeLayout>


 代码直接加载 

setContentView(new MyView(this));


为View加入逻辑线程,使其实现动态效果

创建第二个MyView2,同样继承View,绘制移动的文字,改变角度的圆,以及大小变化的圆,主要把通过改变参数大小实现,把参数大小改变交给别的线程

MyView2

public class MyView2 extends View{
	private RectF rectF = new RectF(0 ,60 ,100, 160);
	private int s=0,a=0;
	private float rx = 0;
	private Paint paint = new Paint();
	private float sweepAngle = 0;
	private MyThread thread;
	public MyView2(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public MyView2(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		paint.setTextSize(10);
		canvas.drawText("程序猿程序猿", rx, 30, paint);
		canvas.drawArc(rectF, 0, sweepAngle, true, paint);//sweepAngle这个参数表示圆的角度
		canvas.drawCircle(150, 210, s, paint);
		if(thread == null){
			thread = new MyThread();
			thread.start();
		}
	}
	class MyThread extends Thread{
		Random rand = new Random();
		
		@Override
		public void run() {
			
			while(true){
				rx += 3;
				
				if(rx > getWidth()){
					rx = 0 - paint.measureText("LogicView");
				}
				
				sweepAngle ++;
				if(sweepAngle > 360){
					sweepAngle = 0;
				}
				
				if(a==0)
				{
					s++;
					if(s>49)
					{
						a=1;
					}
				}else if(a==1){
					s--;
					if(s<1)
					{
						a=0;
					}
				}
				
				int r = rand.nextInt(256);//RGB的值为0到255
				int g = rand.nextInt(256);
				int b = rand.nextInt(256);
				
				paint.setARGB(255, r, g, b);
				
				postInvalidate();//刷新,会调用<span style="font-family: Arial, Helvetica, sans-serif;">onDraw这个方法</span>
				try {
					Thread.sleep(30);//控制休眠时间
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
}

为了代码简介且重复利用,可以提取封装自己的自定义View

创建一个自定义View作为提取封装好的baseView,便于之后之类间的继承

public abstract class BaseView extends View{
	private boolean running=true;
	private MyThread thread;
	public BaseView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}

	public BaseView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	//提供绘画的抽象方法,之后在继承该自定义View的View中,绘画的功能就在该方法里完成
		protected abstract void huizhi(Canvas canvas);
	//提供编写逻辑的抽象方法,之后在继承该自定义View的View中,所以参数改变的逻辑就直接写入方法里
		protected abstract void luoji();
	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		if(thread==null)
		{
			thread=new MyThread();
			thread.start();
		}else{
			huizhi(canvas);
		}
		
		
	}
	//当我们销毁VIew时,会调用这个方法
		protected void onDetachedFromWindow() {
			running = false;
			super.onDetachedFromWindow();
		}
	class MyThread extends Thread
	{
		@Override
		public void run() {
			// TODO Auto-generated method stub
			while(running)
			{
				luoji();
				postInvalidate();//刷新,会调用onDraw()方法
				
				try {
					Thread.sleep(30);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}
	}
}


为什么要提取封装?若之后程序中还有很多自定义VIew需要编写,就可不管线程代码,直接在新的View中重写抽象的逻辑与绘画方法,可以达到代码的简化以及多重利用的便捷

继承上面封装好自定义baseView的新MyView3


public class MyView3 extends BaseView{

	private Paint paint=new Paint();
	private float rx=0;
	private int a=0,s=0;
	private int sweepAngle=0;
    private RectF rectF = new RectF(0 ,60 ,100, 160);
    Random rand=new Random();//产生随机数对象
	public MyView3(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}
	

	public MyView3(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
	}


	@Override
	//新的View只需要重写绘制方法和逻辑方法
	protected void huizhi(Canvas canvas) {
		// TODO Auto-generated method stub
		
		paint.setTextSize(10);
		canvas.drawText("程序猿程序猿", rx, 30, paint);
		canvas.drawArc(rectF, 0, sweepAngle, true, paint);//sweepAngle这个参数表示圆的角度
		canvas.drawCircle(150, 210, s, paint);
	}

	@Override
	//新的View只需要重写绘制方法逻辑方法
	protected void luoji() {
		//颜色变换逻辑
		int r = rand.nextInt(256);
		int g = rand.nextInt(256);
		int b = rand.nextInt(256);
		paint.setARGB(255, r, g, b);
		//文字逻辑
		rx++;
		if(rx>getWidth())
		{
			rx = - paint.measureText("程序猿程序猿");
		}
		//角度变化圆形逻辑
		sweepAngle++;
		if(sweepAngle>360)
		{
			sweepAngle=0;
		}
		//大小变化的圆形逻辑
		if(a==0)
		{
			s++;
			if(s>49)
			{
				a=1;
			}
		}else if(a==1){
			s--;
			if(s<1)
			{
				a=0;
			}
		}
	}

}
<img src="https://img-blog.csdn.net/20150810185724339?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
在XML定义样式来影响显示效果,分为三步

1.定义属性,将需要在XML改变的属性定义好

2.在values中创建XML文件,定义属性样式

3.解析样式

public class View4 extends BaseView{

	private int mx=0;
	private int lineNum=0;
	private boolean ispao=true;
	private Paint paint=new Paint();
	public View4(Context context, AttributeSet attrs) {
		super(context, attrs);
		//解析样式
		TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.View4);
		lineNum = ta.getInt(R.styleable.Viwe4_lineNum, 1);
		ispao = ta.getBoolean(R.styleable.Viwe4_ispao, false);
		ta.recycle();
		
	}

	public View4(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
	}

	@Override
	
	protected void huizhi(Canvas canvas) {
		// TODO Auto-generated method stub
		for(int i=0;i<lineNum;i++)//lineNum控制输出行数,也作为之后view对应的属性名
		{
			int textSize = 15 + i;
			canvas.drawText("程序猿程序猿", mx, textSize + textSize * i, paint);
		}
		
	}

	@Override
	protected void luoji() {
		// TODO Auto-generated method stub
		if(ispao)//控制移动与否,也作为之后view对应的属性名
		{
		mx++;
		if(mx > getWidth()){
			mx = (int) -paint.measureText("程序猿程序猿");
		}
		}
	}

}

values文件夹的样式文件

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <declare-styleable name="View4">
        <attr name="lineNum" format="integer"/>
        <attr name="ispao" format="boolean" />
    </declare-styleable>
</resources>


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值