屏幕的尺寸信息
屏幕参数:
屏幕大小:值屏幕对角线的长度,通常使用“寸”来度量。
分辨率:分辨率是指手机屏幕的像素点个数。
PPI:每英寸的像素,又被称为DPI,它是由对角线的像素点数除以屏幕的大小得到的。
系统屏幕密度:
在程序中,也可以非常方便的对这些单位进行换算。
同时,系统也提供了TypedValue类帮助我们转换:
Android绘图技巧
系统通过提供的Canvas对象来提供绘图方法。它提供了各种绘制图像的API,如drawPoint(点)、drawLine(线)、drawRect(矩形)、drawVertices(多边形)、drawArc(弧)、drawCircle(圆),等等。通过他们的名字,我们基本上可以打字了解他们的功能。
当然,Paint作为一个非常重要的元素,功能也是非常强大的,这里简单的列举一些他的属性和对应的功能。
Shape
通过Shape可以在XML中绘制各种形状,下面展示Shape所支持的参数
下面就是一个简单的通过渐变来实现的阴影效果:
运行结果:
Layer:
Layer是在Photoshop中非常常用的功能,在Android中,同样可以通过Layer来实现类似Photoshop中图层的概念:
运行结果:
Selector:
Selector的作用在于帮助开发者实现静态绘图中的事件反馈,通过给不同的事件设置不同的图像,从而在程序中根据用户输入,返回不同的效果
下面这个例子就展示在一个Selector中使用Shape作为它的Item的例子,实现一个具有点击反馈效果的、圆角矩形的Selector:
运行结果:
Canvas.save():保存画布。它的作用就是将之前的所有已绘制图像保存起来,让后续的操作就好像在一个新的图层上操作一样。
Canvas.restore():合并图层,它的作用是将我们在save()之后绘制的所有图像与save()之前的图像进行合并。
Canvas.translate():画布平移,或者坐标系的平移。
Canvas.roate():画布翻转,或坐标系的翻转。
通过一个仪表盘的案例来了解这几个方法,这个仪表盘可以分解成以下几个元素:
仪表盘:外面的大圆盘
刻度线:包含四个长的刻度线和其他短的刻度线
刻度值:包含长刻度线对应的大的刻度值和其他小的刻度值
指针:中间的指针,一粗一细两根指针
代码案例:
运行结果:
Layer图层
一张复杂的画可以由很多歌图层叠加起来,形成一个复杂的图像。在Android中,使用saveLayer()方法来创建一个图层,图层同样是基于栈的结构进行管理。
当saveLayerAlpha()方法的倒数第二个参数就是透明度参数
当透明度为127时,就是半透明
当透明度为255时,就是完全不透明
运行结果:
屏幕参数:
屏幕大小:值屏幕对角线的长度,通常使用“寸”来度量。
分辨率:分辨率是指手机屏幕的像素点个数。
PPI:每英寸的像素,又被称为DPI,它是由对角线的像素点数除以屏幕的大小得到的。
系统屏幕密度:
独立像素密度dp:
由于各种屏幕密度的不同,导致同样像素大小的长度,在不同密度的屏幕上显示长度不同。因为相同长度的屏幕,高密度的屏幕包含更多的像素点。Android系统使用mdpi即密度值为160的屏幕作为标准,在这个屏幕上1px=1dp。其他屏幕则可以通过比例进行换算,ldpi:mdpi:hdpi:xdpi:xxdpi=3:4:6:8:12。
单位换算:在程序中,也可以非常方便的对这些单位进行换算。
/**
* dp、sp转换成px的工具类
*
*/
public class DisplayUtils {
/**
* 将px值转换为dpi或者dp值,保持尺寸大小不变
*
* @param content
* @param pxValus
*
* @return
*/
public static int px2dip(Context content, float pxValus) {
final float scale = content.getResources().getDisplayMetrics().density;
return (int) (pxValus / scale + 0.5f);
}
/**
* 将dip和dp值转换为px值,保证尺寸大小不变
*
* @param content
* @param dipValus
*
* @return
*/
public static int dip2px(Context content, float dipValus) {
final float scale = content.getResources().getDisplayMetrics().density;
return (int) (dipValus / scale + 0.5f);
}
/**
* 将px值转换为sp值,保证文字大小不变
*
* @param content
* @param pxValus
* @return
*/
public static int px2sp(Context content, float pxValus) {
final float fontScale = content.getResources().getDisplayMetrics().scaledDensity;
return (int) (pxValus / fontScale + 0.5f);
}
/**
* 将sp值转换为px值,保证文字大小不变
*
* @param content
* @param spValus
* @return
*/
public static int sp2px(Context content, float spValus) {
final float fontScale = content.getResources().getDisplayMetrics().scaledDensity;
return (int) (spValus / fontScale + 0.5f);
}
}
同时,系统也提供了TypedValue类帮助我们转换:
/**
* dp2px
*/
protected int dp2px(int dp){
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources
().getDisplayMetrics());
}
/**
* sp2px
*/
protected int sp2px(int sp){
return (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp,getResources
().getDisplayMetrics());
}
Android绘图技巧
系统通过提供的Canvas对象来提供绘图方法。它提供了各种绘制图像的API,如drawPoint(点)、drawLine(线)、drawRect(矩形)、drawVertices(多边形)、drawArc(弧)、drawCircle(圆),等等。通过他们的名字,我们基本上可以打字了解他们的功能。
当然,Paint作为一个非常重要的元素,功能也是非常强大的,这里简单的列举一些他的属性和对应的功能。
setAntiAlias()//设置画笔的锯齿效果
setColor()//设置画笔的颜色
setARGB()//设置画笔的A、R、G、B值
setAlpha()//设置画笔的Alpha值
setTextSize()//设置字体的尺寸
setStyle()//设置画笔的风格(空心或实心)
setStrokeWidth()//设置空心边框的宽度
设置Paint的Style就可以画出空心或者实心的矩形:
paint.setStyle(Paint.Style.STROKE)//空心效果
paint.setStyle(Paint.Style.FILL)//实心效果
canvas.drawPoint(x, y, paint)//绘制点
canvas.drawLine(startX, startY ,endX, endY, paint)//绘制直线
canvas.drawLines(new float[]{startX1, startY1, endX1, endY1,……,startXn, startYn, endXn, endYn}, paint)//绘制多条直线
canvas.drawRect(left, top, right, bottom, paint)//绘制矩形
canvas.drawRoundRect(left, top, right, bottom, radiusX, radiusY, paint)//绘制圆角矩形
canvas.drawCircle(circleX, circleY, radius, paint)//绘制圆
canvas.drawOval(left, top, right, bottom, paint)//绘制椭圆
canvas.drawText(text, startX, startY, paint)//绘制文本
canvas.drawPosText(text, new float[]{X1,Y1,X2,Y2,……Xn,Yn}, paint)//在指定位置绘制文本
Path path = new Path();
path.moveTo(50, 50);
path.lineTo(100, 100);
path.lineTo(100, 300);
path.lineTo(300, 50);
canvas.drawPath(path, paint)//绘制路径
paint.setStyle(Paint.Style.STROKE);
drawArc(left, top, right,bottom, startAngle, sweepAngle, true, paint)//绘制空心扇形
paint.setStyle(Paint.Style.STROKE);
drawArc(left, top, right,bottom, startAngle, sweepAngle, false, paint)//绘制弧线
paint.setStyle(Paint.Style.FILL);
drawArc(left, top, right,bottom, startAngle, sweepAngle, true, paint)//绘制实心扇形
paint.setStyle(Paint.Style.FILL);
drawArc(left, top, right,bottom, startAngle, sweepAngle, false, paint)//绘制实心弧形
注意drawArc()的倒数第二个参数的布尔值,产生的效果。
Android XML绘图
xml在Android系统中可不仅仅是Java中的一个布局文件、配置列表。在Android开发者的手上,它甚至可以变成一张画、一幅图。Android的开发者给xml提供了几个强大的技能来帮助我们实现这一功能。
Bitmap
在xml中使用Bitmap非常简单:
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="@mipmap/ic_launcher">
</bitmap>
Shape
通过Shape可以在XML中绘制各种形状,下面展示Shape所支持的参数
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
//默认为rectangle
android:shape=["rectangle" | "oval" | "line" | "ring"] >
<corners //当shape="rectangle"时使用
//半径,会被后面的单个半径属性覆盖,默认为1dp
android:radius="integer"
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>
下面就是一个简单的通过渐变来实现的阴影效果:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<gradient
android:angle="45"
android:endColor="#805FBBFF"
android:startColor="#FF5DA2FF" />
<padding
android:bottom="7dp"
android:left="7dp"
android:right="7dp"
android:top="7dp" />
<corners android:radius="8dp" />
</shape>
运行结果:
Layer:
Layer是在Photoshop中非常常用的功能,在Android中,同样可以通过Layer来实现类似Photoshop中图层的概念:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<!--图片1-->
<item android:drawable="@drawable/ic_launcher"/>
<!--图片2-->
<item
android:bottom="10dp"
android:top="10dp"
android:right="10dp"
android:left="10dp"
android:drawable="@drawable/ic_launcher"
/>
</layer-list>
运行结果:
Selector:
Selector的作用在于帮助开发者实现静态绘图中的事件反馈,通过给不同的事件设置不同的图像,从而在程序中根据用户输入,返回不同的效果
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 默认时的背景图片-->
<item android:drawable="@mipmap/ic_launcher" />
<!-- 没有焦点时的背景图片-->
<item android:drawable="@mipmap/ic_launcher" android:state_window_focused="false" />
<!-- 非触摸模式下获得焦点并单击时的背景图片-->
<item android:drawable="@mipmap/ic_launcher" android:state_pressed="true"
android:state_window_focused="true" />
<!-- 触摸模式下单击时的背景图片-->
<item android:drawable="@mipmap/ic_launcher" android:state_focused="false" android:state_pressed="true" />
<!--选中时的图片背景-->
<item android:drawable="@mipmap/ic_launcher" android:state_selected="true" />
<!--获得焦点时的图片背景-->
<item android:drawable="@mipmap/ic_launcher" android:state_focused="true" />
</selector>
下面这个例子就展示在一个Selector中使用Shape作为它的Item的例子,实现一个具有点击反馈效果的、圆角矩形的Selector:
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true">
<shape android:shape="rectangle">
<!--填充的颜色-->
<solid android:color="#33444444" />
<!--设置按钮的四个角为弧形-->
<!--android:radius 弧形的半径-->
<corners android:radius="5dp" />
<!--padding:Button里面的文字与Button边界的间隔-->
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
<item>
<shape android:shape="rectangle">
<!--填充的颜色-->
<solid android:color="#FFFFFF" />
<!--设置按钮的四个角为弧形-->
<!--android:radius 弧形的半径-->
<corners android:radius="5dp" />
<!--padding:Button里面的文字与Button边界的间隔-->
<padding android:bottom="10dp" android:left="10dp" android:right="10dp" android:top="10dp" />
</shape>
</item>
</selector>
运行结果:
Canvas.save():保存画布。它的作用就是将之前的所有已绘制图像保存起来,让后续的操作就好像在一个新的图层上操作一样。
Canvas.restore():合并图层,它的作用是将我们在save()之后绘制的所有图像与save()之前的图像进行合并。
Canvas.translate():画布平移,或者坐标系的平移。
Canvas.roate():画布翻转,或坐标系的翻转。
通过一个仪表盘的案例来了解这几个方法,这个仪表盘可以分解成以下几个元素:
仪表盘:外面的大圆盘
刻度线:包含四个长的刻度线和其他短的刻度线
刻度值:包含长刻度线对应的大的刻度值和其他小的刻度值
指针:中间的指针,一粗一细两根指针
代码案例:
@Override
protected void onDraw(Canvas canvas) {
// 获取宽高参数
mWidth = getMeasuredWidth();
mHeight = getMeasuredHeight();
// 画外圆
Paint paintCircle = new Paint();
paintCircle.setStyle(Paint.Style.STROKE);
paintCircle.setAntiAlias(true);
paintCircle.setStrokeWidth(5);
canvas.drawCircle(mWidth / 2,
mHeight / 2, mWidth / 2, paintCircle);
// 画刻度
Paint painDegree = new Paint();
paintCircle.setStrokeWidth(3);
for (int i = 0; i < 24; i++) {
// 区分整点与非整点
if (i == 0 || i == 6 || i == 12 || i == 18) {
painDegree.setStrokeWidth(5);
painDegree.setTextSize(30);
canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,
mWidth / 2, mHeight / 2 - mWidth / 2 + 60,
painDegree);
String degree = String.valueOf(i);
canvas.drawText(degree,
mWidth / 2 - painDegree.measureText(degree) / 2,
mHeight / 2 - mWidth / 2 + 90,
painDegree);
} else {
painDegree.setStrokeWidth(3);
painDegree.setTextSize(15);
canvas.drawLine(mWidth / 2, mHeight / 2 - mWidth / 2,
mWidth / 2, mHeight / 2 - mWidth / 2 + 30,
painDegree);
String degree = String.valueOf(i);
canvas.drawText(degree,
mWidth / 2 - painDegree.measureText(degree) / 2,
mHeight / 2 - mWidth / 2 + 60,
painDegree);
}
// 通过旋转画布简化坐标运算
canvas.rotate(15, mWidth / 2, mHeight / 2);
}
// 画圆心
Paint paintPointer = new Paint();
paintPointer.setStrokeWidth(30);
canvas.drawPoint(mWidth / 2, mHeight / 2, paintPointer);
// 画指针
Paint paintHour = new Paint();
paintHour.setStrokeWidth(20);
Paint paintMinute = new Paint();
paintMinute.setStrokeWidth(10);
canvas.save();
canvas.translate(mWidth / 2, mHeight / 2);
canvas.drawLine(0, 0, 100, 100, paintHour);
canvas.drawLine(0, 0, 100, 200, paintMinute);
canvas.restore();
}
运行结果:
Layer图层
一张复杂的画可以由很多歌图层叠加起来,形成一个复杂的图像。在Android中,使用saveLayer()方法来创建一个图层,图层同样是基于栈的结构进行管理。
当saveLayerAlpha()方法的倒数第二个参数就是透明度参数
当透明度为127时,就是半透明
当透明度为255时,就是完全不透明
当透明度为127时,就是完全透明
代码案例:
public class MyLayer extends View {
private Paint mPaint;
private static final int LAYER_FLAGS = Canvas.MATRIX_SAVE_FLAG
| Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG
| Canvas.FULL_COLOR_LAYER_SAVE_FLAG
| Canvas.CLIP_TO_LAYER_SAVE_FLAG;
public MyLayer(Context context) {
super(context);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
}
@Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.WHITE);
mPaint.setColor(Color.BLUE);
canvas.drawCircle(150, 150, 100, mPaint);
canvas.saveLayerAlpha(0, 0, 400, 400, 0, LAYER_FLAGS);
mPaint.setColor(Color.RED);
canvas.drawCircle(200, 200, 100, mPaint);
canvas.restore();
}
}
运行结果: