之所以做了这么一个Demo,是因为最近项目中有一个奇葩的需求:用户拍摄照片后,分享到微信的同时添加备注,想获取用户在微信的弹出框输入的内容,保存在自己的服务器上。而事实上,这个内容程序是无法获取的,因此采取了一个折衷方案,将文字直接写在图片上。

首先上Demo效果图:

功能:

1.用户自由输入内容,可手动换行,并且行满也会自动换行。

2.可拖动改变图片中文本位置(文字不会超出图片区域)。

3.点击“生成图片”按钮之后,生成一张带有文字的图片文件。

代码不多,直接全部贴上了:

Activity:

/**

* 将文字写在图片中(截图方式),支持拖动文字。

* 说明:很明显,截图方式会降低图片的质量。如果需要保持图片质量可以使用canvas的方式,将文字直接绘制在图片之上(不过,使用此方式要实现文字拖动较为复杂)。

*/

public class MainActivity extends AppCompatActivity {

//图片组件

private ImageView imageView;

//位于图片中的文本组件

private TextView tvInImage;

//图片和文本的父组件

private View containerView;

//父组件的尺寸

private float imageWidth, imageHeight, imagePositionX, imagePositionY;

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.image_with_text);

imageView = (ImageView) findViewById(R.id.writeText_img);

EditText editText = (EditText) findViewById(R.id.writeText_et);

tvInImage = (TextView) findViewById(R.id.writeText_image_tv);

containerView = findViewById(R.id.writeText_img_rl);

imageView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {

@Override

public void onGlobalLayout() {

imageView.getViewTreeObserver().removeOnGlobalLayoutListener(this);

imagePositionX = imageView.getX();

imagePositionY = imageView.getY();

imageWidth = imageView.getWidth();

imageHeight = imageView.getHeight();

//设置文本大小

tvInImage.setMaxWidth((int) imageWidth);

}

});

imageView.setImageBitmap(getScaledBitmap(R.mipmap.test_img));

//输入框

editText.addTextChangedListener(new TextWatcher() {

@Override

public void beforeTextChanged(CharSequence s, int start, int count, int after) {

}

@Override

public void onTextChanged(CharSequence s, int start, int before, int count) {

if (s.toString().equals()) {

tvInImage.setVisibility(View.INVISIBLE);

} else {

tvInImage.setVisibility(View.VISIBLE);

tvInImage.setText(s);

}

}

@Override

public void afterTextChanged(Editable s) {

}

});

final GestureDetector gestureDetector = new GestureDetector(this, new SimpleGestureListenerImpl());

//移动

tvInImage.setOnTouchListener(new View.OnTouchListener() {

@Override

public boolean onTouch(View v, MotionEvent event) {

gestureDetector.onTouchEvent(event);

return true;

}

});

}

//确认,生成图片

public void confirm(View view) {

Bitmap bm = loadBitmapFromView(containerView);

String filePath = Environment.getExternalStorageDirectory() + File.separator + image_with_text.jpg;

try {

bm.compress(Bitmap.CompressFormat.JPEG, 100, new FileOutputStream(filePath));

Toast.makeText(this, 图片已保存至:SD卡根目录/image_with_text.jpg, Toast.LENGTH_LONG).show();

} catch (FileNotFoundException e) {

e.printStackTrace();

}

}

//以图片形式获取View显示的内容(类似于截图)

public static Bitmap loadBitmapFromView(View view) {

Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888);

Canvas canvas = new Canvas(bitmap);

view.draw(canvas);

return bitmap;

}

private int count = 0;

//tvInImage的x方向和y方向移动量

private float mDx, mDy;

//移动

private class SimpleGestureListenerImpl extends GestureDetector.SimpleOnGestureListener {

@Override

public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {

//向右移动时,distanceX为负;向左移动时,distanceX为正

//向下移动时,distanceY为负;向上移动时,distanceY为正

count++;

mDx -= distanceX;

mDy -= distanceY;

//边界检查

mDx = calPosition(imagePositionX - tvInImage.getX(), imagePositionX + imageWidth - (tvInImage.getX() + tvInImage.getWidth()), mDx);

mDy = calPosition(imagePositionY - tvInImage.getY(), imagePositionY + imageHeight - (tvInImage.getY() + tvInImage.getHeight()), mDy);

//控制刷新频率

if (count % 5 == 0) {

tvInImage.setX(tvInImage.getX() + mDx);

tvInImage.setY(tvInImage.getY() + mDy);

}

return true;

}

}

//计算正确的显示位置(不能超出边界)

private float calPosition(float min, float max, float current) {

if (current < min) {

return min;

}

if (current > max) {

return max;

}

return current;

}

//获取压缩后的bitmap

private Bitmap getScaledBitmap(int resId) {

BitmapFactory.Options opt = new BitmapFactory.Options();

opt.inJustDecodeBounds = true;

BitmapFactory.decodeResource(getResources(), resId, opt);

opt.inSampleSize = Utility.calculateInSampleSize(opt, 600, 800);

opt.inJustDecodeBounds = false;

return BitmapFactory.decodeResource(getResources(), resId, opt);

}

}

一个工具类:

public class Utility {

//计算 inSampleSize 值,压缩图片

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {

// Raw height and width of image

final int height = options.outHeight;

final int width = options.outWidth;

int inSampleSize = 1;

if (height > reqHeight || width > reqWidth) {

final int halfHeight = height / 2;

final int halfWidth = width / 2;

// Calculate the largest inSampleSize value that is a power of 2 and keeps both

// height and width larger than the requested height and width.

while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) {

inSampleSize *= 2;

}

}

return inSampleSize;

}

}

