Android编程实现支持拖动改变位置的图片中叠加文字功能示例

本文实例讲述了Android编程实现支持拖动改变位置的图片中叠加文字功能。分享给大家供大家参考,具体如下:

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

首先上Demo效果图:

功能:

1.用户自由输入内容,可手动换行,并且行满也会自动换行。
2.可拖动改变图片中文本位置(文字不会超出图片区域)。
3.点击“生成图片”按钮之后,生成一张带有文字的图片文件。

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

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>

更多关于Android相关内容感兴趣的读者可查看本站专题:《Android图形与图像处理技巧总结》、《Android开发入门与进阶教程》、《Android调试技巧与常见问题解决方法汇总》、《Android基本组件用法总结》、《Android视图View技巧总结》、《Android布局layout技巧总结》及《Android控件用法总结》

希望本文所述对大家Android程序设计有所帮助。

(0)

相关推荐

  • Android自定义组件获取本地图片和相机拍照图片

    iOS中有封装好的选择图片后长按出现动画删除效果,效果如下 而Android找了很久都没有找到有这样效果的第三方组件,最后懒得找了还是自己实现这效果吧 选择图片后还可对图片进行剪裁 当然,代码中还有很多不完善的地方,我接下来会继续完善这个组件的 已经上传到开源社区,欢迎大家来Star啊~ Demo源码:传送门 设计中的碰到的一些问题和解决思路 1.如何让加号图片显示在GridView最后面 首先在调用GridAdapter构造方法时就加载加号图片 /** * 图片适配器 * @param con

  • Android ViewPager加载图片效果

    目前项目中需要用到ViewPager加载图片,现在在此记录一下. 首先先看布局文件:activity_main.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.c

  • Android自定义ImageView实现在图片上添加图层效果

    首先我们先看下效果图 实现思路 这是两张前后对比图,右边第二张图里面的已抢光标签图片当已经没有商品的时候就会显示了,在每个图片的中心位置,第一想法是在ImageView的外层再套一层RelativeLayout 实现方法 <RelativeLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <SelectableRoundedImageVi

  • Android百度地图应用之图层展示

    一.简介  1.地图类型  百度地图Android SDK 3.7.1提供了两种类型的地图资源(普通矢量地图和卫星图),开发者可以利用BaiduMap中的MapType属性(C#)来设置地图类型.C#核心代码如下: mMapView = FindViewById<TextureMapView>(Resource.Id.bmapView); mBaiduMap = mMapView.Map; //设置底图显示模式:普通地图 mBaiduMap.MapType = BaiduMap.MapType

  • Android中超大图片无法显示的问题解决

    发现问题 最近在做图片浏览功能时遇到了一个很蛋疼的问题,在开启硬件加速情况下,超大图无法正常显示(图的长宽有一个大于9000),而且程序不会crash,只是图片加载不出来,View显示为黑色.通过查看日志,发现系统打印出了下面的内容: W OpenGLRenderer( 4014): Bitmap too large to be uploaded into a texture (600x9518, max=8192x8192) 从日志内容可以看出,这是由OpenGL打印出来的日志,是由于图片的尺

  • Android编程实现图片背景渐变切换与图层叠加效果

    本文实例讲述了Android编程实现图片背景渐变切换与图层叠加效果.分享给大家供大家参考,具体如下: 本例要实现的目的: 1.图片背景渐变的切换,例如渐变的从红色切换成绿色. 2.代码中进行图层叠加,即把多个Drawable叠加在一起显示在一个组件之上. 效果图: 代码很简单: (1)布局文件: <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="

  • Android ViewPager实现图片轮翻效果

    很多App都有这种效果,特别一些电商类的App,顶部每隔几秒钟会向右翻页显示下张图片,用来作推广或者内容展示用的.今天来简单地模仿一下,还自带一个自动跳动的小功能(底部有几个小点,图片移动的时候,点的状态也在变化),用定时器来实现不难. import java.util.ArrayList; import java.util.List; import android.app.Activity; import android.os.Bundle; import android.os.Handler

  • Android中从图库中选取图片实例详解

    android 从图库中选取图片 在android中,如何从图库gallary中挑选图片呢,其实很简单,步骤如下 1) 设计一个imageview,用来显示图库选出来的图片 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientati

  • android自定义ImageView仿图片上传示例

    看下效果图 主要看下自定义view 代码 public class ProcessImageView extends ImageView{ private Context context; private Paint paint; private LogUtil log=LogUtil.getInstance(); int progress = 0; private boolean flag; public ProcessImageView(Context context) { super(co

  • Android 实现局部图片滑动指引效果

    Android 实现局部图片滑动指引效果 而ViewPager的事件监听器代码如下: // 滑动页面更改事件监听器 private class ImagePageChangeListener implements OnPageChangeListener { @Override public void onPageScrollStateChanged(int arg0) { // TODO Auto-generated method stub } @Override public void on

随机推荐