自定义View-绘图机制与处理技巧

2024-09-05 16:18

本文主要是介绍自定义View-绘图机制与处理技巧,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

转载自:http://blog.csdn.net/dakaniu/article/details/78846972
仅作学习之用

1 单位转换
由于各种屏幕密度不同,导致同样像素大小的长度,在不同密度的屏幕上显示的长度不同,如下是各个密度值中的换算公式,
在mdpi 中 1dp = 1px,
在hdpi 中 1dp = 1.5px,
在xhdpi 中 1dp = 2px,
在xxhdpi 中 1dp = 3px,
其直接的换算公式是: ldpi:mdpi:hdpi:xhdpi:xxhpi = 3:4:6:8:12
转换代码如下:

 /*** 根据手机的分辨率从 dp 的单位 转成为 px(像素) */public static int dip2px(Context context, float dpValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (dpValue * scale + 0.5f);}/*** 根据手机的分辨率从 px(像素) 的单位 转成为 dp */public static int px2dip(Context context, float pxValue) {final float scale = context.getResources().getDisplayMetrics().density;return (int) (pxValue / scale + 0.5f);}/***  使用系统提供的TypedValue 进行转换*  */public static int dp2px(Context context,float dp){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,context.getResources().getDisplayMetrics());}public static int px2dp(Context context,float px){return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_PX,px,context.getResources().getDisplayMetrics());}

2 2D的绘图基础
系统通过提供Canvas对象来提供绘图的方法,比如

 // 画笔的属性以及对应功能 mPaint.setAlpha(8); //设置画笔的AlphamPaint.setStrokeWidth(5); //设置空心边框的宽度mPaint.setShader(new LinearGradient(0, 0, 400, 0, new int[]{Color.BLUE, 0x123321, Color.BLUE}, null, Shader.TileMode.CLAMP))mPaint.setTextSize(20);mPaint.setARGB(10,8,5,4); //设置颜色值,分别对应 透明度,红,绿,蓝的四个通道分量来决定像素点的颜色mPaint.setAntiAlias(true);//设置画笔的锯齿效果mPaint.setColor(Color.YELLOW);//设置画笔的颜色mPaint.setStyle(Paint.Style.STROKE);//设置画笔的风格:空心STROKE 或者实心FILLPath path = new Path(); //定义一条路径 path.moveTo(40,50);//移动到坐标 40 50path.lineTo(100,100);path.lineTo(100,50);path.lineTo(50,200);// 绘图的功能以及属性canvas.drawPath(path,mPaint);canvas.drawPosText("Hello",new float[]{100,100,//第一个字母的坐标 100,200,//第二个字母的坐标 ......100,300,100,400,100,500},mPaint);//在指定的位置绘制文本canvas.drawOval(100,200,400,300,mPaint);//绘制椭圆RectF rect = new RectF(50, 50, 200, 200);//定义一个矩形区域canvas.drawRoundRect(rect,30, //x轴的半径30, //y轴的半径mPaint);canvas.drawPoint(400,500,mPaint);//绘制点canvas.drawLine(200,300,500,600,mPaint);//绘制线canvas.drawArc(rect1, //弧线所使用的矩形区域大小0,  //开始角度90, //扫过的角度false, //是否使用中心mPaint);canvas.drawText("android",200,410,mPaint);//绘制文本canvas.drawRect(100,200,500,460,mPaint);//绘制矩形canvas.drawCircle(100,370,40,mPaint);//绘制圆形

3 XML绘图

3.1 Bitmap
在xml中的drawable/目录下可以创建Bitmap资源,举例,在drawable目录下创建bit_picture.xml并实现如下代码

<?xml version="1.0" encoding="utf-8"?>
<bitmapxmlns:android="http://schemas.android.com/apk/res/android"android:src="drawable/drawable_resource"android:antialias=["true" | "false"]android:dither=["true" | "false"]android:filter=["true" | "false"]android:gravity=["top" | "bottom" | "left" | "right" | "center_vertical" |"fill_vertical" | "center_horizontal" | "fill_horizontal" |"center" | "fill" | "clip_vertical" | "clip_horizontal"]android:mipMap=["true" | "false"]android:tileMode=["disabled" | "clamp" | "repeat" | "mirror"] />

通过以上代码,可以直接将图片转换成Bitmap 直接使用

    //xml调用<ImageViewandroid:layout_width="100dp"android:layout_weight="1"android:layout_height="100dp"android:src="@drawable/bit_picture"/>//java中调用getResources().getDrawable(R.drawable.bit_picture);

