Android:图片中叠加文字,支持拖动改变位置

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

首先上Demo效果图:

功能:

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

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

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

代码不多,直接所有贴上了:

Activity:

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

<br/>
 * 说明:非常明显,截图方式会减少图片的质量。假设须要保持图片质量能够使用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;
    }
}

布局文件:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="10dp">

    <RelativeLayout
        android:id="@+id/writeText_img_rl"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal">

        <ImageView
            android:id="@+id/writeText_img"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:maxHeight="360dp"
            android:adjustViewBounds="true"
            android:contentDescription="@null"/>

        <TextView
            android:id="@+id/writeText_image_tv"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:visibility="invisible"
            android:layout_centerInParent="true"
            android:background="#79652a"
            android:clickable="true"
            android:padding="4dp"
            android:textColor="@android:color/white"
            android:textSize="15sp" />
    </RelativeLayout>

    <EditText
        android:id="@+id/writeText_et"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:hint="加入备注" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="confirm"
        android:text="生成图片" />

</LinearLayout>

<完>

时间: 2024-11-08 07:53:05

Android:图片中叠加文字,支持拖动改变位置的相关文章

textview跟随seekbar的拖动改变位置

代码里面: package com.example.seek; import android.os.Bundle; import android.app.Activity; import android.content.Context; import android.util.DisplayMetrics; import android.view.Menu; import android.widget.RelativeLayout.LayoutParams; import android.wid

android精确绘制文字位置的方法

android 中使用Canvas的drawText绘制文本的位置,是基于基线的.如下图: 其中字母Q的小尾巴在横线下面了. 怎么样找准字母的中心位置呢? 先看下面的例子:(右边的数字,表示字体的 left, top, right, bottom) 这里面的关键是Paint.getTextBound. getTextBound会填充一个Rect,这个Rect表示的就是一个字的left, top, right, bottom.注意到left和top并不是从0,0开始的. left和right应该是

如何通过迅捷OCR文字识别软件精准识别图片中的文字

怎样精准的将图片中的文字识别出来呢?相信这是很多人的烦恼,因为我们经常会遇到文字识别的时候,使用到的方法也有很多,但是很多方法识别出来的效果不是很好,需要对比着原图去改正,这就很令人烦恼了.下面小编将分享一种在图片文字识别软件中精准提取文字的方法,一起来学习下. 步骤一.文字识别的话需要使用到工具,可以打开电脑浏览器通过搜索迅捷OCR文字识别软件将其下载安装到电脑中去. 步骤二.将安装好的软件打开,关闭自动弹窗接着点击软件上上图片局部识别选项. 步骤三.进入图片局部识别选项后,点击添加文件按钮将

如何识别图片中的文字

相信很多朋友和我一样都有这样的困扰,经常要将图片或者扫描文件中的文字提取出来,保存在我们的文档中去.但是用了很多软件,效果都不是很理想,还是需要自己人工去核对,大大影响了我们的工作效率,有没有一种简单.高效.识别率百分百的方法呢?下面我就来教大家一个方法保证简单.快速.高效! 工具/原料 WPS办公软件 AJViewer文字识别软件 准备工作 1 下载软件 ① 在“百度搜索”中输入这2款软件的软件名进行下载. ② 在“百度网盘”下载,地址是:http://pan.baidu.com/share/

Android 官方提供的支持屏幕大小的全部方法(精华)

本文将告诉你如何让你的应用程序支持各种不同屏幕大小,主要通过以下几种办法: 让你的布局能充分的自适应屏幕 根据屏幕的配置来加载合适的UI布局 确保正确的布局应用在正确的设备屏幕上 提供可以根据屏幕大小自动伸缩的图片 使用 "wrap_content" 和 "match_parent" 为了确保你的布局能够自适应各种不同屏幕大小,你应该在布局的视图中使用"wrap_content"和"match_parent"来确定它的宽和高.

如何将图片中的文字翻译成英文

有的时候,因为某种需要,会将图片中的文字翻译成英文,这时候你会在浏览器中将文字一个一个字的输进去 进行翻译吗?这种方法太麻烦了,下面就教大家一种在简单的方法. 步骤一.打开电脑,在浏览器中搜素查找迅捷办公将迅捷OCR文字识别软件下载下来,接下来会使用到,再保存一张需要将文字翻译成英文的图片. 步骤二.下载完成后将软件打开,这时候点击软件上方图片局部识别功能,这里就可以将图片中的文字翻译成英文. 步骤三.点击添加文件按钮,就可以将保存的图片添加进来了. 步骤四.图片添加进来后先不着急识别,可以在这

如何简单的识别电脑图片中的文字

相信很多人都和小编一样有这样的烦恼,经常需要将电脑中的图片或者扫描件中的文字提取出来应用到别的地方,但是使用了很多种方法效果都不是很理想,这就比较令人头疼了,那如何简单的识别电脑图片中的文字呢?接下来小编就带大家来了解下具体的操作方法. 使用工具:迅捷OCR文字识别软件 操作步骤: 1:打开电脑中的迅捷OCR文字识别软件,在软件左边导航栏中选择图片局部识别板块. 2:进入图片局部识别版块后就可以将所需识别的图片添加进来了,点击添加文件按钮添加. 3:接着鼠标点击框选工具,拖动鼠标在图片将所需识别

IOS 开发笔记-基础 UI(3)按钮的使用(放大缩小、改变位置,首位式动画)和学习案例

UIKit框架提供了非常多的UI控件,但并不是每一个都很常用,有些控件可能1年内都用不上,有些控件天天用,比如UIButton.UILabel.UIImageView.UITableView等等,按钮控件是非常重要且比较基础的一个UI控件---UIButton,一般情况下,点击某个控件后,会做出相应反应的都是按钮,按钮的功能比较多,既能显示文字,又能显示图片,还能随时调整内部图片和文字的位置. 案例: 功能分析 (1)左下角4个方向按钮,控制头像按钮的位置 (2)右下角分别是放大.缩小按钮,控制

给Jquery添加alert,prompt方法,类似系统的Alert,Prompt,可以响应键盘,支持拖动

我们在调用系统的Alert,prompt的弹出提示时,不同的系统会有不同的提示框,视觉效果不统一,而且不好看,功能单一,现在我们通过Jquery模拟Alert,prompt,现实统一视觉效果,而且内容丰富的弹出提示. Jquery可以扩展自己的功能,如果对Jquery开发插件不熟悉的人可以到官方网去看看文档,比较简单易懂. Js代码   /* *  本插件基于JQUERY *  Jquery版本: 1.7.2 *        Date:2012-06-28 *      Author:King