android 屏幕密度350 是xh xxh,Android-绘图机制总结-程序员宅基地

技术标签: android 屏幕密度350 是xh xxh  

这里你将了解到以下内容:Android屏幕相关知识

Android绘图技巧

Android图像处理技巧

SurfaceView的使用

1、屏幕尺寸信息

1.屏幕参数

一块屏幕通常具备以下的几个参数

屏幕大小:

指屏幕对角线的长度,通常用寸来表示,例如4.7寸,5.5寸

分辨率:

分辨率是指实际屏幕的像素点个数,例如720X1280就是指屏幕的分辨率,宽有720个像素点,高有1280个像素点

PPI

每英寸像素又称为DPI,他是由对角线的的像素点数除以屏幕的大小所得,通常有400PPI就已经很6了

2.系统屏幕密度

AAffA0nNPuCLAAAAAElFTkSuQmCC

3.独立像素密度dp

这是由于各种屏幕密度的不同,导致同样像素大小的长度,在不同密度的屏幕上显示长度不同,因此相同长度的屏幕,高密度的屏幕包含更多的像素点,在安卓系统中使用mdpi密度值为160的屏幕作为标准,在这个屏幕上,1px = 1dp,其他屏幕则可以通过比例进行换算,例如同样是100dp的长度,mdpi中为100px,而在hdpi中为150,我们也可以得出在各个密度值中的换算公式,在mdpi中 1dp = 1px, 在hdpi中, 1dp = 1.5px,在xhdpi中,1dp = 2px,在xxhdpi中1dp = 3px,由此可见,我们换算公式l:m:h:xh:xxh = 3:4:6:8:12

4.换算公式

到我历史博客即可;

系统提供TypedValue帮助我们转换/**

* dp2px

* @param dp

* @return

*/

protected int dp2px(int dp){        return (int)

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources()

.getDisplayMetrics());

}    /**

* sp2px

* @param dp

* @return

*/

protected int sp2px(int sp){        return (int)

TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP,sp

,getResources().getDisplayMetrics());

}

二、绘图基础

1.Paint

作为一个非常重要的元素,功能也是很强大的以下是一些基础的属性和对应的功能setAntiAlias(); //设置画笔的锯齿效果

setColor(); //设置画笔的颜色

setARGB(); //设置画笔的A、R、G、B值

setAlpha(); //设置画笔的Alpha值

setTextSize(); //设置字体的尺寸

setStyle(); //设置画笔的风格(空心或实心)

setStrokeWidth(); //设置空心边框的宽度

getColor(); //获取画笔的颜色

接下来实现一个Demo

代码:paint1 = new Paint();

paint1.setColor(Color.BLUE);

paint1.setAntiAlias(true);        //空心

paint1.setStyle(Paint.Style.STROKE);

paint2 = new Paint();

paint2.setColor(Color.GREEN);        //实心

paint2.setStyle(Paint.Style.FILL);

效果图:

AAffA0nNPuCLAAAAAElFTkSuQmCC

2.Canvas

四种常用的方法canvas.save();          //保存画布

canvas.restore();       //合并图层

canvas.translate(x,y);  //画布平移到x,y处

canvas.rotate(翻转的角度,圆心的X坐标,圆心的Y坐标);//画布翻转

DrawPoint 绘制点

canvas.drawPoint(x,y,paint);

DrawLine绘制直线

canvas.drawLine(startX,startY,endX,endY,paint);

绘制多条直线:

float[] pts1={startX1,startY1,endX1,endY1...startXn,startYnendXn,endYn};

canvas.drawLines(pts,paint);

DrawRect绘制矩形

canvas.drawRect(left,top,right,button,paint);

DrawRoundRect绘制圆角矩形

canvas.drawRect(left,top,right,button,radiusX,radiusY,paint);

DrawCircle绘制圆

canvas.drawCircle(圆心X坐标,Y坐标,半径,paint1);

DrawArc绘制弧形/扇形

两种写法:

第一种:canvas.drawArc(left,top,right,button, startAngle, sweepAngle, useCenter, paint2);

第二种:

RectF rectF = new RectF(left,top,right,button);

canvas.drawArc(rectF, 0, 100, true, paint2);

在这里rectF代表的是圆弧外轮扩矩形区域

startAngle表示起始的角度 (以X轴正方向为0度顺时针开始算)

sweepAngle为圆弧扫过的角度

useCenter设置为true的时候显示圆心

AAffA0nNPuCLAAAAAElFTkSuQmCC

DrawPath绘制路径

绘制多边形//实例化路径

Path path = new Path();

path.moveTo(80, 200);// 此点为多边形的起点

path.lineTo(120, 250);

path.lineTo(80, 250);

path.lineTo(300, 300);        //path.close(); // 使这些点构成封闭的多边形

canvas.drawPath(path, paint1);

绘制曲线:Path path=new Path();

path.moveTo(100, 320);          //设置Path的起点

path.quadTo(160,320,180,410);   //设置路径点和终点

canvas.drawPath(path, paint1);

AAffA0nNPuCLAAAAAElFTkSuQmCC

DrawOval绘制椭圆

DrawOval(left,top,right,button,paint);RectF rectF = new RectF(210,100,250,130) ;

canvas.drawOval(rectF, paint2) ;

DrawText绘制文本

canvas.drawText("自定义文本",X坐标,Y坐标,paint);

绘制不同位置的文本信息float [] pts=new float[]{100,100,200,200,300,300,400,400,500,500,600,600};

canvas.drawPosText("text",pts,paint1);

效果图:

AAffA0nNPuCLAAAAAElFTkSuQmCC

三、XML绘图

1、Bitmap

在XML中使用Bitmap很简单<?xml  version="1.0" encoding="utf-8"?>

android:class="lazyload" src="https://img-blog.csdnimg.cn/2022010618181314842.png" data-original="@mipmap/ic_launcher">

通过这样引用图片就可以将图片直接转化成Bitmap让我们在程序中使用

2、Shape

通过Shape可以绘制各种图形,下面展示一下shape的参数<?xml  version="1.0" encoding="utf-8"?>

android:shape="rectangle">

android:bottomLeftRadius="1dp"

android:bottomRightRadius="1dp"

android:radius="1dp"

android:topLeftRadius="1dp"

android:topRightRadius="1dp" />

android:angle="1dp"

android:centerColor="@color/colorAccent"

android:centerX="1dp"

android:centerY="1dp"

android:gradientRadius="1dp"

android:startColor="@color/colorAccent"

android:type="linear"

android:useLevel="true" />

android:bottom="1dp"

android:left="1dp"

android:right="1dp"

android:top="1dp" />

android:width="1dp"

android:height="1dp" />

android:width="1dp"

android:color="@color/colorAccent" />

android:dashWidth= "1dp"    

android:dashGap= "1dp"

3.Layer

Layer是在PhotoShop中是非常常用的功能,在Android中,我们同样可以实现图层的效果<?xml  version="1.0" encoding="utf-8"?>

android:bottom="10dp"

android:top="10dp"

android:right="10dp"

android:left="10dp"

android:drawable="@mipmap/ic_launcher"

/>

4.Selector

Selector的作用是帮助开发者实现静态View的反馈,通过设置不同的属性呈现不同的效果<?xml  version="1.0" encoding="utf-8"?>

这一方法可以帮助开发者迅速制作View的反馈,通过配置不同的触发事件,selector会自动选中不同的图片,特别是自定义button的时候,而我们不再使用原生单调的背景,而是使用selector特别制作的背景,就能完美实现触摸反馈了

通常情况下,上面提到的这些方法都可以共同实现,下面这个例子就展示了在一个selector中使用shape作为他的item的例子,实现一个具体点击反馈效果的,圆角矩形的selector,代码如下<?xml  version="1.0" encoding="utf-8"?>

AAffA0nNPuCLAAAAAElFTkSuQmCC

四、Android绘图技巧

在学完Android的基本绘图之后我们来讲解一下常用的绘图技巧

1、CanvasCanvas.save()

Canvas.restore()

Canvas.translate()

Canvas.roate()

首先,我们来看一下前面两个方法

在讲解这两个方法之前,首先来了解一下Android绘图的坐标体系,这个其实这个前面已经讲了,这里不赘述,而Canvas.save()这个方法,从字面上的意思可以理解为保存画布,他的作用就是讲之前的图像保存起来,让后续的操作能像在新的画布一样操作,这跟PS的图层基本差不多

而Canvas.restore()这个方法,则可以理解为合并图层,,就是讲之前保存下来的东西合并.

8

而后面两个方法尼?从字母上理解画布平移或者旋转,但是把他理解为坐标旋转更加形象,前面说了,我们绘制的时候默认坐标点事左上角的起始点,那么我们调用translate(x,y)之后,则将原点(0,0)移动到(x,y)之后的所有绘图都是在这一点上执行的

2.Layer图层

Android中的绘图API,很大程度上都来自绘图的API,特别是借鉴了很多PS的原理,比如图层的概念,相信看过图层的也都知道是个什么样的,我们画个图来分析一下

Android通过saveLayer()方法,saveLayerAlpha()将一个图层入栈,使用restore()方法,restoreToCount()方法将一个图层出栈,入栈的时候,后面的所有才做都是发生在这个图层上的,而出栈的时候,则会把图层绘制在上层Canvas上,我们仿照API Demo来@Override

protected void onDraw(Canvas canvas) {        // TODO Auto-generated method stub

super.onDraw(canvas);

canvas.drawColor(Color.WHITE);

mPaint.setColor(Color.BLUE);

canvas.drawCircle(150, 150, 100, mPaint);

canvas.saveLayerAlpha(0, 0,400,400,127,LAYER_TYPE_NONE);

mPaint.setColor(Color.RED);

canvas.drawCircle(200, 200, 100, mPaint);

canvas.restore();

}

当绘制两个相交的圆时,就是图层

接下来将图层后面的透明度设置成0-255不同值

我们分别演示 127 255 0三个

AAffA0nNPuCLAAAAAElFTkSuQmCC

五.Android图像处理之画笔特效处理

不管是在我们的世界里,还是在Android的世界里,要想画出好的图片,就必须账务画笔的特效,今天我们就来玩玩这个Paint的特殊Get

1.PorterDuffXfermode

AAffA0nNPuCLAAAAAElFTkSuQmCC

途中列举了16种PorterDuffXfermode,有点像数学中的集合,主要是一个混合显示模式

这里注意了,PorterDuffXfermode设置两个图层交集区域的显示方法des是先画的图像,src是后画的

当然,这些模式也不是经常的用到,用到最多的事,使用一张图片作为另一张图片的遮罩,通过控制遮罩层的图形,来控制下面被遮罩的显示效果,其中最常用的就是通过DST_IN.SRC_IN模式来实现将一个矩形变成圆角图片的效果,我们这里来实现一下mBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.nice);

mOut = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);

Canvas canvas = new Canvas(mOut);

mPaint = new Paint();

mPaint.setAntiAlias(true);

canvas.drawRoundRect(0, 0, mBitmap.getWidth(), mBitmap.getHeight(), 80, 80, mPaint);

mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN));

canvas.drawBitmap(mBitmap,0,0,mPaint);

下面我们来做一个比较类似于刮刮卡的效果,其实效果就是两张图片,上面那张一刮就显示下面的那张看,这个效果同样我们可以使用PorterDuffXfermode去实现,我们首先要做的就是初始化一些数据

AAffA0nNPuCLAAAAAElFTkSuQmCC

