自定义界面上绘制Text,可通过拖动控制文字大小及其位置
最近项目上有个需求,需要在一块区域中显示文字,这块区域可以拖动,也可以通过拖拽右下角来改变大小,里面的文字大小要根据区域的大小进行自适应。刚开始觉得这个需求不难,只需要一个TextView就能实现。
后来发现虽然使用TextView可以很容易实现拖动与缩放的功能,但是文字大小不会改变。在求助github的时候发现了AutoFitTextView控件,参考https://github.com/AndroidDeveloperLB/AutoFitTextView,但是使用的时候,每一次需要根据区域的大小重新创建一个TextView。想想这样对性能消耗太大,不如自己编写一个。
程序常量与变量
具体含义见注释
//事件类型, 0代表移动, 1代表缩放
private static final int MOVEVIEW = 0;
private static final int DRAGVIEW = 1;
//背景画笔
private Paint backPaint;
//文字画笔
private TextPaint textPaint;
//背景区域
private Rect backRect;
//文字测量出的区域
private Rect textMeasureRect;
//事件类型
private int eventType;
//手指点击的位置
private int lastX, lastY;
//背景与文字的长宽
private int rectWidth, rectHeight, textWidth, textHeight;
//字体大小
private int textSize;
private String text = "这是一个测试程序abcdefg!@#$%^&";
构造函数
因为是将文字绘制在View上,所以在构造函数里生成了一个背景画笔和文字画笔,同时生成背景的矩阵。
public MyDrawView(Context context, AttributeSet attrs) {
super(context, attrs);
backPaint = new Paint(); //设置一个笔刷大小是3的黄色的画笔
backPaint.setColor(Color.YELLOW);
backPaint.setStrokeJoin(Paint.Join.ROUND);
backPaint.setStrokeCap(Paint.Cap.ROUND);
backPaint.setStrokeWidth(3);
textPaint = new TextPaint();
textPaint.setColor(Color.BLUE);
textPaint.setTextSize(100);
backRect = new Rect(100, 100, 400, 200);
textMeasureRect = new Rect();
}
Touch事件
在TouchEvent中,手指按下时,根据手指的点击位置,判断是拖动事件还是缩放事件,并设置eventType。
根据eventType,在手指拖动时,执行移动或者缩放的操作。执行完之后,别忘了invalidate,重新绘制区域。
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
Log.d(TAG, "onTouchEvent: " + event.getX() + " " + backRect.right + " " + event.getY() + " " +
backRect.bottom);
if ((Math.abs(event.getX() - backRect.right)) < 100
&& ((Math.abs(event.getY() - backRect.bottom) < 100))) {
eventType = DRAGVIEW;
} else {
eventType = MOVEVIEW;
}
Log.d(TAG, "onTouchEvent: " + eventType);
break;
case MotionEvent.ACTION_MOVE:
switch (eventType) {
case MOVEVIEW:
int dx = (int) (event.getRawX() - lastX);
int dy = (int) (event.getRawY() - lastY);
backRect.offset(dx, dy);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
break;
case DRAGVIEW:
Log.d(TAG, "onTouchEvent: " + backRect.toShortString());
if (event.getX() > backRect.left + 100 && event.getY() > backRect.top + 100) {
backRect.set(backRect.left, backRect.top, (int) event.getX(), (int) event.getY());
}
break;
}
break;
case MotionEvent.ACTION_UP:
break;
}
invalidate(); //重新绘制区域
return true;
}
onDraw在界面上绘制
在onDraw时间里,需要调用adjustTextSize函数计算文字大小,得到文字大小后,需要进行文字绘制。在绘制的时候,通过StaticLayout对文字进行自动换行操作,将文字绘制在背景的Rect上。
参考Android自定义View使用canvas绘制文字实现居中、自动换行和Android使用StaticLayout实现文本绘制自动换行
@Override
protected void onDraw(Canvas canvas) {
canvas.drawRect(backRect, backPaint);
adjustTextSize();
//文字自动换行
StaticLayout layout = new StaticLayout(text, textPaint, backRect.width(), Layout.Alignment.ALIGN_NORMAL, 1.0F,
0.0F, true);
canvas.save();
textPaint.setTextAlign(Paint.Align.LEFT);
//文字的位置
canvas.translate(backRect.left, backRect.top);
layout.draw(canvas);
canvas.restore();
super.onDraw(canvas);
}
计算文字大小
首先获取背景的长度和宽度,最开始将文字大小设为行高的0.9倍,然后通过TextPaint.getTextBounds,获取文字的长宽,如果文字的面积大于背景矩阵面积*0.7(因为行与行之间有间隙,假设文字占据了行高的0.7倍),则减小文字的大小,一直到文字大小稍小于背景面积*0.7为止。如此便可获得合适的文字大小。
/**
* 确定文字大小
*/
private void adjustTextSize() {
rectWidth = backRect.right - backRect.left;
rectHeight = backRect.bottom - backRect.top;
textSize = (int) (rectHeight * 0.9);
textPaint.setTextSize((float) (textSize));
textPaint.getTextBounds(text, 0, text.length(), textMeasureRect);
textWidth = textMeasureRect.width();
textHeight = textMeasureRect.height();
//0.7为文字占据行高的系数
while (rectWidth * rectHeight * 0.7 < textWidth * textHeight) {
textSize = textSize -3;
textPaint.setTextSize((float) (textSize));
textPaint.getTextBounds(text, 0, text.length(), textMeasureRect);
textWidth = textMeasureRect.width();
textHeight = textMeasureRect.height();
}
textPaint.getTextBounds(text, 0, text.length(), textMeasureRect);
Log.d(TAG, "adjustTextSize: " + textMeasureRect.width() + " " + textMeasureRect.height());
}
后记:经过这个项目,知道了在解决问题前,应该先好好的分析解决思路。第三方控件并不是万能的,只有深刻的理解了Android上控件的机理,才能准确的找到解决问题的思路。
自定义界面上绘制Text,可通过拖动控制文字大小及其位置的更多相关文章
- css控制文字大小及颜色、字体
字体:font-style:italic:斜体 font-weight:bold:加粗 font-size:30px:大小 line-height:30 ...
- [寒江孤叶丶的Cocos2d-x之旅_33]RichTextEx一款通过HTML标签控制文字样式的富文本控件
RichTextEx一款通过HTML标签控制文字样式的富文本控件 原创文章,欢迎转载.转载请注明:文章来自[寒江孤叶丶的Cocos2d-x之旅系列] 博客地址:http://blog.csdn.net ...
- HTML5<canvas>标签:使用canvas元素在网页上绘制线条和圆(1)
什么是 Canvas? HTML5 的 canvas 元素使用 JavaScript 在网页上绘制图像. 画布是一个矩形区域,您可以控制其每一像素. canvas 拥有多种绘制路径.矩形.圆形.字符以 ...
- OpenCV之响应鼠标(四):在图像上绘制出矩形并标出起点的坐标
涉及到两方面的内容:1. 用鼠标画出矩形.2.在图像上绘制出点的坐标 用鼠标绘制矩形,涉及到鼠标的操作,opencv中有鼠标事件的介绍.需要用到两个函数:回调函数CvMouseCallback和注册回 ...
- 使用 Electron 构建桌面应用(拖动控制篇)
使用 Electron 构建桌面应用(拖动控制篇) 当窗口被定义了大小,我们也就是在自定义这个窗口,使得它不可拉伸没有框架,让它看起来就像一个真正的声效器浮在桌面上. 现在问题来了 – 要如何移动或者 ...
- C# 在Bitmap上绘制文字出现锯齿的问题
解决锯齿问题主要是修改Graphics的属性 修复绘制图片锯齿问题可以修改 g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiA ...
- 哪个HTML5内建对象用于在画布上绘制?()
哪个HTML5内建对象用于在画布上绘制?() getContent getContext getGraphics getCanvas 我的理解: A.C.D不存在HTML5,,js方法中 HTML 5 ...
- 利用百度API(JavaScript 版)实现在地图上绘制任一多边形,并判断给定经纬度是否在多边形范围内。以及两点间的测距功能
权声明:本文为博主原创文章,未经博主允许不得转载. 利用百度API(JavaScript 版)实现在地图上绘制任一多边形,并判断给定经纬度是否在多边形范围内.以及两点间的测距功能. 绘制多边形(蓝色) ...
- 在谷歌地图上绘制行政区域轮廓【结合高德地图的API】
实现思路: 1.利用高德地图行政区域API获得坐标列表 2.将坐标列表绘制在谷歌地图上[因为高德地图和国内的谷歌地图都是采用GCJ02坐标系,所有误差很小,可以不进行坐标误差转换] 注意点: 1.用百 ...
随机推荐
- 黄聪:AngularJS如何在filter中相互调用filter
调用方式如下: app.filter('filter2', function( $filter ) { return function( input) { return $filter('filter ...
- wsl(Windows Subsystem for Linux)安装简易指南
1. 在“启用或关闭Windows功能”窗口中打开“适用于Linux的Windows子系统”: 2. 让你的Windows更新程序将你的Windows更新到最新版本: 3. 在Microsoft St ...
- 运营站点-开放robots后,站内google搜索数量第二天10条左右,第5天搜录9920条,可喜可贺
开放robots后,站内google搜索数量第二天10条左右,第5天搜录9920条,可喜可贺 2014年4月29日 16:17:56 到目前为之已搜录14000多条,已有客户在网站注册,加入购物车
- Android开发之动态添加控件
动态添加TextView控件: 一:创建一个Android project项目 activity_main.xml文件: 1.用两个LinearLayout布局分别包裹一对TextView,EditT ...
- vo和pojo
pojo直接描述数据库中的表和字段,一一对应 vo的话,可以多添加些属性,比如code对应的name,或者标识符等等 查询列表的时候也可以直接用vo,但是修改或添加记录必须是pojo QueryVo ...
- spring4.0之七:Ordering Autowired Collections
Spring 4.0的一个小特性是在自动注入的时候使用@Order.Spring 2.5中,我们将bean注入List,如下代码: import org.springframework.stereot ...
- [转][JS]修改链接中的参数
转自:https://blog.csdn.net/weixin_40845192/article/details/81561644 /** * url地址修改 * @param url 待修改url ...
- docker拉取oracle11g镜像配置
开始拉取oracle11g镜像 下载过程稍长,镜像大小6.8G(之前拉取过了,所以就不截图了) #docker pull registry.cn-hangzhou.aliyuncs.com/helow ...
- CDN上的缓存刷新、缓存预热是怎样的使用场景?
缓存刷新 源站内容更新后,希望用户可以获取到最新资源,CDN租户可以通过提交刷新请求将CDN节点上指定的缓存内容强制过期.当用户再次访问时,CDN节点将回源获取已更新内容返回给用户并在节点缓存最新资源 ...
- redis问题:redis-server.exe双击闪退 win10系统
转:https://blog.csdn.net/qq_40361770/article/details/80454248 解决方法: 1-win+R 打开命令行 2-cd至redis目录,例如 D:\ ...
