画笔以及动画

本文详细介绍Android中视图绘制的基本方法,包括点、线、面等基本元素的绘制技巧,以及文字、图片等复杂元素的处理方式。此外,还深入探讨了动画效果的实现方法,包括平移、旋转、缩放和淡入淡出等基本动画类型及其组合应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

anim
单词:
Point:点
Line:线
Paint :绘画,画笔
Stroke:笔锋
rectangle(矩形)面
argtangel:弧度 canvas.drawArc(oval, 0, 90, true, paint)
RectF:圆外切矩形
平移translate,
缩放scale,
旋转rotate,
倾斜skelton





一、画点
无论通过画布画什么,点,线,面,第一步都是继承我们的view,继承view同时把我们的paint画笔这个类直接通过构造方法实例化
public class MyView extends View {

	Paint paint = null;

	public MyView(Context context) {
		super(context);
		paint = new Paint();
	}

	/**
	 * 画任何是这个方法
	 */
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
	}
}

1、Paint 属性
		paint.setColor(Color.RED);
		// 设置笔锋的宽度
		paint.setStrokeWidth(5.0f);

2、画点
前面二个参数是坐标,后面是画笔
canvas.drawPoint(10.0f, 20.0f, paint);




二、画线
前面二个参数是开始坐标,后面二个参数是结束坐标
canvas.drawLine(10, 10, 50, 50, paint);

1、取屏幕的宽度和高度
这里补充一点,屏幕的状态栏和标题栏在2.2是像素一共是50px
		/**
		 * 通过方法取宽度高度,这里用画布去取屏幕的宽度和高度
		 */
		int width = canvas.getWidth();
		int height = canvas.getHeight();
		canvas.drawLine(0, 0, width, height - 50, paint);






三、画面
		canvas.drawRect(30, 30, 80, 160, paint);



四、画文字
		canvas.drawText("陈奕迅", 100, 100, paint);




五、画弧形

		/**
		 * 画弧形
		 */
		paint.setStrokeWidth(5.0f);
		paint.setColor(Color.RED);
		//全屏抗锯齿,AntiAlias:修正偏移量
		paint.setAntiAlias(true);
		//设置只有笔锋,不填充
		paint.setStyle(Style.STROKE);
		RectF oval = new RectF(50, 50, 150, 150);
		canvas.drawArc(oval, 0, 90, true, paint);









六、画圆形
canvas.drawCircle(200, 200, 40, paint);






七、画三角形
画三角形通过path这个类来实现,了解我们平时画三角形都是从一个点到另外一个点到最后一个点,因此保证点的连续
		/**
		 * 三角形
		 * path:路径
		 * 
		 * 了解moveTo是移动,lineTo绘制其中一条边
		 */
		//这里了解工具path,如果draw完成不了的,我们就使用这个方法
		Path path = new Path();
		//代表把画笔移动到我们起始图形的坐标点
		path.moveTo(100, 50);
		//把起笔坐标和终点坐标连起来
		path.lineTo(50, 180);
		path.lineTo(150, 180);
		path.lineTo(100, 50);
		paint.setAntiAlias(true);
		canvas.drawPath(path, paint);




八、画特效文字
		/**
		 * path:绘制特效文字
		 */
		Path myTextPath = new Path();
		//这里path可以添加我们需要的形状,等会文字就摆放到我们的添加图形的周围
		//最后一个参数文字摆放按顺还是逆dir:diraction
		myTextPath.addCircle(100, 100, 50, Direction.CW);
		canvas.drawTextOnPath("陈奕迅", myTextPath, 0, 10, paint);



九、画图片

		/**
		 * 图片的绘制
		 * Bitmap 
		 */
		BitmapFactory bitmapFactory = new BitmapFactory();
		Bitmap bitmap = bitmapFactory.decodeResource(getResources(), R.drawable.img1);
		canvas.drawBitmap(bitmap, 100, 100, paint);



1、添加图片运动
		/**
		 * 图片在二维平面的操作:平移translate,缩放scale,旋转rotate,倾斜skelton
		 */
		Matrix matrix = new Matrix();
		
		//平移
		matrix.setTranslate(0, 20);
		//旋转
		matrix.setRotate(45);
		//缩放
		matrix.setScale(0.5f, 0.5f);
		
		canvas.drawBitmap(bitmap, matrix, paint);