3.2 Shape
通过shape可以在xml中绘制各种形状,举例 在res/drawable文件夹下,新建一个文件,命名为:shape_demo.xml 代码如下

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"android:shape="rectangle"> // |oval|line|ring<!-- shape = rectangle时使用,表示边角的圆弧半径 半径默认是1dp--><corners android:radius="9dp"android:topLeftRadius="5dp"android:topRightRadius="2dp"android:bottomLeftRadius="3dp"android:bottomRightRadius="4dp"/><!-- 实心填充 --><solid android:color="#00000000" /><!-- 描边:一般大小都是1dp --><strokeandroid:width="1dp"android:color="#ff000000"android:dashGap="15dp"android:dashWidth="40dp"/><!-- 四周留出来的空白,和xml文件中的pad效果一样,对内起作用 --><paddingandroid:bottom="30dp"android:left="20dp"android:right="30dp"android:top="20dp" /><!-- 指定大小 --><size android:height="400dp"android:width="400dp"/><!-- 背景颜色渐变 --><gradientandroid:angle="45"android:endColor="#ff00ff00"android:startColor="#ff0000ff"android:type="linear"android:useLevel="true"android:centerColor="#611111"/>
</shape>
调用方法同3.1

3.3 Layer
Layer主要是用来实现图层效果的,举例 在res/drawable文件夹下,新建一个文件,命名为:layer_demo.xml

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item android:drawable="@drawable/arrow_right"/><item android:left="10.0dip"android:top="10.0dip"android:right="20.0dip"android:bottom="30.0dip"android:drawable="@drawable/arrow_right"/>
</layer-list>
调用方法同3.1

3.4 Selector
主要是实现静态绘图中的事件反馈,通过不同的事件设置不同的图像,在res/drawable文件夹下,新建一个文件,命名为:selector_demo.xml
举例1

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android"><!-- 默认时背景图片--><item android:drawable="@drawable/red"/><!-- 没有焦点时背景图片--><item android:state_window_focused="false"android:drawable="@drawable/dark_yellow"/><!-- 非触摸模式下获得焦点并单击时背景图片--><item android:state_focused="true"android:state_pressed="true"android:drawable="@drawable/bule"/><!-- 触摸模式下获得焦点并单击时背景图片--><item android:state_focused="false"android:state_pressed="true"android:drawable="@drawable/black"/><!-- 选中时背景图片--><item android:state_selected="true"android:drawable="@drawable/dark_bule"/><!-- 获取焦点时背景图片--><item android:state_focused="true"android:drawable="@drawable/deep_yellow"/>
</selector>
// 调用方法同3.1

举例2 在Selector中使用shape来作为它的item

    <item android:state_pressed="true" ><shape android:shape="rectangle"><solid android:color="#224444"></solid><corners android:radius="5dp"/><padding android:right="10dp"android:top="10dp"android:left="10dp"android:bottom="10dp"/></shape></item><item ><shape android:shape="rectangle"><solid android:color="#FFFFFF"/><corners android:radius="5dp"/><padding android:bottom="10dp"android:top="10dp"android:left="10dp"android:right="10dp"/></shape></item>

4 绘图技巧

4.1 Canvas
作为绘图的直接对象, 以下几个方法非常好用

