屏幕的尺寸信息
屏幕参数
- 屏幕大小,指屏幕对角线的长度
- 分辨率,手机的像素点的个数
- PPI,每英寸像素
系统屏幕密度
独立像素密度dp
使用mdpi作为标准,此情况下1px=1dp
密度越高,1dp所对应的px就会越大
单位转换
/**
* 将px转换为dip
* @param context
* @param pxValue
* @return
*/
public static int px2dip(Context context,float pxValue){
float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue/scale+0.5f);
}
/**
* 将dp转换为px
* @param context
* @param dipValue
* @return
*/
public static int dip2px(Context context,float dipValue){
float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
/**
* px转sp
* @param context
* @param pxValue
* @return
*/
public static int px2sp(Context context,float pxValue){
float scale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue/scale + 0.5f);
}
/**
* sp转px
* @param context
* @param spValue
* @return
*/
public static int sp2px(Context context,float spValue){
float scale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * scale + 0.5f);
}
2D绘图基础
Paint属性
setAntiAlias() //设置画笔锯齿效果
setColor() //设置颜色
setARGB()
setAlpha()
setTextSize()
setStyle() //设置画笔空心或者实心
setStrokeWidth() //设置空心边框的宽度
Canvas方法
DrawPoint,Line,Lines,Rect,RoundRect,Circle,Arc,Oval,Text,PosText(在制定位置绘制文本),Path。
DrawArc中的属性useCenter表示绘制弧形还是扇形,
Android的XML绘图
Bitmap
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@drawable/banana">
</bitmap>
Shape
使用shape可以在xml中绘制各种形状(rectangle,oval,line,ring)
标签
corners (圆角矩形,当shape为rectangle时使用)
gradient 渐变
padding 内边距
size 指定大小,一般用在imageview配合scaleType时使用
solid 填充颜色
stroke 指定边框
Layer
作为图层使用。
根结点为 layer-list
子节点为item 每一个item作为一个图层 drawable属性作为图层内容
Selector
用于设置不同状态下不同样式的图像。
Android绘图技巧
Canvas
Canvas.save(); //保存画布状态,后续操作仿佛在新的图层中进行
Canvas.restore(); //恢复画布状态,类似合并图层操作
Canvas.translate(); //将本为(0,0)的原点平移到新的地方
Canvas.rotate() //将坐标系旋转一定的角度
Layer图层
图层入栈(之后所有的绘图操作都会在这个图层上进行)
saveLayer();
saveLayerAlpha(); //可以调整这个图层的透明度0-255
图层出栈(合并图层内容);
restore();
restoreToCount();
色彩特效处理
颜色矩阵,按行来解释,分别为R,G,B,透明度的分量
按列来说,最后一列是分量中的偏移量offset
初始矩阵
改变偏移量
直接改变第五列的值即是改变了颜色分量的偏移量,如果把第一行和第二行的第五列改为100,则加强了红色和绿色,混合出黄色使得画面偏黄。
改变颜色系数
如果改变第二行的1变为2,则是改变了G分量所对应的系数,进行运算后G分量会变成原来的两倍,使得色调偏绿。
改变色光属性
色光属性指的是图像的色调,饱和度,亮度三个属性。
//改变色调
ColorMatrix hueMatrix = new ColorMatrix();
hueMatrix.setRotate(0,xxx); //0,1,2分别代表RGB
//改变饱和度
ColorMatrix saturationMatrix = new ColorMatrix();
saturationMatrix.setSaturation(float sat);
//改变亮度
ColorMatrix lumMatrix = new ColorMatrix();
lumMatrix.setScale(lum,lum,lum,1);
//混合
ColorMatrix imageMatrix = new ColorMatrix();
imageMatrix.postConcat(hueMatrix);
imageMatrix.postConcat(saturationMatrix);
imageMatrix.postConcat(lumMatrix);
//给paint设置颜色矩阵
Paint paint = new Paint();
paint.setColorFilter(new ColorMatrixColorFilter(imageMatrix));
像素点分析
可以通过修改一张图片上每个像素点的ARGB值,来达到更加精细的美化效果。
使用bitmap.getPixels();方法提取Bitmap中的像素点。
bitmap.getPixels(pixels,offset,stride,x,y,width,height);
- pixels:提取颜色的数组
- offset:写入pixels中的第一个像素索引值
- stride:行间距
- x:从位图读取的第一个像素的x坐标值
- y:从位图读取的第一个像素的y坐标值
- width:每一行的像素宽度
- height:总行数
提取之后进行处理
//获取像素的red分量值
int r = Color.red(pixels[i]);
//进行处理之后
//合成
newPixels[i] = Color.argb(a,r,g,b);
bmp.setPixels(newPixels,0,0,width,height);
图形特效处理
变形矩阵Matrix
Matrix可以对图形形状来进行改变,通常有四种变化模式
- 平移
- 旋转
- 缩放
- 错切
平移变换:
每一个像素点都进行平移变换。
旋转变换:
缩放变换:
将每个点的坐标都进行相同比例的缩放。
在代码中可以用一维数组来模拟矩阵,代码如下
private float[] mImageMatrix = new float[9];
Matrix matrix = new Matrix();
matrix.setValues(mImageMatrix);
//以变换矩阵的形式绘制图像
canvas.drawBitmap(bmp,matrix,null);
Android提供了API来简化矩阵的运算,主要是:
- setRotate()旋转
- setTranslate()平移
- setScale()缩放
- setSkew()错切
- post()和pre(),提供前乘和后乘运算
set方法会重置矩阵中的所有值,但是post和pre不会,这两个方法通常用于矩阵的混合作用。不满足交换律。
像素块分析
除了用图像矩阵,还有一个方法可以进行图形变换
drawBitmapMesh(...);
它的原理是将图像分成一个个的小块,通过改变每一个小块的图像来修改整个图像。
画笔特效处理
PorterDuffXfermode
它控制的是两个图片混合时候的现实区域
刮刮卡效果:
public class XfermodeView extends View {
private Bitmap mBigBitmap,mFgBitmap;
private Paint mPaint;
private Canvas mCanvas;
private Path mPath;
public XfermodeView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
private void init() {
mPaint = new Paint();
mPaint.setAlpha(0);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeCap(Paint.Cap.ROUND);
mPaint.setStrokeJoin(Paint.Join.ROUND);
mPaint.setStrokeWidth(50);
mPath = new Path();
mBigBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.banana);
mFgBitmap = Bitmap.createBitmap(mBigBitmap.getWidth(),mBigBitmap.getHeight(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mFgBitmap);
mCanvas.drawColor(Color.GRAY);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPath.reset();
mPath.moveTo(event.getX(),event.getY());
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(event.getX(),event.getY());
break;
}
mCanvas.drawPath(mPath,mPaint);
invalidate();
return true;
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawBitmap(mBigBitmap,0,0,null);
canvas.drawBitmap(mFgBitmap,0,0,null);
}
}
Shader
Shader成为着色器或者渲染器,它用来实现一系列的渐变效果。
- BitmapShader——位图Shader
- LinearGradient——线性Shader
- RadialGradient——光束Shader
- SweepGradient——梯度Shader
ComposeShader——混合Shader
几种填充模式:
CLAMP拉伸——拉伸图片的最后一个像素
- REPEAT重复——横向,纵向不断重复
- MIRROR镜像——不断反转重复
PathEffect
路径笔触的显示效果,有拐角圆滑,杂点,虚线,组合显示效果。
SurfaceView
SurfaceView和View的区别
- SurfaceView常用于被动刷新,例如频繁刷新的情况下
- SurfaceView在子线程中刷新
- SurfaceView有双缓冲机制
在数据量大,需要频繁刷新时应该使用SurfaceView
SurfaceView的使用
创建SurfaceView
创建自定义的SurfaceView,实现对应的Callback和Runnable接口
初始化
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsDrawing;
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
mHolder = getHolder();
mHolder.addCallback(this);
}
使用
//创建方法 新建线程
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
//停止绘画
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mIsDrawing = false;
}
//线程的执行逻辑
@Override
public void run() {
while (mIsDrawing){
draw();
}
}
//具体绘画所执行的过程
private void draw(){
try {
mCanvas = mHolder.lockCanvas();
mCanvas.drawColor(Color.GRAY);
}catch (Exception e){
}finally {
if(mCanvas != null){
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
绘图板代码
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback,Runnable{
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsDrawing;
private Path mPath;
private Paint mPaint;
public MySurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
mPath = new Path();
mPaint = new Paint();
mPaint.setColor(Color.RED);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeWidth(5);
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
setKeepScreenOn(true);
}
//创建方法 新建线程
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
mIsDrawing = true;
new Thread(this).start();
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
//停止绘画
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
mIsDrawing = false;
}
//线程的执行逻辑
@Override
public void run() {
long start = System.currentTimeMillis();
while (mIsDrawing){
draw();
}
long end = System.currentTimeMillis();
if(end - start < 100){
try {
Thread.sleep(100-(end - start));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
//具体绘画所执行的过程
private void draw(){
try {
mCanvas = mHolder.lockCanvas();
mCanvas.drawColor(Color.GRAY);
mCanvas.drawPath(mPath,mPaint);
}catch (Exception e){
}finally {
if(mCanvas != null){
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
int x = (int) event.getX();
int y = (int) event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
mPath.moveTo(x,y);
break;
case MotionEvent.ACTION_MOVE:
mPath.lineTo(x,y);
break;
}
return true;
}
}