十、裁切图片
		/**
		 * 裁剪我们的图片
		 * 
		 * bitmap.getwidth:取图片的宽
		 * bitmap.getHeight:取图片高
		 */
		Bitmap bitmap2 = bitmap.createBitmap(bitmap, 0, 0, 30, 30);
		canvas.drawBitmap(bitmap2, 100, 100, paint);









十一、图片的四种特效
这里的图片的四种特效可以用代码实现,也可以通过我们的配置文件中,新建anim的文件夹,然后在这个文件里面添加我们的图片特效
1、translate平移
1、四个参数:开始坐标,结束坐标,以及动画时间
<?xml version="1.0" encoding="utf-8"?>
<translate xmlns:android="http://schemas.android.com/apk/res/android"
    android:fromXDelta="20"
    android:fromYDelta="50"
    android:toXDelta="150"
    android:toYDelta="220"
    android:duration="5000" />

2、AnimationUtils
这里用到AnimationUtils这个类中loadAnimation这个方法,第一个是本Context,第二个是对应的资源文件,当然后面的我们的三种动画同样利用这种方式来加载
	//平移
   private TranslateAnimation ts;
   ts = 
(TranslateAnimation)AnimationUtils.loadAnimation(MyTweenActivity.this, R.anim.mytranslate);
3、startAnimation
iv.startAnimation(animationSequence  );



2、Rotate旋转
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
	android:fromDegrees="0"
	android:toDegrees="180"
    android:duration="5000" />



3、Scale缩放
<?xml version="1.0" encoding="utf-8"?>
<scale xmlns:android="http://schemas.android.com/apk/res/android"
    android:duration="5000"
    android:fromXScale="1"
    android:fromYScale="1"
    android:pivotX="0.5"
    android:pivotY="0.5"
    android:toXScale="2"
    android:toYScale="2" />




4、Alpha淡入淡出
<?xml version="1.0" encoding="utf-8"?>
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
	android:fromAlpha="1.0"
	android:toAlpha="0.3"
   android:duration="5000" />





5、动画组合
<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="5000"
        android:fromXDelta="20"
        android:fromYDelta="50"
        android:toXDelta="150"
        android:toYDelta="220" />

    <alpha
        android:duration="5000"
        android:fromAlpha="1.0"
        android:toAlpha="0.3" />

</set>









6、顺序组合
动画先后播放
 android:startOffset="3001"  了解这个属性,这个当前面的播放完毕后,从前面播放完毕后一秒毫秒开始下一个动画

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android" >

    <translate
        android:duration="3000"
        android:fromXDelta="20"
        android:fromYDelta="50"
        android:toXDelta="80"
        android:toYDelta="120" />

    <alpha
        android:duration="5000"
        android:fromAlpha="1.0"
        android:startOffset="3001"
        android:toAlpha="0.3" />

</set>






十二、图片gif效果
1、按钮监听器图片跑动
设置资源文件对应的动画图片
<?xml version="1.0" encoding="utf-8"?>
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
	android:oneshot="false">
	<item android:drawable="@drawable/tuzi001" android:duration="50" />
	<item android:drawable="@drawable/tuzi002" android:duration="50" />
	<item android:drawable="@drawable/tuzi003" android:duration="50" />
	<item android:drawable="@drawable/tuzi004" android:duration="50" />
	<item android:drawable="@drawable/tuzi005" android:duration="50" />
	<item android:drawable="@drawable/tuzi006" android:duration="50" />
	<item android:drawable="@drawable/tuzi007" android:duration="50" />
	<item android:drawable="@drawable/tuzi008" android:duration="50" />
</animation-list> 
按钮监听器
		bt.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				iv.setBackgroundResource(R.anim.frame_animset_anim);
				AnimationDrawable frameAnimal = (AnimationDrawable) iv.getBackground();
				if(frameAnimal.isRunning()){
					frameAnimal.stop();
				}else{
					frameAnimal.stop();
					frameAnimal.start();
				}
			}
		});





