Android 自定义View消除锯齿实现图片旋转,添加边框及文字说明
先看看图片的效果,左边是原图,右边是旋转之后的图;
之所以把这个写出来是因为在一个项目中需要用到这样的效果,我试过用FrameLayout布局如上的画面,然后旋转FrameLayout,随之而来也就存在了一些问题——锯齿!
在网上搜索之后,有两种方法,一是利用Paint,二是利用Canvas;
(1)、paint.setAntiAlias(true);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
(2)、DrawFilter pfdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG|Paint.FILTER_BITMAP_FLAG);
canvas.setDrawFilter(pfdf);
而如果利用paint,或者canvas,需要从哪获取paint/canvas,这也是一个问题;
在实现的过程中,尝试过自定义FrameLayout下面的单个View{ImageView,TextView},但都以失败告终,失败的主要问题在于右图下边的文字描述无法和相片边框相对齐,而且用Matrix旋转背景之后背景大小改变,位置也不在最下边,所以就采用了单独实现一个View的方法,主要原因还是因为自身对Canvas绘图及Paint画笔不是很熟悉,所以导致的效率不高;
public class RotateTextImageView extends View {
PaintFlagsDrawFilter pfdf;
Paint paint;
Matrix matrix;
Bitmap bitmap;
int index = -1;
private int oriHeight;
private int oriWidth;
private int newHeight;
private int newWidth;
private int angle = 5;
protected Path path = new Path();
private float[] f = new float[8];
private int shawHeight = 20;
private int borderSize = 8;
Bitmap oriBitmap;
private String text = ""; public RotateTextImageView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
initCanvasInfo();
} public RotateTextImageView(Context context, AttributeSet attrs) {
super(context, attrs);
initCanvasInfo();
} public RotateTextImageView(Context context) {
super(context);
initCanvasInfo();
} /**
* 初始化Paint
*/
protected void initCanvasInfo() {
pfdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG
| Paint.FILTER_BITMAP_FLAG);
paint = new Paint();
paint.setAntiAlias(true);
matrix = new Matrix();
matrix.setRotate(5);
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
paint.reset();
// 消除锯齿
paint.setAntiAlias(true);
paint.setFlags(Paint.ANTI_ALIAS_FLAG);
canvas.setDrawFilter(pfdf);
canvas.drawBitmap(bitmap, 0, 0, paint);
newHeight = bitmap.getHeight();
newWidth = bitmap.getWidth();
calculatePoints();
// 添加阴影
path.reset();
path.moveTo(f[0], f[1]);
path.lineTo(f[2], f[3]);
path.lineTo(f[4], f[5]);
path.lineTo(f[6], f[7]);
path.close();
paint.setStyle(Paint.Style.FILL_AND_STROKE);
paint.setColor(Color.parseColor("#96ffffff"));
canvas.drawPath(path, paint);
// 添加字符
if (text != null && !text.equals("")) {
path.reset();
paint.setTextSize(18);
float width = paint.measureText(text);
path.moveTo((f[0] + f[2]) / 2, (f[1] + f[3]) / 2);
path.lineTo((f[4] + f[6]) / 2, (f[5] + f[7]) / 2);
paint.setColor(Color.parseColor("#2b2b2b"));
canvas.drawTextOnPath(text, path, (oriWidth - width) / 2, 3, paint);
}
layout(0, 0, newWidth, newHeight);
} /**
* 计算坐标值
*/
private void calculatePoints() {
double a = angle * Math.PI / 180;
BigDecimal height = new BigDecimal(oriHeight);
BigDecimal width = new BigDecimal(oriWidth);
BigDecimal cos = new BigDecimal(Math.cos(a));
BigDecimal tan = new BigDecimal(Math.tan(a));
f[0] = 0;
f[1] = height.multiply(cos).floatValue();
f[2] = tan.multiply(new BigDecimal(shawHeight)).floatValue();
f[3] = (new BigDecimal(f[1])).subtract(new BigDecimal(shawHeight))
.floatValue();
f[4] = width.multiply(cos).add(new BigDecimal(f[2])).floatValue();
f[5] = new BigDecimal(newHeight - shawHeight).floatValue();
f[6] = width.multiply(cos).floatValue();
f[7] = new BigDecimal(newHeight).floatValue();
} /**
* 设置图片
*
* @param bmp
*/
public void setBitmap(Bitmap bmp) {
oriBitmap = bmp;
matrix.reset();
matrix.setRotate(angle);
Bitmap bitmapF = addFrame(bmp);
oriHeight = bitmapF.getHeight();
oriWidth = bitmapF.getWidth();
bitmap = Bitmap.createBitmap(bitmapF, 0, 0, bitmapF.getWidth(),
bitmapF.getHeight(), matrix, true);
postInvalidate();
} /**
* 旋转角度
*
* @param angle
*/
public void setAngle(int angle) {
this.angle = angle;
setBitmap(oriBitmap);
} /**
* 设置底部阴影高度
*
* @param shawHeight
*/
public void setShawHeight(int shawHeight) {
this.shawHeight = shawHeight;
postInvalidate();
} /**
* 生成添加了白色边缘的图
*
* @param bmp
* @return
*/
protected Bitmap addFrame(Bitmap bmp) {
Bitmap bmpWithBorder = Bitmap.createBitmap(bmp.getWidth() + borderSize
* 2, bmp.getHeight() + borderSize * 2, bmp.getConfig());
Canvas canvas = new Canvas(bmpWithBorder);
canvas.drawColor(Color.WHITE);
canvas.drawBitmap(bmp, borderSize, borderSize, null);
return bmpWithBorder;
} /**
* 设置字符串
*
* @param text
*/
public void setText(String text) {
this.text = text;
postInvalidate();
} /**
* 获取字体高度
*/
protected int getFontHeight() {
FontMetrics fm = paint.getFontMetrics();
return (int) Math.ceil(fm.descent - fm.top) + 2;
}
}
代码解释:其实没有什么难的东西,只是一些数学运算,代码中每一个方法都有对应的功能注释。浮点型数组代表阴影层四个坐标点的八个坐标值,分别是左下、左上、右上、右下四个点,阴影层坐标计算也比较简单,但有点繁琐,就是把原图旋转之后再根据几何知识进行求解坐标!
每次重新设置角度,设置图片,都需要重新绘制图形-->postInvalidate();
View的使用
一、xml配置文件
<com.livingstone.RotateTextImageView
android:id="@+id/myview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minHeight="250dip"
android:minWidth="200dip"
android:paddingLeft="5dip" />
二、设置文字说明及角度、图片
RotateTextImageView myView = (RotateTextImageView) findViewById(R.id.myview);
myView.setShawHeight(50);
Bitmap bmp = BitmapFactory.decodeResource(getResources(),R.drawable.test1);
myView.setBitmap(bmp);
myView.setAngle(10);
myView.setText("这是一个测试");
Ex:获取字体宽度的两种方法
<1>.通过paint获取字体的Rect
Rect rect=newRect();
paint.getTextBounds("你好",0,1, rect);
Log.v("a:","height:"+rect.height()+"width:"+rect.width());
<2>.通过paint直接获取字体宽度
intwidth=(int)paint.measureText("你好",0,1);
Log.v("width:","width:"+width);
Android 自定义View消除锯齿实现图片旋转,添加边框及文字说明的更多相关文章
- 【朝花夕拾】Android自定义View篇之(三)Canvas绘制文字
前言 转载请声明,转自[https://www.cnblogs.com/andy-songwei/p/10968358.html],谢谢! 前面的文章中在介绍Canvas的时候,提到过后续单独讲Can ...
- Android绘图机制(二)——自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解
Android绘图机制(二)--自定义View绘制形, 圆形, 三角形, 扇形, 椭圆, 曲线,文字和图片的坐标讲解 我们要想画好一些炫酷的View,首先我们得知道怎么去画一些基础的图案,比如矩形,圆 ...
- Android 自定义 view(三)—— onDraw 方法理解
前言: 上一篇已经介绍了用自己定义的属性怎么简单定义一个view<Android 自定义view(二) -- attr 使用>,那么接下来我们继续深究自定义view,下一步将要去简单理解自 ...
- [原] Android 自定义View步骤
例子如下:Android 自定义View 密码框 例子 1 良好的自定义View 易用,标准,开放. 一个设计良好的自定义view和其他设计良好的类很像.封装了某个具有易用性接口的功能组合,这些功能能 ...
- Android自定义View
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/24252901 很多的Android入门程序猿来说对于Android自定义View ...
- android自定义View之仿通讯录侧边栏滑动,实现A-Z字母检索
我们的手机通讯录一般都有这样的效果,如下图: OK,这种效果大家都见得多了,基本上所有的android手机通讯录都有这样的效果.那我们今天就来看看这个效果该怎么实现. 一.概述 1.页面功能分析 整体 ...
- Android自定义View和控件之一-定制属于自己的UI
照例,拿来主义.我的学习是基于下面的三篇blog.前两是基本的流程,第三篇里有比较细致的绘制相关的属性.第4篇介绍了如何减少布局层次来提高效率. 1. 教你搞定Android自定义View 2. 教你 ...
- android 自定义view 前的基础知识
本篇文章是自己自学自定义view前的准备,具体参考资料来自 Android LayoutInflater原理分析,带你一步步深入了解View(一) Android视图绘制流程完全解析,带你一步步深入了 ...
- 【Android - 自定义View】之自定义View浅析
1.概述 Android自定义View / ViewGroup的步骤大致如下: 1) 自定义属性: 2) 选择和设置构造方法: 3) 重写onMeasure()方法: 4) 重写onDraw()方法: ...
随机推荐
- 测试FlowTable
1.确定openvswitch模块加载#lsmod |grep oepnvswitch#/sbin/modprobe openvswitch 2.启动配置:1)默认配置rm -f /usr/local ...
- 电子质检报告系统v3.8
南京转折点信息是太阳升软件全资子公司,一家专业从事医药软件开发的医药软件企业. 根据新版GSP支持医药企业药品质检报告电子化的要求及国家药监局的解释:供货商提供的加盖企业电子印章的电子药品检验报告与纸 ...
- 一种精准monkey测试的方法
WeTest 导读 相信大家都知道移动端应用的monkey测试吧,不知你们有没有为monkey测试的太过于随机性的特性有过困扰,至少在我们这种界面控件较少且控件位置较偏的app的使用上其测试有效性大打 ...
- GIt学习第一天之安装和版本库创建
搬运自 ‘廖雪峰的官方网站’ 1.git安装 官网下载地址:https://git-scm.com/download/win 百度网盘下载地址:https://pan.baidu.com/s/1k ...
- 监控系统cpu相关统计信息
背景:需要测试监控各个操作系统平台机器上的cpu相关的各种统计信息 为了方便测试,我写了一个比较通用的shell脚本,目前可以兼容Redhat6+,Redhat7+,其他操作系统没测,可以实时监控机器 ...
- .NET中发送邮件的实现
.NET中发送邮件 注意: 1.引用下列命名空间: using System.Net; using System.Net.Mail; 2.确保你使用的发送邮件的邮箱开启了stamp服务等. /// & ...
- CSP201312-2:ISBN号码
引言:CSP(http://www.cspro.org/lead/application/ccf/login.jsp)是由中国计算机学会(CCF)发起的"计算机职业资格认证"考试, ...
- javaee开发工具及环境配置过程
在配置javaee开发环境的过程中遇到过很多问题,在此系统的整理一下我之前的配置过程 注:配置过程学习自<JSP&Servlet学习笔记(第二版)>详细过程可以阅读此书.在文章的最 ...
- 【第二章】Shell 变量
一.什么是变量? 变量就是一个固定的字符串(也可以是字符.数字的组合)代替更多.更复杂的内容,该内容可能是变量.路径.字符串等其他内容. 变量就是程序中保存用户数据的一块内存空间,而变量名就是这块内存 ...
- 技本功丨知否知否,Redux源码竟如此意味深长(下集)
上集回顾 Redux是如何使用的?首先再来回顾一下这个使用demo(谁让这段代码完整地展示了redux的使用) 如果有小伙伴对这段代码不是很理解的话,建议先去学习Redux的使用再来看这篇源码,这样更 ...