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()方法: ...
随机推荐
- Spring Boot 2.x Redis多数据源配置(jedis,lettuce)
Spring Boot 2.x Redis多数据源配置(jedis,lettuce) 96 不敢预言的预言家 0.1 2018.11.13 14:22* 字数 65 阅读 727评论 0喜欢 2 多数 ...
- linux_fdisk命令详解,关于分区的详解
这篇文章写的十分详细,特别的好 fdisk -l 可以列出所有的分区,包括没有挂上的分区和usb设备.我一般用这个来查找需要挂载的分区的位置,比如挂上u盘. 实例解说Linux中fdisk分区使用方法 ...
- Andorid自定义attr的各种坑
本文来自网易云社区 作者:孙有军 在开发Andorid应用程序中,经常会自定义View来实现各种各样炫酷的效果,在实现这吊炸天效果的同时,我们往往会定义很多attr属性,这样就可以在XML中配置我们想 ...
- iOS - Foundation相关
1.NSString A.创建的方式: stringWithFormat:格式化字符串 ,创建字符串对象在堆区域 @"jack& ...
- 「日常训练」 Yukari's Birthday(ZOJ-3665)
题意与分析 二分题.考虑到n的范围是\(10^{12}\),注意到等比公式\(S=a_1\frac{1-q^n}{1-q} (q\ne 1)\),可以看出,不论q有多大(1除外,这个时候\(r=1,k ...
- 感觉总结了一切python常见知识点,可直接运行版本
#encoding=utf-8#http://python.jobbole.com/85231/#作用域a=1def A(a): a=2 print 'A:',a def B(): print 'B: ...
- 【Extremely Basic Words for Listening】word list
[Extremely Basic Words for Listening]word list updated continuously recite count: 0 careless exercis ...
- linux学习总结----mongoDB总结
dbhelper.py 用户登录和注册(加密算法) 加密导包 import hashlib 或者使用Md5 加密 MongoDB ->JSON service mysql start servi ...
- 换抵挡装置 (Kickdown,ACM/ICPC NEERC 2006,UVa1588
题目描述:算法竞赛入门经典习题3-11 题目思路:1.两长条移动匹配 2.上下调换,取小者 #include <stdio.h> #include <string.h> int ...
- 【转】: 探索Lua5.2内部实现:虚拟机指令(1) 概述
Lua一直把虚拟机执行代码的效率作为一个非常重要的设计目标.而采用什么样的指令系统的对于虚拟机的执行效率来说至关重要. Stack based vs Register based VM 根据指令获取操 ...