动画与图形——画布与绘制
绘制几何图形
“如何在手机上绘制2D圈形呢? "这是许多android游戏开发都是常提到的问题,在android SDK当中,并没有JavaGraphics2D的函数可以使用,而是使用android.graphics底下的类来绘制20向量图。这个package提供了许多在手机上绘制图形的类与方法其中Canvas上而Paint(Android graphics Paint)类则像是彩色铅笔,给予不同的调协,即可绘制不同颜色
不同种类效果的向量图形。
本例将运用Paint对象(绘笔)的设置值不同,在Cavas(画布)上绘制空心、实心及渐变色的多种几何多形。
自定义一个View类继承View,并重写onDraw方法
package com.example.animateandview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.view.View;
public class MyView extends View {
public MyView(Context context) {
super(context);
}
//会在主键加载时调用
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//设置画布颜色为白色
canvas.drawColor(Color.WHITE);
Paint paint=new Paint();//创建画笔
//去锯齿
paint.setAntiAlias(true);
//设置画笔颜色
paint.setColor(Color.RED);
//设置画笔风格(空心、实心) STROKE:空心
paint.setStyle(Paint.Style.STROKE);
//设置画笔宽度
paint.setStrokeWidth(3);
//画一个空心圆 参数(圆心x,圆心y,半径r,paint)
canvas.drawCircle(40,40,30,paint);
//画一个空心正方形 参数(left,top,right,buttom,)
canvas.drawRect(10,90,70,150,paint);
//长方形
canvas.drawRect(10,170,70,200,paint);
//椭圆形
RectF re=new RectF(10,220,70,250);
canvas.drawOval(re,paint);
//三角形
Path path=new Path();
path.moveTo(10,330);
path.lineTo(70,330);
path.lineTo(40,270);
path.close();
canvas.drawPath(path,paint);
//梯形
Path path1=new Path();
path1.moveTo(10,410);
path1.lineTo(70,410);
path1.lineTo(55,350);
path1.lineTo(25,350);
path1.close();
canvas.drawPath(path1,paint);
//实心
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.BLUE);
//画一个实心圆 参数(圆心x,圆心y,半径r,paint)
canvas.drawCircle(120,40,30,paint);
//画一个实心正方形 参数(left,top,right,buttom,)
canvas.drawRect(90,90,150,150,paint);
//长方形
canvas.drawRect(90,170,150,200,paint);
//椭圆形
RectF re1=new RectF(90,220,150,250);
canvas.drawOval(re1,paint);
//三角形
Path path2=new Path();
path2.moveTo(90,330);
path2.lineTo(150,330);
path2.lineTo(120,270);
path2.close();
canvas.drawPath(path2,paint);
//梯形
Path path3=new Path();
path3.moveTo(90,410);
path3.lineTo(150,410);
path3.lineTo(135,350);
path3.lineTo(105,350);
path3.close();
canvas.drawPath(path3,paint);
//绘制渐变色
Shader shader=new LinearGradient(0,0,100,100,new int[]{
Color.RED,Color.GREEN,Color.BLUE,Color.YELLOW},null,Shader.TileMode.REPEAT);
paint.setShader(shader);
//画一个渐变圆 参数(圆心x,圆心y,半径r,paint)
canvas.drawCircle(200,40,30,paint);
//画一个渐变正方形 参数(left,top,right,buttom,)
canvas.drawRect(170,90,230,150,paint);
//长方形
canvas.drawRect(170,170,230,200,paint);
//椭圆形
RectF re2=new RectF(170,220,230,250);
canvas.drawOval(re2,paint);
//三角形
Path path4=new Path();
path4.moveTo(170,330);
path4.lineTo(230,330);
path4.lineTo(200,270);
path4.close();
canvas.drawPath(path4,paint);
//梯形
Path path5=new Path();
path5.moveTo(170,410);
path5.lineTo(230,410);
path5.lineTo(215,350);
path5.lineTo(185,350);
path5.close();
canvas.drawPath(path5,paint);
//文字
paint.setTextSize(24);
canvas.drawText("圆形",240,50,paint);
canvas.drawText("正方形",240,120,paint);
canvas.drawText("长方形",240,190,paint);
canvas.drawText("椭圆形",240,250,paint);
canvas.drawText("三角形",240,320,paint);
canvas.drawText("梯形",240,390,paint);
}
}
显示文件修改setContentView
setContentView(new MyView(this));
问题:有个问题就是,渐变色只显示圆形和椭圆,多边形和文字不显示
图像绘制
自定义一个View类继承View,并重写onDraw方法
package com.example.animateandview;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.view.View;
public class MyImageView extends View {
public MyImageView(Context context) {
super(context);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint=new Paint();
Bitmap bitmap= BitmapFactory.decodeResource(getResources(),R.mipmap.ic_launcher);
canvas.drawBitmap(bitmap,0,0,paint);
}
}
修改setContentView
setContentView(new MyView(this));
SurfaceView
SurfaceView是视图(View)的继承类,这个视图里内嵌了一个专门用于绘制的Surface。你可以控制这个Surface的格式和尺寸SurfaceView控制这个Surface的绘制位置。可以直接从内存或者DMA等硬件接口取得图像数据,是个非常重要的绘图容器。
传统View及其派生类的更新只能在UI线程,然而UI线程还同时处理其他交互逻辑,这就无法保证view更新的速度和帧率了,而SurfaceView可以用独立的线程来进行绘制,因此可以提供更高的帧率。
例如游戏,摄像头取景等场景就比较适合用SurfaceView来实现。写入到Surface的内容可以被直接复制到显存从而显示出来,这使得显示速度会非常快。
package com.example.animateandview;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {
private SurfaceHolder holder;
private MyThread myThread;
public MySurfaceView(Context context) {
super(context);
holder=this.getHolder();
holder.addCallback(this);//添加回调接口
}
//线程内部类
class MyThread implements Runnable{
private SurfaceHolder holder;
public boolean isRun;
public MyThread(SurfaceHolder holder){
this.holder=holder;
isRun=true;
}
@Override
public void run() {
int count=0;
Canvas canvas=null;
while (isRun){
try {
synchronized (holder){//同步块
canvas=holder.lockCanvas();//锁定画布
canvas.drawColor(Color.WHITE);
Paint paint=new Paint();
paint.setColor(Color.RED);
paint.setStyle(Paint.Style.FILL);
paint.setAntiAlias(true);
canvas.drawRect(10,10,100,100,paint);
paint.setTextSize(24);
canvas.drawText("当前是第"+(count++)+"秒",10,150,paint);
Thread.sleep(1000);//休眠1秒
}
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
holder.unlockCanvasAndPost(canvas);//释放
}
}
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
myThread=new MyThread(holder);
myThread.isRun=true;
new Thread(myThread).start();
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
myThread.isRun=false;
}
}
修改setContentView
setContentView(new MySurfaceView(this));
SurfaceView实现视频播放
package com.example.animateandview;
import android.media.AudioManager;
import android.media.MediaPlayer;
import android.os.Environment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import java.io.IOException;
public class Main5Activity extends AppCompatActivity implements SurfaceHolder.Callback {
private SurfaceView surfaceView;
private SurfaceHolder holder;
private MediaPlayer player;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main5);
surfaceView=findViewById(R.id.surfaceView);
holder=surfaceView.getHolder();
holder.addCallback(this);
holder.setFixedSize(320,220);//设置分辨率,不设置即为视频默认分辨率
}
public void playClick(View view){
player.start();
}
public void pauseClick(View view){
player.pause();
}
public void stopClick(View view){
player.stop();
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
player=new MediaPlayer();
player.setAudioStreamType(AudioManager.STREAM_MUSIC);
player.setDisplay(holder);
String path= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MOVIES)+"/2.mp4";
try {
player.setDataSource(path);//设置播放视频源
player.prepare();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
if (player!=null){
if (player.isPlaying()){
player.stop();
player.release();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
if (player!=null){
if (player.isPlaying()){
player.stop();
player.release();
}
}
}
}
设置权限,之前忘记设置,导致找不到文件,视频无法播放
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Draw 9-patch
与传统的png格式图片相比,9.png 格式图片在图片四周有一圈一个像素点组成的边沿,该边沿用于对图片的可扩展区和内容显示区进行定义。这种格式的图片在android环境下具有自适应调节大小的能力。
运行android SDK中tools路径下的draw9patch工具:
给.9图片划线,指的是通过划线,决定图片的可拉伸区域和显示文本信息的区域。其中,上方和左 方的线是控制图片的可拉伸区域的,也就是说,上方的线控制图片横向可拉伸,左侧的线控制纵向可拉伸。下方的线和右侧的线控制图片的文本区域,也就是说,如果图片上有text,就会杷位置控制在下方和右侧的线围城的区域里。
如果想制除划线,按住shift+鼠标左键,删除划线。
现在因为draw9patch已经被广泛使用,已经在android studio里了。