相关报道:

在进行数据查询的时候我们有真分页和假分页两种,所谓真分页就是按照根据pageIndex(当前页码)和pageSize(每页的记录条数)去数据库中查找响应的记录,而假分 更多

一.基本规则1.函数定义 在python中函数用关键字def声明,参数用逗号隔开,另外需要注意的是函数没有返回类型.Python函数不指定特定的返回类型,甚至不需要指定是否返回一个.但实际上,每一个python函数都会返回一 个.如果执行了return语句,那么它会返回 更多

android中拖动文字实现功能,Android:图片中叠加文字,支持拖动改变位置相关推荐

  1. android中最新webview的功能,Android WebView实现截长图功能

    本文实例为大家分享了Android实现截长图功能的具体代码,供大家参考,具体内容如下 先看看手机自带的长截屏功能:  机型: vivo x9 plus 大胆推测实现逻辑: 1:需要一个可以滚动的Vie ...

  2. android中实现GPS定位功能,Android中实现GPS定位的简单例子

    今天弄了一个多小时,写了一个GPS获取地理位置代码的小例子,包括参考了网上的一些代码,并且对代码进行了一些修改,希望对大家的帮助.具体代码如下:  要实用Adnroid平台的GPS设备,首先需要添加上 ...

  3. android java 8_四个库,让你在 Android 中启用 Java 8 功能

    Java 8 的推出引入很多革命性变化,加入了函数式编程的特征,使基于行为的编程成为可能,同时简化了各种设计模式的实现方式,是 Java 有史以来最重要的更新. 自 Android N 之后,由于 J ...

  4. Java乔晓松-android中调用系统拍照功能并显示拍照的图片

    android中调用系统拍照功能并显示拍照的图片 如果你是拍照完,利用onActivityResult获取data数据,把data数据转换成Bitmap数据,这样获取到的图片,是拍照的照片的缩略图 代 ...

  5. android 碎片技术,【移动开发】Android中强大的适配功能----Fragment(碎片)总结

    [移动开发]Android中强大的适配功能----Fragment(碎片)总结 发布时间:2020-06-27 00:32:58 来源:51CTO 阅读:10233 作者:zhf651555765 作 ...

  6. 软件android_id,Android中@id和@+id及@android:id的区别介绍

    前言 昨天突然有新来的同事问我这个@id 和@+id 的区别 ,为什么 我们的项目都是@id 自己新增的ui 使用的@+id 这里说下我的简单的回复项目是维护的之前的是为了统一管理使用了@id  方便 ...

  7. Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器

    Android 中封装优雅的 MediaPlayer 音频播放器,支持多个播放器实例的示例: public class AudioPlayer implements MediaPlayer.OnPre ...

  8. Android OpenCV应用篇三:提取图片中的文字

    上篇我们大致了解了如何运用OpenCV在Android上进行图片但简单处理 Android OpenCV应用篇二:图片处理 接下来我们就运用之前的一些相关技术来搞点事情: 如何从一张图片中将文字提取出 ...

  9. 【移动开发】Android中强大的适配功能----Fragment(碎片)总结

    作为大多数刚接触Android应用开发的人来说,在一个强大的Activity类中,就可以完成丰富多彩的UI工作,但是杂乱的屏幕分辨率,使得本来好不容易写好的UI,变得不堪入目...该怎么办那? 查阅了 ...

最新文章

  1. 新一届最强预训练模型上榜,出于BERT而胜于BERT
  2. 项目小结:日立OA系统(Asp.net)
  3. OpenLayers中地图缩放级别的设置方法
  4. 无意看到,当真给力!记住:永远不要在MySQL中使用UTF-8
  5. 有哪些是你成为一名开发之后才知道的事情
  6. php variables,浅析PHP原理之变量(Variables inside PHP)
  7. 2016年最值得学习的五大开源项目
  8. 紧急救援 L2-001 dijkstra 打印路径 最短路条数 权值
  9. _inflateEnd, referenced from _inflateInit_错误,
  10. 学校图书馆借阅管理系统软件项目分析
  11. Procexp.exe —— 强大的进程管理器
  12. 运维面试和笔试常见问题
  13. DES算法是对称算法吗,能否通过在线工具进行DES解密?
  14. 老版本MACBOOK更换固态硬盘教程
  15. 转帖 -- 仙4语录
  16. 如何判断是否是ssd硬盘?win10查看固态硬盘的方法
  17. requires INJECT_EVENTS permission
  18. gluster部署和使用
  19. mes系统多少钱,企业要不要上mes系统?
  20. 计算机一级wps表格函数,WPS表格函数学习之公式大全(字母顺序).pdf

热门文章

  1. 前端学习(1891)vue之电商管理系统电商系统之el-table渲染表格
  2. 前端学习(1680):前端系列实战课程之创建和显示蛇
  3. oracle之数据处理
  4. 打不开磁盘“D:\CentOS7\CentOS7.vmdk”或它所依赖的某个快照磁盘。
  5. html:(39):块级元素和内联块级元素
  6. php 动态修改网站配置,动态修改php的配置项
  7. Mac系统下如何使用命令行方式启动MySQL
  8. nginx php7 win,Win7配置Nginx+PHP7
  9. python生成yaml文件_Python实践34-读写yaml文件
  10. Linux 系统更改界面显示详解