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

首先上Demo效果图:

android imageview叠加反向 android图片叠加显示_ide

  

功能:

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>

<完>






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

首先上Demo效果图:

android imageview叠加反向 android图片叠加显示_ide

  

功能:

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>

<完>