2、直接图片跑动
这里是重点,用到定时器,不过这里定时器不能设置的太久,一般都是很小的一个毫秒数
特别注意:第一种方式,通过计时器,不过这里貌似有问题,只有设置时间为0
public class MainActivity extends Activity {

	private ImageView iv = null;
	private MyFrameTask frameTask;

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

		iv = (ImageView) this.findViewById(R.id.iv);

		Timer timer = new Timer();
		frameTask = new MyFrameTask();
		timer.schedule(frameTask, 20);

	}

	/**
	 * 这里相当于一个线程
	 */
	class MyFrameTask extends TimerTask {
		@Override
		public void run() {
			iv.setBackgroundResource(R.anim.frame_animset_anim);
			AnimationDrawable frameAnimal = (AnimationDrawable) iv.getBackground();
			frameAnimal.start();
		}
	}

}














十三、转动风扇
1、一定记住自动刷新,这样才能完成风扇的转动
下面这个是继承view的类,这里负责画图
public class MyFanView extends View {

	Paint paint = null;
	int n = 0;
	int speed = 5;

	public MyFanView(Context context) {
		super(context);
		paint = new Paint();
	}

	@Override
	protected void onDraw(Canvas canvas) {

		RectF oval = new RectF(0, 0, 230, 240);
		paint.setColor(Color.BLUE);
		canvas.drawArc(oval, n, 60, true, paint);

		paint.setColor(Color.GREEN);
		canvas.drawArc(oval, n + 120, 60, true, paint);

		paint.setColor(Color.RED);
		canvas.drawArc(oval, n + 240, 60, true, paint);

		super.onDraw(canvas);
	}

	public void move() {
		n += speed;
		super.invalidate();// 刷新一次窗口视图
	}

}


2、这个是Activity中的方法,这来注意了这线程是主线程,有点类似我们的cpu的双核来完成这个线程的任务
public class MainActivity extends Activity {
	
	MyFanView fanView = null;
	
	Runnable myRun = new Runnable() {
		@Override
		public void run() {
			fanView.move();
			//通过视图的post方法来开启线程
			fanView.post(myRun);
			System.out.println(Thread.currentThread().getName());
		}
	};
	
	@Override
	protected void onResume() {
		fanView.post(myRun);
		super.onResume();
	}

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		fanView = new MyFanView(getApplicationContext());
		setContentView(fanView);
	}

	@Override
	protected void onDestroy() {
		fanView.removeCallbacks(myRun);
		super.onDestroy();
	}
	
}








 十四、surfaceview
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		
		MySurfaceView surfaceView = new MySurfaceView(this);
		setContentView(surfaceView);
	}


/**
 * SurfaceView动画制作:
 * 1、添加监听器SurfaceHolder  SurfaceHolder:Surface持有者,补做Surface对象产生和销毁的事件。
 * 2、自己制作动画制作的绘制方法
 * 3、使用Thread启动和停止完成在Surface对象上的绘图操作。
 * 4、必须通过Surface启动和销毁的间隔时间控制动画播放速度。
 *
 */

