惯例先看效果图
// 注意做类似这种模板功能时候 方位由后台数据提供,这里我们用假数据 4个点 或者xy 加区域来做示例
//一开始我们公司用的是透明盖住 操作图片 但发现 局限性较大。后来直接限定区域。将操作图片层级移到模板图上面 随意叠加
1. 背景图上绘制操作区域,(操作区域可以不止一个,比如美图秀秀的模板)
2. 操作区域内加上 编辑素材图的容器与编辑区域相同
3. 添加可编辑的view(这里方便观看用的ImageView)
4. 合成将你想要的View范围截屏(也可以去掉你不想要的那部分)
合成将你想要的View范围截屏文件
知道这个 可以简化你自己做图生成图片的 省略 很多复杂方法 所以先放出来 后面DIY也是用的最多的方法。
flRoot.setClipChildren(false);//是否限制子View在其范围内*(注意这个属性必须放在拖动布局的爷爷布局才能生效)
还有这个方法。使其显示View的全局哪怕被遮挡。方便用户在编辑图片的时候更清晰
1.
View view = 你想要合成的当前显示的view
Bitmap bitmap = Bitmap.createBitmap(view .getWidth(), view .getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
canvas.drawColor(Color.WHITE);
view .draw(canvas);
如果本例中我是ivTemps 那么整个图片就局部截屏下来了。就类似局部截屏。当然这个bitmap可以继续操作。又或者你可以把4个按钮隐藏掉后 再局部截屏
2.
bitmap存文件 public static String saveBitmap(Context context, Bitmap bitmap) { File file = null; try { file = new File(getCacheDir(), getFileName());/这是你的文件存的路径 自己定义吧 FileOutputStream os = new FileOutputStream(file); bitmap = small(bitmap,0.5f); mmmmmm = Bitmap.createBitmap(bitmap).copy(Bitmap.Config.ARGB_8888, true); bitmap.compress(Bitmap.CompressFormat.PNG, 100, os); os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } return file.getPath(); }
背景图上绘制操作区域
<com.rex.refreshapp.ImagesTemplates android:id="@+id/ivTemps" android:layout_width="match_parent" android:layout_height="wrap_content" />
自定义的FrameLayout
ImagesTemplates带的布局 View view = View.inflate(mContext, R.layout.view_images_templates, null);
addView(view);
简单形成一个组合控件。
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/flRoot" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FFF" > <ImageView android:id="@+id/ivBg" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <FrameLayout android:id="@+id/flZone" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#50654786" android:clipChildren="false" > </FrameLayout> </FrameLayout>
操作区域内加上 编辑素材图的容器与编辑区域相同
initBg(30, 90, 800, 1200);//背景起点 长宽 private void initBg(int x, int y, int width, int height) { ivBg.setX(x); ivBg.setY(y); ivBg.setScaleType(ImageView.ScaleType.CENTER_CROP); ivBg.setImageResource(R.mipmap.yudi); ViewGroup.LayoutParams layoutParams = ivBg.getLayoutParams(); layoutParams.width = width; layoutParams.height = height; ivBg.setLayoutParams(layoutParams); } //可多个 ----------------------- initEditZone(30, 30, 600, 800);// 展现编辑区域 虚线 和半透明 可能多个拓展 /** * 通过起点和区域范围 得到编辑区域 * * @param x * @param y * @param width * @param height */ private void initEditZone(final int x, final int y, final int width, final int height) { ViewTreeObserver vto = ivBg.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //监听一次马上结束 if (Build.VERSION.SDK_INT < 16) { ivBg.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { ivBg.getViewTreeObserver().removeOnGlobalLayoutListener(this); } Bitmap bitmap = Bitmap.createBitmap(ivBg.getWidth(), ivBg.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawColor(Color.WHITE); ivBg.draw(canvas); Paint p = new Paint(); p.setStyle(Paint.Style.STROKE); //设置虚线效果 p.setPathEffect(new DashPathEffect(new float[]{10, 5}, 0)); p.setStrokeWidth(3); p.setColor(Color.parseColor("#D0104C")); Path path = new Path(); path.moveTo(x, y); path.lineTo(x + width, y); path.lineTo(x + width, y + height); path.lineTo(x, y + height); path.close(); canvas.drawPath(path, p); ivBg.setImageBitmap(bitmap); //显示编辑区域范围 flZone.setX(x + ivBg.getX()); flZone.setY(y + ivBg.getY()); FrameLayout.LayoutParams layoutParams = (LayoutParams) flZone.getLayoutParams(); layoutParams.width = width; layoutParams.height = height; flZone.setLayoutParams(layoutParams); } } ); }
- 1.
添加可编辑的view(这里方便观看用的ImageView)
当然你可以一个ImageView画4个bitmap搞定 但是后面我否定了这个方法 重写了这种比较直观的4个ImageView 作为按钮盖在主图View方法,中间的View可以替换。也方便理解,简化了后面的步骤。
R.layout.add_img_item
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fl" android:layout_width="wrap_content" android:layout_height="wrap_content" > <ImageView android:id="@+id/iv" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="15dp" android:scaleType="centerCrop"/> <ImageView android:id="@+id/ivLeft" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="top|left" android:src="@mipmap/r_close" /> <ImageView android:id="@+id/ivRight" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="top|right" android:src="@mipmap/r_rotate" /> <ImageView android:id="@+id/ivBLeft" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="bottom|left" android:src="@mipmap/r_symmetric" /> <ImageView android:id="@+id/ivBRight" android:layout_width="30dp" android:layout_height="30dp" android:layout_gravity="bottom|right" android:src="@mipmap/r_zoom" /> </FrameLayout>
private void initEditImage() { final View flEditImage = View.inflate(mContext, R.layout.add_img_item, null); flZone.addView(flEditImage); final ImageView iv = (ImageView) flEditImage.findViewById(R.id.iv); final ImageView ivLeft = (ImageView) flEditImage.findViewById(R.id.ivLeft); final ImageView ivRight = (ImageView) flEditImage.findViewById(R.id.ivRight); final ImageView ivBLeft = (ImageView) flEditImage.findViewById(R.id.ivBLeft); final ImageView ivBRight = (ImageView) flEditImage.findViewById(R.id.ivBRight); iv.setImageResource(R.mipmap.shaosiming); flEditImage.setTag(iv); ViewTreeObserver vto = flEditImage.getViewTreeObserver(); vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { //监听一次马上结束 if (Build.VERSION.SDK_INT < 16) { flEditImage.getViewTreeObserver().removeGlobalOnLayoutListener(this); } else { flEditImage.getViewTreeObserver().removeOnGlobalLayoutListener(this); } int[] location = new int[2]; flEditImage.getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标 centerX0 = location[0] + flEditImage.getWidth() / 2; centerY0 = location[1] + flEditImage.getHeight() / 2; } } ); //平移 flEditImage.setOnTouchListener(new OnTouchListener() { private boolean isMove; private int downY; private int downX; private ImageView iv; @Override public boolean onTouch(View view, MotionEvent event) { FrameLayout flview = (FrameLayout) view; iv = (ImageView) view.getTag(); if (event.getAction() == MotionEvent.ACTION_DOWN) { downX = (int) event.getRawX(); downY = (int) event.getRawY(); isMove = false; } if (event.getAction() == MotionEvent.ACTION_MOVE) { isMove = true; int moveX = (int) event.getRawX(); int moveY = (int) event.getRawY(); // Log.d(TAG,"moveX "+moveX+" moveY "+moveY); int dx = moveX - downX; int dy = moveY - downY; int i1 = dx + (int) ViewHelper.getTranslationX(flview); int i2 = dy + (int) ViewHelper.getTranslationY(flview); ViewHelper.setTranslationX(flview, i1); ViewHelper.setTranslationY(flview, i2); downX = moveX; downY = moveY; Log.i("rex", "ACTION_MOVE"); flRoot.setClipChildren(false);//是否限制子View在其范围内*(注意这个属性必须放在拖动布局的爷爷布局才能生效) } if (event.getAction() == MotionEvent.ACTION_UP) { Log.i("rex", "ACTION_UP"); centerX = centerX0 + flEditImage.getTranslationX(); centerY = centerY0 + flEditImage.getTranslationY(); flRoot.setClipChildren(true); flRoot.invalidate(); if (CheckIsOut(iv, flview)) { ViewGroup parent = (ViewGroup) flview.getParent(); parent.removeView(flview); // flZone.removeView(flview); Toast.makeText(mContext, "超出范围已移除", Toast.LENGTH_SHORT).show(); } if (!isMove) { // Log.i("rex", "i 点击事件 "); } // centerX = (flEditImage.getLeft() + flEditImage.getWidth()) / 2; // centerY = (flEditImage.getTop() + flEditImage.getHeight()) / 2; } return true; } }); //删除 ivLeft.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { flZone.removeView(flEditImage); } }); //镜像 ivBLeft.setOnClickListener(new OnClickListener() { @Override public void onClick(View view) { Bitmap bitmap = Bitmap.createBitmap(iv.getWidth(), iv.getHeight(), Bitmap.Config.ARGB_8888); Canvas canvas = new Canvas(bitmap); canvas.drawColor(Color.WHITE); iv.draw(canvas); iv.setImageBitmap(flip(bitmap, false)); } }); //旋转 ivRight.setOnTouchListener(new OnTouchListener() { private float mDownY; private float mDownX; // // float centerX = flEditImage.getWidth() / 2; // float centerY = flEditImage.getHeight() / 2; @Override public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mDownX = event.getRawX(); mDownY = event.getRawY(); break; case MotionEvent.ACTION_MOVE: float moveX = event.getRawX(); float moveY = event.getRawY(); float rotate = flEditImage.getRotation(); float angle = getDegress(moveX, moveY) - getDegress(mDownX, mDownY); // float angle = getDegress(mDownX, mDownY) - getDegress(moveX, moveY); Log.d("name", "degress -> " + (angle + rotate)); flEditImage.setRotation((rotate + angle) % 360); mDownX = moveX; mDownY = moveY; break; case MotionEvent.ACTION_UP: break; } return true; } private float getDegress(float newX, float newY) { float x = newX - centerX; float y = newY - centerY; return (float) Math.toDegrees(Math.atan2(y, x)); } }); //缩放 ivBRight.setOnTouchListener(new OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: // mDownX = event.getRawX(); // mDownY = event.getRawY(); break; case MotionEvent.ACTION_MOVE: float moveX = event.getRawX(); float moveY = event.getRawY(); float bili = getBili(moveX, moveY); Log.d("rex", "bili -> " + bili); flEditImage.setScaleX(bili); flEditImage.setScaleY(bili); correct4ButtonSize(1 / bili); Log.d("rex", " ivBRight.getScaleX(); " + ivBRight.getScaleX()); // mDownX = moveX; // mDownY = moveY; break; case MotionEvent.ACTION_UP: break; } return true; } /** * * @param bili */ private void correct4ButtonSize(float bili) { ivLeft.setScaleX(bili); ivLeft.setScaleY(bili); ivRight.setScaleX(bili); ivRight.setScaleY(bili); ivBLeft.setScaleX(bili); ivBLeft.setScaleY(bili); ivBRight.setScaleX(bili); ivBRight.setScaleY(bili); ; } private float getBili(float moveX, float moveY) { int[] location = new int[2]; // flEditImage.getLocationInWindow(location); //获取在当前窗口内的绝对坐标 flEditImage.getLocationOnScreen(location);//获取在整个屏幕内的绝对坐标 float radius = ivBLeft.getWidth();//不精确 float oldLine = (float) Math.sqrt(flEditImage.getWidth() * flEditImage.getWidth() + flEditImage.getHeight() * flEditImage.getHeight()); float newLine = (float) Math.sqrt((moveX - location[0] + radius) * (moveX - location[0] + radius) + (moveY - location[1] + radius) * (moveY - location[1] + radius)); float scale = newLine / oldLine;//此处有微量误差 return scale; } }); }
/** * 判断是否超出 * @param iv * @param fl * @return */ private boolean CheckIsOut(ImageView iv, FrameLayout fl) { int maxX = flZone.getWidth(); int maxY = flZone.getHeight(); int a = fl.getWidth(); int a2 = (int) fl.getX(); int a3 = iv.getLeft(); int a4 = iv.getRight(); int x1 = (int) (fl.getX() + iv.getLeft()); int x2 = (int) (fl.getX() + fl.getWidth() - iv.getLeft()); int y1 = (int) (fl.getY() + iv.getTop()); int y2 = (int) (fl.getY() + fl.getHeight() - iv.getTop()); if (x1 > maxX || x2 < 0 || y1 > maxY || y2 < 0) { return true; } return false; } public static Bitmap flip(Bitmap bitmap, boolean isVer) { int w = bitmap.getWidth(); int h = bitmap.getHeight(); Matrix matrix = new Matrix(); if (isVer) matrix.postScale(1, -1);//镜像垂直翻转 else matrix.postScale(-1, 1); //镜像水平翻转 Bitmap newBitmap = Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true); bitmap.recycle(); return newBitmap; }
转自:Android DIY之路 (一) 指定区域多图片合成 放大 缩小 镜像 旋转 等