Android的图形与图像处理之一 使用简单图片&绘图
16lz
2021-01-26
R.drawable.file_name是一个int常量,若想获取实际的Drawable对象,可调用Resource的getDrawable(int id)获取
Bitmap与BitmapFactory BitmapDrawable里封装的图片就是一个Bitmap对象,封装方法如下: BitmapDrawable drawable = new BitmapDrawable(bitmap); 如果要获取BitmapDrawable所包装的Bitmap对象,则可调用BitmapDrawable的getBitmap()方法,示例如下: Bitmap bitmap = drawable.getBitmap(); Bitmap还提供了一些静态方法来创建新的Bitmap对象,如下:
BitmapFactory包含大量方法
通常做法是把图片放在/res/drawabe-hdpi目录下,程序通过ID来获取对象。如果系统不停的去解析、创建Bitmap对象,可能由于前面创建Bitmap所占内存还没有回收,而导致程序发生OutOfMemory错误,为此设计了如下方法: boolean isRecycled():返回是否已被回收 void recycle():强制一个Bitmap对象以及回收自己
绘图 Canvas、Paint Android的绘图继承View组件,并重写它的onDraw(Canvas canvas)方法 API Canvas代表依附于指定View画布,它有如下方法: 除了上述方法外,Canvas还提供如下方法进行坐标变换:
Canvas提供上面的方法还涉及一个API:Paint,Paint代表了Canvas上的画笔,用于设置绘制风格 Paint常用方法:
Canvas提供的绘制方法中还有一个API:Path,Path代表任意多条直线连接而成的任意图形,当Canvas根据Path绘制图形,它可以绘制出任意形状。 还可以自定义一个View组件,重写它的onDraw(Canvas)方法。 Canvas不仅可以绘制简单图形,还可以直接将一个Bitmap绘制到画布上,这是极大的分工方便 下面详解Path类 Android还为路径绘制提供了PathEffect来定义绘制效果,PathEffect包含如下子类:
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView( new MyView( this ));
}
class MyView extends View
{
float phase ;
PathEffect[] effects = new PathEffect[7];
int [] colors ;
private Paint paint ;
Path path ;
public MyView(Context context)
{
super (context);
paint = new Paint();
paint .setStyle(Paint.Style. STROKE );
paint .setStrokeWidth(4);
path = new Path();
path .moveTo(0,0);
for ( int i =1; i<= 15; i++)
{
path .lineTo(i*20, ( float )Math.random()*60);
}
colors = new int []{Color. BLACK ,Color. BLUE , Color. CYAN
, Color. GREEN , Color. MAGENTA , Color. RED , Color. YELLOW };
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color. WHITE );
effects [0]= null ;
effects [1] = new CornerPathEffect(10);
effects [2] = new DiscretePathEffect(3.0f, 5.0f);
effects [3] = new DashPathEffect( new float []{20,10,5,10}, phase );
Path p = new Path();
p.addRect(0,0,8,8,Path.Direction. CCW );
effects [4] = new PathDashPathEffect(p,12, phase ,
PathDashPathEffect.Style. ROTATE );
effects [5] = new ComposePathEffect( effects [2], effects [4]);
effects [6] = new SumPathEffect( effects [4], effects [3]);
canvas.translate(8, 8);
for ( int i = 0; i< effects . length ; i++)
{
paint .setPathEffect( effects [i]);
paint .setColor( colors [i]);
canvas.drawPath( path , paint );
canvas.translate(0, 60);
}
phase += 1;
invalidate();
} } } 此外,Android的Canvas还提供了一个drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)方法,该方法可以沿着Path绘制文本。 示例代码如下: main.xml public class PathTest extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView( new TextView( this ));
// setContentView(new MyView(this));
}
class TextView extends View
{
final String DRAW_STR = "android java" ;
Path[] paths = new Path[3];
Paint paint ;
public TextView(Context context)
{
super (context);
paths [0] = new Path();
paths [0].moveTo(0, 0);
for ( int i = 1; i<= 7;i++)
{
paths [0].lineTo(i * 30, ( float ) Math.random() * 30);
}
paths [1] = new Path();
RectF rectF = new RectF(0,0,200,120);
paths [1].addOval(rectF,Path.Direction. CCW );
paths [2] = new Path();
paths [2].addArc(rectF, 60, 180);
paint = new Paint();
paint .setAntiAlias( true );
paint .setColor(Color. CYAN );
paint .setStrokeWidth(1);
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color. WHITE );
canvas.translate(40, 40);
paint .setTextAlign(Paint.Align. RIGHT );
paint .setTextSize(20);
paint .setStyle(Paint.Style. STROKE );
canvas.drawPath( paths [0], paint );
paint .setStyle(Paint.Style. FILL );
canvas.drawTextOnPath( DRAW_STR , paths [0],-8,20, paint );
canvas.translate(0, 60);
paint .setStyle(Paint.Style. STROKE );
canvas.drawPath( paths [1], paint );
paint .setStyle(Paint.Style. FILL );
canvas.drawTextOnPath( DRAW_STR , paths [1], -20, 20, paint );
canvas.translate(0, 120);
paint .setStyle(Paint.Style. STROKE );
canvas.drawPath( paths [2], paint );
paint .setStyle(Paint.Style. FILL );
canvas.drawTextOnPath( DRAW_STR , paths [2], -10, 20, paint );
} } }
绘制游戏动画 动画其实就是不断地重复调用View组件的onDraw(Canvas canvas)方法 如果要View上绘制的图形发生部分改变,就需要程序采用变量来“记住”这些状态数据; 如果需要游戏动画随着用户操作而改变,就需要为用户动作编写事件监听器; 如果需要游戏动画自动改变,就需要使用Timer控制状态数据修改;
绘图中,为了保留用户之间绘制的内容,程序需要借助“双缓冲”技术。 (双缓冲:当程序需要在指定View上进行绘制时,程序并不直接绘制到该View组件上,而是先绘制到一个内存中的Bitmap上,等到内存中的Bitmap绘制好之后,再一次性将Bitmap绘制到View组件上)
Bitmap与BitmapFactory BitmapDrawable里封装的图片就是一个Bitmap对象,封装方法如下: BitmapDrawable drawable = new BitmapDrawable(bitmap); 如果要获取BitmapDrawable所包装的Bitmap对象,则可调用BitmapDrawable的getBitmap()方法,示例如下: Bitmap bitmap = drawable.getBitmap(); Bitmap还提供了一些静态方法来创建新的Bitmap对象,如下:
createBitmap(Bitmap source, int x, int y, int width, int height) | 从源位图source的指定坐标开始,从中挖取width*height的一块来创建新Bitmap |
createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) | 对源位图进行缩放,缩放成(dstWidth*dstHeight)的新位图 |
createBitmap(int width, int height, Bitmap.Config config) | 创建一个宽width、高height的新位图 |
createBitmap(Bitmap source, int x, int y, int width, int height, Matrix m, boolean filter) | 从源位图挖取一块指定宽高创建Bitmap对象,并按Matrix指定的规则变换 |
decodeByteArray(byte[] data, int offset, int length) | 从指定字节数组的offset开始,将长度为length的字节数据解析成Bitmap对象 |
decodeFile(String pathName) | 从pathName指定的文件中解析创建Bitmap对象 |
decodeFileDescriptor(FileDescriptor fd) | 用于从FileDescriptor对应的文件 |
decodeResource(Resources res, int id) | 根据给定资源ID从指定资源解析、创建 |
decodeStream(InputStream is) | 从指定流中解析、创建 |
绘图 Canvas、Paint Android的绘图继承View组件,并重写它的onDraw(Canvas canvas)方法 API Canvas代表依附于指定View画布,它有如下方法: 除了上述方法外,Canvas还提供如下方法进行坐标变换:
rotate(float degrees,float px, float py) | 对Canvas执行旋转变换 |
scale(float sx, float sy, float sy,float px, float py) | 对Canvas执行缩放变换 |
skew(float sx, float sy) | 对Canvas执行倾斜变换 |
translate(float dx, float dy) | 移动Canvas。向右移动dx距离(dx为负则向左),向下移动dy距离(dy为负则向上) |
setARGB(int a, int r, int g, int b)setColor(int color) | 设置颜色 |
setAlpha(int a) | 设置透明度 |
setAntiAlias(boolean aa) | 设置是否抗锯齿 |
setColor(int color) | |
setPathEffect(PathEffect effect) | 设置绘制路径时的路径效果 |
setShader(Shader shader) | 设置画笔的填充效果 |
setShadowLayer(float radius, float dx, float dy, int color) | 设置阴影 |
setStrokeWidth(float width) | 设置画笔的笔触宽度 |
setStrikeJoin(Paint.Join join) | 设置画笔转弯处的连接风格 |
setStyle(Paint.Style style) | 设置Paint的填充风格 |
setTextAlign(Paint.Align align) | 设置绘制文本时文字的对齐方式 |
setTextSize(float textSize) | 大小 |
- ComposePathEffect
- CornerPathEffect
- DashPathEffect
- DiscretePathEffect
- PathDashPathEffect
- SumPathEffect
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView( new MyView( this ));
}
class MyView extends View
{
float phase ;
PathEffect[] effects = new PathEffect[7];
int [] colors ;
private Paint paint ;
Path path ;
public MyView(Context context)
{
super (context);
paint = new Paint();
paint .setStyle(Paint.Style. STROKE );
paint .setStrokeWidth(4);
path = new Path();
path .moveTo(0,0);
for ( int i =1; i<= 15; i++)
{
path .lineTo(i*20, ( float )Math.random()*60);
}
colors = new int []{Color. BLACK ,Color. BLUE , Color. CYAN
, Color. GREEN , Color. MAGENTA , Color. RED , Color. YELLOW };
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color. WHITE );
effects [0]= null ;
effects [1] = new CornerPathEffect(10);
effects [2] = new DiscretePathEffect(3.0f, 5.0f);
effects [3] = new DashPathEffect( new float []{20,10,5,10}, phase );
Path p = new Path();
p.addRect(0,0,8,8,Path.Direction. CCW );
effects [4] = new PathDashPathEffect(p,12, phase ,
PathDashPathEffect.Style. ROTATE );
effects [5] = new ComposePathEffect( effects [2], effects [4]);
effects [6] = new SumPathEffect( effects [4], effects [3]);
canvas.translate(8, 8);
for ( int i = 0; i< effects . length ; i++)
{
paint .setPathEffect( effects [i]);
paint .setColor( colors [i]);
canvas.drawPath( path , paint );
canvas.translate(0, 60);
}
phase += 1;
invalidate();
} } } 此外,Android的Canvas还提供了一个drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint)方法,该方法可以沿着Path绘制文本。 示例代码如下: main.xml public class PathTest extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super .onCreate(savedInstanceState);
setContentView( new TextView( this ));
// setContentView(new MyView(this));
}
class TextView extends View
{
final String DRAW_STR = "android java" ;
Path[] paths = new Path[3];
Paint paint ;
public TextView(Context context)
{
super (context);
paths [0] = new Path();
paths [0].moveTo(0, 0);
for ( int i = 1; i<= 7;i++)
{
paths [0].lineTo(i * 30, ( float ) Math.random() * 30);
}
paths [1] = new Path();
RectF rectF = new RectF(0,0,200,120);
paths [1].addOval(rectF,Path.Direction. CCW );
paths [2] = new Path();
paths [2].addArc(rectF, 60, 180);
paint = new Paint();
paint .setAntiAlias( true );
paint .setColor(Color. CYAN );
paint .setStrokeWidth(1);
}
@Override
protected void onDraw(Canvas canvas)
{
canvas.drawColor(Color. WHITE );
canvas.translate(40, 40);
paint .setTextAlign(Paint.Align. RIGHT );
paint .setTextSize(20);
paint .setStyle(Paint.Style. STROKE );
canvas.drawPath( paths [0], paint );
paint .setStyle(Paint.Style. FILL );
canvas.drawTextOnPath( DRAW_STR , paths [0],-8,20, paint );
canvas.translate(0, 60);
paint .setStyle(Paint.Style. STROKE );
canvas.drawPath( paths [1], paint );
paint .setStyle(Paint.Style. FILL );
canvas.drawTextOnPath( DRAW_STR , paths [1], -20, 20, paint );
canvas.translate(0, 120);
paint .setStyle(Paint.Style. STROKE );
canvas.drawPath( paths [2], paint );
paint .setStyle(Paint.Style. FILL );
canvas.drawTextOnPath( DRAW_STR , paths [2], -10, 20, paint );
} } }
绘制游戏动画 动画其实就是不断地重复调用View组件的onDraw(Canvas canvas)方法 如果要View上绘制的图形发生部分改变,就需要程序采用变量来“记住”这些状态数据; 如果需要游戏动画随着用户操作而改变,就需要为用户动作编写事件监听器; 如果需要游戏动画自动改变,就需要使用Timer控制状态数据修改;
绘图中,为了保留用户之间绘制的内容,程序需要借助“双缓冲”技术。 (双缓冲:当程序需要在指定View上进行绘制时,程序并不直接绘制到该View组件上,而是先绘制到一个内存中的Bitmap上,等到内存中的Bitmap绘制好之后,再一次性将Bitmap绘制到View组件上)
更多相关文章
- android从fragment进入activity再返回实现刷新fragment的做法
- 20189200余超 2018-2019-2 移动平台应用开发实践第六周作业
- 在Android中实现RN的自定义Native Modeule
- android 指定打包资源文件的方法
- Android(java)学习笔记124:Android权限大全
- Android(安卓)Gradle 使用技巧
- Android(安卓)Espresso
- Android(安卓)启动模式
- Android(安卓)RadioGroup设置单选效果