AAffA0nNPuCLAAAAAElFTkSuQmCCpublic class PlayView extends View {    private Bitmap mBgBitmap, mFgBitmap;    private Paint mPaint;    private Canvas mCanvas;    private Path mPath;    /**

* 构造方法

*

* @param context

* @param attrs

*/

public PlayView(Context context, 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.setStrokeJoin(Paint.Join.ROUND);//让笔更加圆滑一些

mPaint.setStrokeWidth(50);

mPaint.setStrokeCap(Paint.Cap.ROUND);//让笔更加圆滑一些

mPath = new Path();

mBgBitmap = BitmapFactory.decodeResource(getResources(), R.drawable.nice);

mFgBitmap = Bitmap.createBitmap(mBgBitmap.getWidth(), mBgBitmap.getHeight(), Bitmap.Config.ARGB_8888);

mCanvas = new Canvas(mFgBitmap);

mCanvas.drawColor(Color.GRAY);

}    /**

* 触摸事件

*

* @param event

* @return

*/

@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_UP:

mPath.lineTo(event.getX(), event.getY());                break;

}

mCanvas.drawPath(mPath, mPaint);

invalidate();        return true;

}    @Override

protected void onDraw(Canvas canvas) {

canvas.drawBitmap(mBgBitmap, 0, 0, null);

canvas.drawBitmap(mFgBitmap, 0, 0, null);

}

}

2,Shader

Shader又被称为着色器。渲染器,它可以实现渲染,渐变等效果,Android中的Shader包括以下几种

BitmapShader:位图Shader

LinearGradient:线性Shader

RadialGradient:光束Shader

SweepGradient:梯形Shader

ComposeShader:混合Shader

除了第一个之外,其他的都是比较正常的,实现了名副其实的渐变,渲染效果,而与其他Shader的效果不同的是,BitmapShader所产生的是一个图像,有点类似PS里面的图像填充,他的作用是通过Paint对画布进行制定bitmap的填充,填充式有一下几个模式供选择。CLAMP拉伸——拉伸的是图片最后的哪一个像素,不断重复

REPEAT重复——横向,纵向不断重复

MIRROR镜像——横向不断翻转重复,纵向不断翻转重复

这几种模式的含义都非常好理解的,与字面意识基本相同,这里最常用的是CLAMP拉伸模式,虽然他会拉伸最后一个像素,但是只要将突破设置成一个固定的像素,是可以避免的,

六.View之孪生兄弟---SurfaceView

Android系统提供了VieW进行绘图处理, vieW可以满足大部分的绘图需求,但在某些时却也有些心有余而力不足,特别是在进行一些开发的时候。 我们知道,VieW通过刷新来视图, Android系统通过发出VSYNC信号来进行屏幕的重绘, 刷新的间隔时间为I6ms。在16ms内View完成了你所需要执行的所有操作,那么用户在视觉上, 就不会产生卡顿的感觉:而如果执行的操作逻辑太多,特别是需要频繁刷新的界面上,例如游戏界面,那么就塞主线程,从而导致画面卡顿,很多时候,在自定义VieW的Log中经常会看见如下示的警告Skipped 47 frames! The application may be doing too much work on its main thread

这些警告的产生,很多情况下就是因为在绘制过程中, 处理逻辑太多造成的为了避免这一问题的产生一 Android系统提供了surfacevicW组件来解决这个问题,可以说是VieW的孪生兄弟,但它与View还是有所不同的,它们的区别主要体现View主要用于自动更新的情况下,而surfaceVicw主要适用于被动更新,例如频繁刷新

View在主线程中刷新,而surfaceView通常会通过一 个子线程来进行页面刷新。

View在绘制的时候没有双缓冲机制,而surfaceVicw在底层实现机制中就已经实现了双缓冲机制;

总结起来,如果你的自定义View需要频繁刷新,或者刷新时数据处理量比较大,那么你就可以考虑使用surfaceVicw取代View了