Canvas.save() // 将之前的所有已绘制的图像保存起来,后续操作就像在另一个图层上一样
Canvas.restore();//将save之后的绘图与sava之前的绘图合并起来
Canvas.translate();//平移坐标系
Canvas.rotate();//旋转坐标系
举例, 画一个仪表盘

 public CanvasView(Context context, @Nullable AttributeSet attrs) {super(context, attrs);mPaint = new Paint();mPaint.setStyle(Paint.Style.STROKE);mPaint.setAntiAlias(true);mPaint.setStrokeWidth(10);mWidth = 600;mHeight = 800;}@Overrideprotected void onDraw(Canvas canvas) {canvas.drawCircle(mWidth/2,mHeight/2,mWidth/2,mPaint);// 以mWidth/2,mHeight/2为圆心,以mWidth/2为半径,用mPaint画一个圆Log.i("niuniu ", " init  drawCircle ");mPaint.setStrokeWidth(8);for(int i = 0;i<24;i++){String value = String.valueOf(i);if(i==0 || i==6 || i == 12 ||i==18){mPaint.setStrokeWidth(6);mPaint.setTextSize(35);canvas.drawLine(mWidth/2,mHeight/2-mWidth/2,mWidth/2,mHeight/2-mWidth/2+60,mPaint);canvas.drawText(value,mWidth/2-mPaint.measureText(value)/2,mHeight/2-mWidth/2+110,mPaint);}else {mPaint.setStrokeWidth(4);mPaint.setTextSize(20);canvas.drawLine(mWidth/2,mHeight/2-mWidth/2,mWidth/2,mHeight/2-mWidth/2+30,mPaint);canvas.drawText(value,mWidth/2-mPaint.measureText(value)/2,mHeight/2-mWidth/2+60,mPaint);}canvas.rotate(15,mWidth/2,mHeight/2); //以mWidth/2,mHeight/2为圆心,将坐标系旋转15°}Paint paint1 = new Paint();paint1.setStrokeWidth(10);Paint paint2 = new Paint();paint2.setStrokeWidth(8);canvas.save(); // 保存画笔以及上面的圆环canvas.translate(mWidth/2,mHeight/2);//平移到圆心 已圆心为坐标起点 0,0canvas.drawLine(0,0,100,80,paint1);canvas.drawLine(0,0,100,120,paint2);canvas.restore(); // 将所画的的指针与sava之前的圆环合并起来super.onDraw(canvas);}

4.2 Layer图层
图层是基于栈的结构进行管理的.android通过saveLayer(),saveLayerAlpha()将一个图层入栈,利用restore(),restoreToCount()将图层出栈,入栈时,后面的操作都会发生在这个图层上,出栈时,会把图像绘制在上层的cavas上.
举例

        mPaint.setStyle(Paint.Style.FILL);mPaint.setColor(Color.BLUE);canvas.drawColor(Color.WHITE);canvas.drawCircle(150,150,100,mPaint);canvas.saveLayerAlpha(0,0,400,400,127,Canvas.ALL_SAVE_FLAG);//入栈,将后面所画的红色圆都发生在该图层上mPaint.setColor(Color.RED);canvas.drawCircle(200,200,100,mPaint);canvas.restore();//出栈,将前面所有的图像都绘制在该canvas上

这篇关于自定义View-绘图机制与处理技巧的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1139449

相关文章

Java中的雪花算法Snowflake解析与实践技巧

《Java中的雪花算法Snowflake解析与实践技巧》本文解析了雪花算法的原理、Java实现及生产实践,涵盖ID结构、位运算技巧、时钟回拨处理、WorkerId分配等关键点,并探讨了百度UidGen... 目录一、雪花算法核心原理1.1 算法起源1.2 ID结构详解1.3 核心特性二、Java实现解析2.

MySQL中的锁机制详解之全局锁,表级锁,行级锁

《MySQL中的锁机制详解之全局锁,表级锁,行级锁》MySQL锁机制通过全局、表级、行级锁控制并发,保障数据一致性与隔离性,全局锁适用于全库备份,表级锁适合读多写少场景,行级锁(InnoDB)实现高并... 目录一、锁机制基础:从并发问题到锁分类1.1 并发访问的三大问题1.2 锁的核心作用1.3 锁粒度分

深度解析Python装饰器常见用法与进阶技巧

《深度解析Python装饰器常见用法与进阶技巧》Python装饰器(Decorator)是提升代码可读性与复用性的强大工具,本文将深入解析Python装饰器的原理,常见用法,进阶技巧与最佳实践,希望可... 目录装饰器的基本原理函数装饰器的常见用法带参数的装饰器类装饰器与方法装饰器装饰器的嵌套与组合进阶技巧

Java实现自定义table宽高的示例代码

《Java实现自定义table宽高的示例代码》在桌面应用、管理系统乃至报表工具中,表格(JTable)作为最常用的数据展示组件,不仅承载对数据的增删改查,还需要配合布局与视觉需求,而JavaSwing... 目录一、项目背景详细介绍二、项目需求详细介绍三、相关技术详细介绍四、实现思路详细介绍五、完整实现代码

一文详解Java Stream的sorted自定义排序

《一文详解JavaStream的sorted自定义排序》Javastream中的sorted方法是用于对流中的元素进行排序的方法,它可以接受一个comparator参数,用于指定排序规则,sorte... 目录一、sorted 操作的基础原理二、自定义排序的实现方式1. Comparator 接口的 Lam

Go语言代码格式化的技巧分享

《Go语言代码格式化的技巧分享》在Go语言的开发过程中,代码格式化是一个看似细微却至关重要的环节,良好的代码格式化不仅能提升代码的可读性,还能促进团队协作,减少因代码风格差异引发的问题,Go在代码格式... 目录一、Go 语言代码格式化的重要性二、Go 语言代码格式化工具:gofmt 与 go fmt(一)

Redis的持久化之RDB和AOF机制详解

《Redis的持久化之RDB和AOF机制详解》:本文主要介绍Redis的持久化之RDB和AOF机制,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录概述RDB(Redis Database)核心原理触发方式手动触发自动触发AOF(Append-Only File)核

如何在Mac上彻底删除Edge账户? 手动卸载Edge浏览器并清理残留文件技巧

《如何在Mac上彻底删除Edge账户?手动卸载Edge浏览器并清理残留文件技巧》Mac上的Edge账户里存了不少网站密码和个人信息,结果同事一不小心打开了,简直尴尬到爆炸,想要卸载edge浏览器并清... 如果你遇到 Microsoft Edge 浏览器运行迟缓、频繁崩溃或网页加载异常等问题,可以尝试多种方

PostgreSQL中MVCC 机制的实现

《PostgreSQL中MVCC机制的实现》本文主要介绍了PostgreSQL中MVCC机制的实现,通过多版本数据存储、快照隔离和事务ID管理实现高并发读写,具有一定的参考价值,感兴趣的可以了解一下... 目录一 MVCC 基本原理python1.1 MVCC 核心概念1.2 与传统锁机制对比二 Postg

qt5cored.dll报错怎么解决? 电脑qt5cored.dll文件丢失修复技巧

《qt5cored.dll报错怎么解决?电脑qt5cored.dll文件丢失修复技巧》在进行软件安装或运行程序时,有时会遇到由于找不到qt5core.dll,无法继续执行代码,这个问题可能是由于该文... 遇到qt5cored.dll文件错误时,可能会导致基于 Qt 开发的应用程序无法正常运行或启动。这种错