不多说,直接看效果先:
![v2-237095a28c5aadb313c76149058ffaae_b.gif](http://img-02.proxy.5ce.com/view/image?&type=2&guid=eedc0998-4030-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-237095a28c5aadb313c76149058ffaae_b.gif)
小萌新简单耍一下,庆祝国庆放假。实现就是简单的Canvas的drawBitmap即可,主要逻辑就是处理下绘制位置。另外如果要保存导出,就需要将Canvas合成绘制的内容导出 - 小萌新做法是
1. 创建一个临时的Bitmap,
2. 然后需要绘制的两张图片都绘制到这个Bitmap上面,
3.最后将该Bitmap绘制到屏幕上,
4.最后如果想要到处,就直接导出改Bitmap就可以了。
相对麻烦的一点就是:国旗的位置(小萌新的是右下角,原始图片的宽度的1/4,高度则需要根据国旗图片高度来进行缩放计算)
![v2-cb01aacbbd9d454d656b8528461b921a_b.jpg](http://img-03.proxy.5ce.com/view/image?&type=2&guid=eedc0998-4030-eb11-8da9-e4434bdf6706&url=https://pic3.zhimg.com/v2-cb01aacbbd9d454d656b8528461b921a_b.jpg)
有点要注意,小萌新显示原始图片的宽度最大就是屏幕宽度的一半(超过的则显示的时候以宽度一半为主),而两张图片合成到一张图片的时候,实际是往临时的Bitmap上绘制,所以绘制坐标就是临时Bitmap本身的范围来计算的,而不是显示范围,这个要区分下。
另外:其实完全可以直接再临时的Bitmap上面操作就可以的,还有就是代码的封装性这些要注意。。还有关于工具类的使用。我这里代码各方面不是很好,可能还有啥问题....自己需要可以简化完善下。。。
然后就可以简单撸下代码了:
GuoQiCanvas.java
package com.skl.testremoteservice;
import android.annotation.TargetApi;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import android.widget.Toast;
import java.io.File;
import java.io.FileOutputStream;
/**
* @HL - https://www.zhihu.com/people/monkey.d.luffy/activities
* 简单图片拼接Play一下,@微信官方 给我一面国旗
*/
public class GuoQiCanvas extends View {
private Context context;///< 上下文
private Bitmap mBitmap, bitmapGuoQi;
private Canvas cacheCanvas;
private Bitmap cacheBitmap;
private int screenWidth, screenHeight;
private Rect src, dst;
private Rect srcGuoqi, dstGuoqi, dstComposeSrc, dstComposeGuoqi;
public GuoQiCanvas(Context context) {
this(context, null);
}
public GuoQiCanvas(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public GuoQiCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
this(context, attrs, defStyleAttr, 0);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public GuoQiCanvas(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
setLayerType(LAYER_TYPE_SOFTWARE, null);
this.context = context;
WindowManager wm = (WindowManager) getContext().getSystemService(Context.WINDOW_SERVICE);
screenWidth = wm.getDefaultDisplay().getWidth();
screenHeight = wm.getDefaultDisplay().getHeight();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
// if (null != mBitmap) {
// int originShowH = (mBitmap.getWidth() > screenWidth / 2 ? screenWidth / 2 : mBitmap.getWidth()) * mBitmap.getHeight() / mBitmap.getWidth();
// setMeasuredDimension(screenWidth, originShowH * 2);
// }
// 直接全屏
setMeasuredDimension(screenWidth, screenHeight);
}
@Override
protected void onDraw(Canvas canvas) {
// 合成图片 - 此时不绘制单个图片
if (null != cacheBitmap) {
cacheCanvas.drawBitmap(mBitmap, src, src, null);
cacheCanvas.drawBitmap(bitmapGuoQi, srcGuoqi, dstComposeGuoqi, null);
canvas.drawBitmap(cacheBitmap, src, dstComposeSrc, null);
// 导出到相册
exportToCamera();
if (null != mBitmap) {
mBitmap.recycle();
mBitmap = null;
}
if (null != bitmapGuoQi) {
bitmapGuoQi.recycle();
bitmapGuoQi = null;
}
} else {
// 绘制原始图片
if (null != mBitmap) {
canvas.drawBitmap(mBitmap, src, dst, null);
}
// 绘制拼接图片
if (null != bitmapGuoQi) {
canvas.drawBitmap(bitmapGuoQi, srcGuoqi, dstGuoqi, null);
}
}
}
/**
* 绘制原始图片
*
* @param bitmap
*/
public void drawSrcBitmap(Bitmap bitmap) {
if (null != cacheBitmap) {
cacheBitmap.recycle();
cacheBitmap = null;
}
this.mBitmap = bitmap;
src = new Rect(0, 0,
mBitmap.getWidth(),
mBitmap.getHeight());
// 指定图片绘制区域(左上角的四分之一)
int originShowW = (mBitmap.getWidth() > screenWidth / 2 ? screenWidth / 2 : mBitmap.getWidth());
int originShowH = originShowW * mBitmap.getHeight() / mBitmap.getWidth();
dst = new Rect(0, 0,
originShowW,
originShowH);
// 根据图片信息更新控件大小 - 还是保持全屏吧
// requestLayout();
// 请求刷新渲染
invalidate();
}
/**
* 绘制拼接的目标图片
*
* @param bitmap
*/
public void drawDstBitmap(Bitmap bitmap) {
if (null != cacheBitmap) {
cacheBitmap.recycle();
cacheBitmap = null;
}
this.bitmapGuoQi = bitmap;
srcGuoqi = new Rect(0, 0,
bitmapGuoQi.getWidth(),
bitmapGuoQi.getHeight());
// 指定图片绘制区域(右上角的四分之一)
int originShowW = (bitmapGuoQi.getWidth() > screenWidth / 2 ? screenWidth / 2 : bitmapGuoQi.getWidth());
int originShowH = originShowW * bitmapGuoQi.getHeight() / bitmapGuoQi.getWidth();
dstGuoqi = new Rect(
screenWidth / 2,
0,
originShowW + screenWidth / 2,
originShowH);
invalidate();
}
/**
* 图像合成
*/
public boolean compose() {
// 有了就导出到相册
if (null != cacheBitmap){
exportToCamera();
return true;
}
if (null == mBitmap) {
return false;
}
if (null == bitmapGuoQi) {
return false;
}
this.cacheBitmap = Bitmap.createBitmap(mBitmap.getWidth(), mBitmap.getHeight(), Bitmap.Config.ARGB_8888);
this.cacheCanvas = new Canvas(cacheBitmap);
// 国旗图片位置
int guoqiShowW = mBitmap.getWidth() * 3 / 4;
int guoqiShowH = mBitmap.getWidth() * 1 / 4 * bitmapGuoQi.getHeight() / bitmapGuoQi.getWidth();
this.dstComposeGuoqi = new Rect(
guoqiShowW,
mBitmap.getHeight() - guoqiShowH,
mBitmap.getWidth(),
mBitmap.getHeight());
// 合成图片cacheBitmap绘制的位置
this.dstComposeSrc = new Rect(
dst.width() / 2,
0,
dst.width() / 2 + dst.width(),
dst.height());
invalidate();
return true;
}
/**
* 导出到相册
*/
public void exportToCamera() {
if (null != cacheBitmap) {
File sdRoot = context.getCacheDir();
String save_path = sdRoot + "/temp.png";
File file = new File(save_path);
if (file.exists()) {
file.delete();
}
try {
FileOutputStream fileOutputStream = new FileOutputStream(file);
cacheBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);
fileOutputStream.close();
// 插入到相册
saveBmp2Gallery(cacheBitmap, save_path);
Toast.makeText(context, "已经保存到相册", Toast.LENGTH_SHORT).show();
} catch (Exception e) {
Log.e("GuoQi Error--------->", e.toString());
}
}
}
/**
* @param bmp 获取的bitmap数据
* @param pic 图片路径
*/
public void saveBmp2Gallery(Bitmap bmp, String pic) {
// 声明文件对象
File file = new File(pic);
// 插入相册
MediaStore.Images.Media.insertImage(context.getContentResolver(),
bmp, "GuoQi", null);
// 通知相册更新
Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
Uri uri = Uri.fromFile(file);
intent.setData(uri);
context.sendBroadcast(intent);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
Log.e("GuoQi", "onDetachedFromWindow");
if (null != cacheBitmap) {
cacheBitmap.recycle();
cacheBitmap = null;
}
}
}
布局 activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.skl.testremoteservice.GuoQiCanvas
android:id="@+id/aiguoCanvas"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimaryDark"
app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent">
<Button
android:id="@+id/originBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="PicOpt"
android:text="选择头像"
android:textColor="@color/colorAccent"
android:textSize="22sp"
app:layout_constraintEnd_toStartOf="@+id/targetBtn"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/targetBtn"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:onClick="PicOpt"
android:text="选择贴图"
android:textColor="@color/colorAccent"
android:textSize="22sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintStart_toEndOf="@+id/originBtn"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/composeBtn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="PicOpt"
android:text="合成/导出到相册"
android:textColor="@color/colorPrimary"
android:textSize="22sp"
app:layout_constraintTop_toBottomOf="@+id/targetBtn" />
</android.support.constraint.ConstraintLayout>
<!--<WebView-->
<!--android:id="@+id/tetsss"-->
<!--android:layout_width="match_parent"-->
<!--android:layout_height="match_parent"/>-->
</android.support.constraint.ConstraintLayout>
使用(做了存储权限判断):
MainActivity.java (其中点击相关事件和回调部分代码 )
private GuoQiCanvas guoQiCanvas;
guoQiCanvas = findViewById(R.id.aiguoCanvas);
......
/**
* 选择合成点击事件
*
* @param view
*/
public void PicOpt(View view) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 未授权,申请授权(从相册选择图片需要读取存储卡的权限)
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 110);
} else {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
// 没有权限则申请权限
ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
// 已授权,获取照片
switch (view.getId()) {
case R.id.originBtn:
choosePhoto(0);
break;
case R.id.targetBtn:
choosePhoto(1);
break;
case R.id.composeBtn:
guoQiCanvas.compose();
break;
}
}
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// 获取图片成功进行绘制
if (resultCode == RESULT_OK) {
switch (requestCode) {
case 0:
case 1:
Uri uri = data.getData();
try {
Bitmap mBitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), uri);
if (0 == requestCode) {
guoQiCanvas.drawSrcBitmap(mBitmap);
} else if (1 == requestCode) {
guoQiCanvas.drawDstBitmap(mBitmap);
}
} catch (IOException e) {
Toast.makeText(this, e.getMessage(), Toast.LENGTH_SHORT).show();
}
break;
}
}
}
/**
* 选择相册图片
*
* @param type
*/
private void choosePhoto(int type) {
Intent intentToPickPic = new Intent(Intent.ACTION_PICK, null);
intentToPickPic.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
startActivityForResult(intentToPickPic, type);
}
权限配置:
AndroidManifest.xml
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
基本就差不多了。。。我就瞎玩了一把。。哈哈。。。 放假了,还是要好好享受,多锻炼,保持身心健康...
工程地址: https://gitee.com/heyclock/doc/tree/master/微信_给我一面国旗
apk下载地址: https://heyclock.gitee.io/doc/微信_给我一面国旗/微信_给我一面国旗.apk