1.surfaceView的使用

一套模板代码:public class SurfaView extends SurfaceView implements SurfaceHolder.Callback, Runnable {    //SurfaceHolder

private SurfaceHolder mHolder;    //用于绘制的Canvas

private Canvas mCanvas;    //子线程标志位

private boolean mIsDrawing;    /**

* 构造方法

*

* @param context

* @param attrs

*/

public SurfaView(Context context, AttributeSet attrs) {        super(context, attrs);

mHolder = getHolder();

mHolder.addCallback(this);

setFocusable(true);

setFocusableInTouchMode(true);

setKeepScreenOn(true);

}    @Override

public void surfaceCreated(SurfaceHolder holder) {

mIsDrawing = true;        new Thread(this).start();

}    @Override

public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}    @Override

public void surfaceDestroyed(SurfaceHolder holder) {

mIsDrawing = false;

}    @Override

public void run() {        while (mIsDrawing) {

draw();      //在这里不断绘制要绘制的内容

}

}    private void draw() {        try {

mCanvas = mHolder.lockCanvas();            //这里要不断地用mCanvas方法绘制

} catch (Exception e) {

} finally {            if (mCanvas != null) {                //提交

mHolder.unlockCanvasAndPost(mCanvas);

}

}

}

}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_31659249/article/details/117775826

智能推荐

服务器ssd硬盘的读写速度,SSD完胜HDD:读写速度和IOPS对比-程序员宅基地

文章浏览阅读6k次。04SSD完胜HDD:读写速度和IOPS对比在HDD机械硬盘时代,读写速度和寻道时间是最重要的两项指标,目前HDD的读写速度最快能达到225MB/秒、读写寻道能力在数秒时间。SSD将HDD的寻道时间直接无视,因为它是毫秒级别。对于SSD来说,它的读写速度和随机读写能力是至关重要的两项指标。下面进行①读写速度和②随机读写能力对比:注:小编自用主机,将此块SSD作为“C区系统盘”使用。这和以往小编将S..._读密集型ssd iops

MySQL数据库---基础学习笔记_alter table t_person change sal salary int;-程序员宅基地

文章浏览阅读144次。###数据库之前学习的通过IO流操作文件的形式对数据进行增删改查 存在很多弊端效率低一般只能保存小量数据只能保存文本数据- 什么是DBMS: DataBaseManagementSystem,数据库管理系统(数据库管理软件),作用就是负责对数据进行增删改查的软件,常见的DBMS: MySQL、Oracle、DB2、SQLServer、SQLite等- 数据库分类:1. 关系型数据..._alter table t_person change sal salary int;

向量vector(4)_vector4(200, 0, 0, 255);-程序员宅基地

文章浏览阅读703次。目录 1.6.4 查找1.6.5 二分查找(版本A)1.6.5.1 减而治之1.6.5.2 实例和复杂度1.6.5.3 查找长度1.6.6 Fibonacci查找1.6.6.1 递推方程1.6.6.2 黄金分割1.6.7 二分查找(版本B)1.6.8 二分查找(版本C)1.6.4 查找template &lt;typena..._vector4(200, 0, 0, 255);

java 转 .net_转:将java库转换为.net库-程序员宅基地

文章浏览阅读376次。动机:充分利用java阵营众多的类库工具:IKVM――把java bytecode转换成IL程序,并提供大部分J2SE 1.4类的.net实现(IKVM.GNU.Classpath.dll)winrar――提取jar,打包jarJava IDE(可选)――阅读源代码,浏览类之间的关系,我用的是eclipse反编译工具(可选)――没源代码时用,主要也是浏览类与类之间的关系,java反编译我用的是DJ..._java类转.net

PostgreSQL 10.0 preview sharding增强 - 支持异步, 多节点并行-程序员宅基地