public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback , Runnable{
	
	Context context = null;
	SurfaceHolder surfaceHolder = null;
	
	Canvas canvas = null;
	Paint paint = null;
	 
	boolean isStop = true;
	
	//设置小球起始的坐标
	int startX = 0;

	public MySurfaceView(Context context) {
		super(context);
		this.context = context;
		//SurfaceView和监听器SurfaceHolder.Callback绑定
		surfaceHolder = this.getHolder();
		surfaceHolder.addCallback(this);
		//响应用户在窗口的触摸事件
		setFocusable(true);
		setFocusableInTouchMode(true);
		paint = new Paint();
	}

	/**
	 * Surface对象创建事件
	 */
	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		isStop = true;
		new Thread(this).start();
	}

	/**
	 * Surface切换(Change)事件
	 */
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
	}

	/**
	 * Surface对象实例销毁事件
	 */
	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		isStop = false;
	}

	/**
	 * 实现线程,子线程在surfaceview对象上绘图
	 */
	@Override
	public void run() {
		while(isStop){
			//必须设置每秒25个surfaceview对象绘图
			//1、得到画一个小球需要多长的时间
			long startTime = System.currentTimeMillis();
			synchronized (surfaceHolder) {
				myDraw();
			}
			long endTime = System.currentTimeMillis();
			long diffTime = endTime - startTime;
			
			/**
			 * 理解这里的算法:中间是我们自己写的方法myDraw(),加上同步块,由方法可以确认开始时间和结束时间这样
			 * 
			 * 能确定画一次图的时间,然后通过控制线程的yield()方法,当我们的时间执行的时间的多少就能控制这里的速度,因为每次
			 * 
			 * 画图都是在坐标上控制的
			 */
			while(diffTime <= 40){
				diffTime = (int)(System.currentTimeMillis()-startTime);
				//子线程切换到主线程完成View绘制
				Thread.yield();
			}
			
		}
	}
	
	public void myDraw(){
		/**
		 * 画图,然后由线程调用,这个图必须画到surface上
		 * 
		 * canvas:整个窗口
		 * 
		 * SurfaceHolder获取Surface所代表窗口
		 */
		try {
			canvas = surfaceHolder.lockCanvas();
			//设置surface的背景色,重新绘制surface的背景色,才有了一块画布,才能出来
           //这里的canvas画布就是surfaceview
			canvas.drawColor(Color.WHITE);
			paint.setColor(Color.BLACK);
			
			//每次向右移动10个像素
			startX= startX+10;
			
			if(canvas != null){
				//surface对象已经实例化
				canvas.drawCircle(startX, 120, 10, paint);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			surfaceHolder.unlockCanvasAndPost(canvas);
		}
	}

}



雷电飞机背景
public class AnimationView extends SurfaceView implements Callback {

	Context ctxt = null;
	Canvas canvas = null;
	Paint paint = null;
	SurfaceHolder surfaceHolder = null;
	Bitmap bitmap01 = null;
	Bitmap bitmap02 = null;
	boolean isStop = false;
	MyThread thread = null;
	
	int backY01 = 0;
	int backY02 = 0;
	
	int screenWidth = 0;
	int screenHeight = 0;
	
	public AnimationView(Context context, int width, int height) {
		super(context);
		ctxt = context;
		this.screenWidth = width;
		this.screenHeight= height;
		paint = new Paint();
		surfaceHolder = this.getHolder();
		surfaceHolder.addCallback(this);
		bitmap01 = ReadBitMap(ctxt,R.drawable.map_0);
		bitmap02 = ReadBitMap(ctxt,R.drawable.map_1);
		backY01 = 0;
		backY02 = -screenHeight;
	}

	class MyThread extends Thread{
		@Override
		public void run() {
			while (isStop) {
				long startTime = System.currentTimeMillis();
				try {
				synchronized (surfaceHolder) {
					canvas = surfaceHolder.lockCanvas();
					Draw();
				}	
				} catch (Exception e) {
					// TODO: handle exception
				}finally{
				   surfaceHolder.unlockCanvasAndPost(canvas);
				}
				long endTime = System.currentTimeMillis();
				int diffTime = 
				(int)(endTime-startTime);
				while (diffTime < 200) {
					diffTime = (int)(System.currentTimeMillis()-startTime);
					Thread.yield();
				}
			}
			super.run();
		}
	}
	public void Draw(){
		renderBack();
		updateBack();
	}
	
	public void renderBack(){
		canvas.drawBitmap(bitmap01, 0, backY01, paint);
		canvas.drawBitmap(bitmap02, 0, backY02, paint);
	}
	public void updateBack(){
		backY01+=10;
		backY02+=10;
		if (backY01 == screenHeight) {
			backY01 = -screenHeight;
		}
		if (backY02 == screenHeight) {
			backY02 = -screenHeight;
		}
	}
	
	public Bitmap ReadBitMap(Context context, int resId) {
	    BitmapFactory.Options opt = 
	    new BitmapFactory.Options();
	    opt.inPreferredConfig = Bitmap.Config.RGB_565;
	    opt.inPurgeable = true;
	    opt.inInputShareable = true;
	    // 获取资源图片
	    InputStream is = 
	    context.getResources().openRawResource(resId);
	    return BitmapFactory.decodeStream(is, null, opt);
	}
	
	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {
		

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		isStop = true;
		thread = new MyThread();
		thread.start();
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		isStop = false;
	}

}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值