前言
目录
Android绘图机制与处理技巧.png
Android屏幕相关知识
屏幕尺寸信息
屏幕参数
- 屏幕大小:指屏幕对角线的长度,通常使用“寸”来度量,如4.7寸、5.5寸手机等
- 分辨率:手机屏幕像素点的个数,720×1280就是指宽有720个像素点,高有1280个像素点
- PPI:每英寸像素,又名DPI,由对角线的像素点数除以屏幕的大小得到的
系统屏幕密度
密度 |
密度值 |
分辨率 |
ldpi |
120 |
240×320 |
mdpi |
160 |
320×480 |
hdpi |
240 |
480×800 |
xhdpi |
320 |
720×1280 |
xxhdpi |
480 |
1080×1920 |
独立像素密度dp
Android系统使用mdpi即密度值为160的屏幕作为标准,在这个屏幕上1px = 1dp,其他屏幕可以进行比例换算,例如同样是100dp的长度,在mdpi中为100px,而hdpi中为150px。也就是说在mdpi中1dp = 1px,而hdpi中1dp = 1.5px,在xdpi中1dp = 2px,在xxhpi中1dp = 3px
各分辨率换算比率
ldpi :mdpi :hdpi :xhdpi :xxhdpi = 3:4:6:8:12
单位换算
- 这里的换算封装成工具类以便以后使用
- 核心就是从DisplayMetrics显示度量类中获取信息
- 这里我顺便添加了获得屏幕宽度的方法
public class DisplayUtils {
/**
* 获得屏幕宽度(像素)
*
* @param activity
* @return
*/
public static int getDisplayWidth(Activity activity) {
DisplayMetrics metric = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
int width = metric.widthPixels; // 屏幕宽度(像素)
return width;
}
/**
* 获得屏幕高度(像素)
*
* @param activity
* @return
*/
public static int getDisplayHeight(Activity activity) {
DisplayMetrics metric = new DisplayMetrics();
activity.getWindowManager().getDefaultDisplay().getMetrics(metric);
int height = metric.heightPixels; // 屏幕高度(像素)
return height;
}
/**
* 将px值转换为dip或dp值,保证尺寸大小不变
*
* @param context 通过上下文获得显示参数中的屏幕密度
* @param pxValue 需要转换的px值
* @return
*/
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 将dip或dp值转换为px值,保证尺寸大小不变
*
* @param context 通过上下文获得显示参数中的屏幕密度
* @param dipValue 需要转换的dp值
* @return
*/
public static int dip2px(Context context, float dipValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dipValue * scale + 0.5f);
}
/**
* 将px值转换为sp值,保证文字大小不变
*
* @param context 通过上下文获得显示参数中的屏幕密度
* @param pxValue 需要转换的px值
* @return
*/
public static int px2sp(Context context, float pxValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValue / fontScale + 0.5f);
}
/**
* 将sp值转换为px值,保证文字大小不变
*
* @param context 通过上下文获得显示参数中的屏幕密度
* @param spValue 需要转换的sp值
* @return
*/
public static int sp2px(Context context, float spValue) {
final float fontScale = context.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValue * fontScale + 0.5f);
}
}
Android绘图技巧
2D绘图技巧
- 系统通过Canvas画布对象来提供绘图方法,它提供了各种绘图API
API |
绘制(6) |
drawPoint() |
点 |
drawLine() |
线 |
drawsLine() |
多条线 |
drawRect() |
矩形 |
drawRoundRect() |
圆角矩形 |
drawVertices() |
多边形 |
drawArc() |
弧、扇 |
drawCircle() |
圆 |
drawOval() |
椭圆 |
drawText() |
绘制文本 |
drawPosText() |
在指定位置绘制文本 |
drawPath() |
绘制路径 |
drawBitmap() |
绘制Bitmap(加载) |
API |
设置属性 |
setAntiAlias() |
设置画笔锯齿效果 |
setColor() |
设置画笔颜色 |
setARGB() |
设置画笔A,R,G,B值 |
setAlpha() |
设置画笔Alpha值 |
setTextSize() |
设置字体尺寸 |
setStyle() |
设置画笔风格(空心或实心) |
setStrokeWidth() |
设置空心边框的宽度 |
reset() |
重置 |
绘制的实例
http://blog.csdn.net/rhljiayou/article/details/7212620
- 需要注意其中画弧和扇形,本质是画一个矩形,以矩形的中心为弧或扇的中心点,以矩形的中心为角度的坐标原点绘制
Android XML绘图
Bitmap
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@mipmap/ic_launcher"/>
Shape
- 绘制各种形状,省去了canvas和paint的步骤
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners //当shape为rectangle时使用
android:radius="integer" //半径值会被后面的单个半径属性覆盖,默认为1dp
android:topLeftRadius="integer"
android:topRightRadius="integer"
android:bottomLeftRadius="integer"
android:bottomRightRadius="integer" />
<gradient //渐变
android:angle="integer"
android:centerX="integer"
android:centerY="integer"
android:centerColor="integer"
android:endColor="color"
android:gradientRadius="integer"
android:startColor="color"
android:type=["linear" | "radial" | "sweep"]
android:useLevel=["true" | "false"] />
<padding //内边距
android:left="integer"
android:top="integer"
android:right="integer"
android:bottom="integer" />
<size //指定大小,一般用在imageview配合scaleType属性使用
android:width="integer"
android:height="integer" />
<solid //填充颜色
android:color="color" />
<stroke //边框
android:width="integer"
android:color="color"
android:dashWidth="integer"
android:dashGap="integer" />
</shape>
Layer 层
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:drawable="@drawable/ic_launcher" />
<item android:drawable="@drawable/ic_launcher"
android:left="10.0dp"
android:top="10.0dp"
android:right="10.0dp"
android:bottom="10.0dp"/>
......
</layer-list>
Selector 选择器
- Fragment配合RadioGroup实现点击切换内容时RadioGroup的子项就是用选择器作为View的触摸反馈,不过我更喜欢FragmentTabHost做为下方选项卡(跑题了。。。)
<?xml version="1.0" encoding="utf-8" ?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 默认时的背景图片-->
<item android:drawable="@drawable/X1"/>
<!-- 没有焦点时的背景图片 -->
<item android:drawable="@drawable/X2" android:state_window_focused="false"/>
<!-- 非触摸模式下获得焦点并单击时的背景图片 -->
<item android:drawable="@drawable/X3" android:state_focused="true" android:state_pressed="true"/>
<!-- 触摸模式下单击时的背景图片-->
<item android:drawable="@drawable/X4" android:state_focused="false" android:state_pressed="true"/>
<!--选中时的图片背景-->
<item android:drawable="@drawable/X5" android:state_selected="true"/>
<!--获得焦点时的图片背景-->
<item android:drawable="@drawable/X6" android:state_focused="true"/>
</selector>
Android绘图技巧
Canvas
API |
作用 |
Canvas.save() |
保存画布(类似PS中的图层保存) |
Canvas.restore() |
合并画布(类似PS中的合并图层) |
Canvas.translate() |
画布所在坐标系平移 |
Canvas.rotate() |
画布所在坐标系旋转 |
Layer 层
API |
作用 |
saveLayer() |
将图层入栈 |
saveLayerAlpha() |
将图层入栈 |
restore() |
将图层出栈 |
restoreCount() |
将图层出栈 |
- 入栈时,后面所有的操作都会发生在这个图层中
- 出栈时,则会把图像绘制到上层Canvas上
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
p.setColor(Color.BLUE);
canvas.drawCircle(150, 150, 100, p);
// 图一
canvas.saveLayerAlpha(0, 0, 400, 400, 127, LAYER_TYPE_NONE);
// 图二
// canvas.saveLayerAlpha(0, 0, 400, 400, 255, LAYER_TYPE_NONE);
p.setColor(Color.RED);
canvas.drawCircle(200, 200, 100, p);
canvas.restore();
}
图一,透明度为127时,为半透明状态
图二,透明度设置为255时,完全不透明
Android图像处理技巧
- Android对于图片的处理,最常用使用到的数据结构就是位图--Bitmap,它包含一张图片的所有数据
- 整个图片都是有点阵和颜色组成的
- 点阵就是一个包含像素的矩阵,每个元素对应者图片的一个像素
色彩矩阵分析
- 在色彩处理中通常用以下三个角度描绘一个图像
- 色调--物体传播的颜色
- 饱和度--颜色的纯度,从0(灰)到100%(饱和)来进行描述
- 亮度--颜色的相对明暗程度
- 在Android中系统使用颜色矩阵ColorMatrix来处理这个色彩效果
// ---- 施工中(8月2日--6日) ----
SurfaceView的使用
- SurfaceView是为了解决View中执行操作逻辑太多出现卡顿的情况
SurfaceView和View的区别
- View主要适用于主动更新的情况下,而SurfaceView主要适用于被动更新,例如频繁的刷新
- View在主线程中对画面进行刷新,而SurfaceView通常会通过一个子线程来进行页面的刷新
- View在绘图时没有使用双缓冲机制,而SurfaceView在底层实现机制中已经实现了双缓冲机制
SurfaceView的使用
- 创建SurfaceView
- 自定义SurfaceView继承SurfaceView
- 实现SurfaceHolder.Callback接口,并实现对应的三个方法
- 实现Runnable接口,实现run()方法
@Override
public void surfaceCreated(SurfaceHolder surfaceHolder) {
}
@Override
public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {
}
@Override
public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
}
@Override
public void run() {
}
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsDrawing;
private void init() {
mHolder = getHolder();
mHolder.addCallback(this);
}
API |
作用 |
lockCanvas() |
获得当前Canvas对象 |
drawColor() |
清屏 |
public class SurfaceViewDemo extends SurfaceView implements Runnable, SurfaceHolder.Callback {
private SurfaceHolder mHolder;
private Canvas mCanvas;
private boolean mIsDrawing; // 子线程标志位
public SurfaceViewDemo(Context context) {
super(context);
initView();
}
private void initView() {
mHolder = getHolder();
mHolder.addCallback(this);
setFocusable(true);
setFocusableInTouchMode(true);
this.setKeepScreenOn(true);
// mHolder.setFormat(PixelFormat.OPAQUE);
}
@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) {
draws();
}
}
public void draws() {
try {
mCanvas = mHolder.lockCanvas();
} catch (Exception e) {
} finally {
if (mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
}
SurfaceView实例
1. 正选曲线
@Override
public void run() {
while (mIsDrawing) {
draws();
x += 1;
y = (int) (100 * Math.sin(x * 2 * Math.PI/180) + 400);
mPath.lineTo(x, y);
}
}
private void draws() {
try {
mCanvas = mHolder.lockCanvas();
// Surface背景
mCanvas.drawColor(Color.WHITE);
mCanvas.drawPath(mPath, mPaint);
} catch (Exception e) {
} finally {
if (mCanvas != null) {
mHolder.unlockCanvasAndPost(mCanvas);
}
}
}
绘制正弦曲线
2. 绘图板
private void draws() {
try {
mCanvas = mHolder.lockCanvas();
// Surface背景
mCanvas.drawColor(Color.WHITE);
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;
case MotionEvent.ACTION_UP:
break;
}
return true;
}
画笔粗细没调。。
网友评论