文章浏览阅读112次。标签PostgreSQL , 10.0 , sharding 增强背景PostgreSQL 10.0的sharding增强,比如聚合函数的下推算一个。现在又带来了一个核武器级别的增强,postgres_fdw的异步化调用。为什么说是核武器级别的呢,比如你有16个sharding节点(对应postgres_fdw的16个库),10.0以前,如..._postgresql sharding

系统改造二_系统改造主要影响-程序员宅基地

文章浏览阅读259次。系统改造二思路想法思路通过系统改造一,我再次了解和对比了下相应的概念。了解了商品和SPU和SKU的关系。但是我要改造的是wms系统,有必要全部的了解下吗?不论说什么还是要先将概念了解透彻。SKU:通常表示颜色规格和款式,是物理上不可分割的最小存货单位,专业的物流术语是“货格“。同时具有相对的概念,在使用时要根据不同的业态和不同的管理模式来处理,比如:一箱香烟是50条,一条里10盒,一盒里是20支。这些单位就需要根据不同的需要来设定SKU.比如仓储批发大卖场,一定是按照一箱来设定的。普通卖场是按条来_系统改造主要影响

随便推点

Ceph对象存储安装部署及验证-程序员宅基地

文章浏览阅读292次。今天来玩下Ceph的对象存储,在开始之前呢,先扯会闲篇,我觉得生活中处处是非结构化数据,最简单的举例,下面两个行业,一个是直播,一个是摄影。现在直播行业这么火,不夸张的说甚至每天都会产生一个直播软件。不单单是视频流媒体行业,还有现在非常流行的云摄影,什么是云摄影呢?相信经常参会的朋友应该知道,有些现场拍的照片立马就可以发出来,很是方便,相信以后肯定会火起来。有些细心的朋友应该会看到每张照片都会有水..._应用配置对象存储,怎么检查是否连接成功

cmd设置mysql初始密码,mysql安装忘记初始密码简单有效的解决方法-程序员宅基地

文章浏览阅读576次。在安装MySQL的时候会给定一个初始的密码,而这个初始的密码特别恶心人一堆大小写特殊字符。记住是不可能的,如果之前没有过安装经历的小伙伴第一次自主安装十有八九不会去注意这个。​ 本次教程使用的MySQL版本是8.0.19版本。8版本的应该都可以使用这个方法,其他版本的不清楚,可以试一下。全程熟练的话两分钟搞定。首先上教程。直接操作吧,前面的发现都是废话1.先要确保my.ini文件里面的datadi..._cmd设置mysql初始密码

appserv写php,怎么用appserv+eclipse开发PHP环境-程序员宅基地

文章浏览阅读97次。安装xampp现在最新的版本是1.7.3,去下载下来,安装即可,这步很简单。下载eclipse去网上下载一个 PDT 2.1 SR-1 All In Ones 版本的eclipse,下载Xdebug我用Xdebug来调试PHP,可以在这里下载Xdebug下载页面把下载下来后的Xdebug,放到C:\xampp\php\ext\目录下,当然也可以选其他目录配置PHP.ini在PHP.ini最下方,加..._appserver如何编辑php

uitableview加载MySQL数据_UITableView 上拉刷新 加载数据问题?-程序员宅基地

文章浏览阅读48次。@property (strong, nonatomic) NSMutableArary *listArray;#pragma mark - TableView datasource- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{tableV..._uitableview上拉刷新加载数据

python-字符串作为代码执行(exec、eval、locals、compile)_python将字符串作为代码执行-程序员宅基地

文章浏览阅读1.7w次,点赞16次,收藏43次。字符串作为代码执行的方法:1、eval()构造器:eval(source, globals=None, locals=None, /)说明:输入一个【python表达式或code对象】参与计算。用于恶意攻击,窥视:再看下eval的参数globals和locals参数的用法,看栗子:一幕了然,局部变量空间和全局变量空间的优先级的先后顺序~2、e..._python将字符串作为代码执行

推荐文章

热门文章

相关标签