
大家好,又到了新的一期項(xiàng)目需求分析。臺(tái)下的觀(guān)眾舉起手,讓我看到你們。
同時(shí)我已經(jīng)上傳該項(xiàng)目:截屏及仿支付寶涂鴉功能
歡迎各位點(diǎn)個(gè)star哦。(⊙o⊙)

開(kāi)始秋名山飄移之路
這個(gè)也是具體項(xiàng)目中遇到的項(xiàng)目需求:需要在一個(gè)特定的界面中(都是圖表和各種數(shù)據(jù),可能需求分享給別人,告訴別人這個(gè)數(shù)據(jù)怎么怎么,這個(gè)圖表怎么怎么)
所以給我們開(kāi)發(fā)的需求就是:
- 對(duì)該界面進(jìn)行截屏
- 截屏后跳到涂鴉界面,可能某個(gè)數(shù)據(jù)圈出來(lái),讓別人一看就知道。(涂鴉,橡皮擦,撤銷(xiāo),清空操作)
- 分享給QQ,微信等等其他第三方軟件。
功能上來(lái)說(shuō),其實(shí)沒(méi)啥難度。各種第三方的,別人寫(xiě)好的涂鴉封裝包也有很多。但是要么是不能隨意定制化,要么就是寫(xiě)的也不是特別好,而且我更加提倡的是技術(shù)本身不是特別好的各位同僚們,還是寧可下載下來(lái)觀(guān)看,然后自己試著去寫(xiě)一下,寫(xiě)一個(gè)自己的工具??赡軐?xiě)的沒(méi)別人好,可能有點(diǎn)重復(fù)造輪子的意思,但是對(duì)于自己的提升還是很大的。當(dāng)然大家可以提出意見(jiàn)。我寫(xiě)的也不見(jiàn)得很好。。(大牛請(qǐng)忽略這段話(huà)。哈哈)
具體步驟
1.界面截屏功能
因?yàn)楫?dāng)前我做的是截屏后把獲得的Bitmap保存為本地圖片,然后跳轉(zhuǎn)到涂鴉界面,然后打開(kāi)這個(gè)本地圖片進(jìn)行涂鴉處理。其他人可以根據(jù)自己的需求對(duì)這個(gè)截屏獲取的Bitmap進(jìn)行處理。
/**
* 截屏并將圖片保存到相應(yīng)路徑下
* @param activity 當(dāng)前需要截屏的activity
* @param path 圖片保存路徑
*/
public static void SaveScreenShot(Activity activity,String path) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(path);
bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
}finally {
if(outputStream != null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
view.setDrawingCacheEnabled(false);
}
}
核心的代碼就是:
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
view.setDrawingCacheEnabled(false);
2.涂鴉功能
核心的概念就是:自定義View(畫(huà)板),然后在上面先畫(huà)上我們截屏的圖片,然后再在上面畫(huà)上一層圖片,我們的涂鴉其實(shí)也就是在上面一層圖片畫(huà)來(lái)畫(huà)去。一臉懵逼?? 一定要逼我換個(gè)通俗易懂的???
比如畫(huà)板是一個(gè)桌子,我們先在上面放了一個(gè)海報(bào),然后我們?cè)倌靡粋€(gè)透明的圖片(這里比如我們拿的是一塊透明玻璃)蓋在海報(bào)上面,然后我們拿個(gè)粉筆在玻璃上面畫(huà)來(lái)畫(huà)去,這時(shí)候來(lái)我們看來(lái),是不是就等于海報(bào)被涂了各種顏色。比如我們要清空涂鴉。是不是只要把玻璃上面的涂鴉給擦光就行了。然后下面的海報(bào)就又變成了原來(lái)的樣子。
所以我們這個(gè)涂鴉也要一步步來(lái)處理,因?yàn)樵趯?shí)際開(kāi)發(fā)中會(huì)遇到各種問(wèn)題,所以要一步步來(lái)。
如何把截圖的圖片,按照我們自定義的View(畫(huà)板)的大小,等比例放進(jìn)去。
可能有人要問(wèn)了。為啥要等比例放進(jìn)去,我們就直接把圖片塞進(jìn)去我們的畫(huà)板不就OK了嗎。
因?yàn)槲覀冞@次是全屏截圖!??!而我們的畫(huà)板肯定是比全屏的截圖面積要小,因?yàn)橄旅嬗挟?huà)筆、橡皮擦等其他功能菜單區(qū)域。
看效果(我故意把我的涂鴉畫(huà)板的高度設(shè)置小很多):



[圖片上傳失敗...(image-c6aeef-1531720247591)]
OK,我們接下去就知道了。如果我們要在自定義的View(畫(huà)板)上先放上去截圖的圖片,就要先把圖片按比例處理好再放入。所以也就是說(shuō)這個(gè)圖片需要根據(jù)我們的畫(huà)板的面積來(lái)做相應(yīng)調(diào)整。
也有可能有人要問(wèn),如果我的需求不是截屏涂鴉,是打開(kāi)內(nèi)置的某個(gè)圖片,然后畫(huà)板反而比我的圖片大怎么辦
。沒(méi)關(guān)系。這里教你們一招。不用在意圖片跟畫(huà)板哪個(gè)大哪個(gè)小。
1.獲取圖片的寬和高:bitmapWidth,bitmapHeight
2.獲取畫(huà)板的寬和高:boardWidth,boardHeight
3.如果bitmapWidth > boardWidth或者 bitmapHeight > boardHeight,則把圖片縮小比例,來(lái)適應(yīng)畫(huà)板
4.否則就設(shè)置畫(huà)板控件的寬和高等于圖片的寬和高。既讓boardWidth = bitmapWidth,boardHeight = bitmapHeight。我們反過(guò)來(lái)讓畫(huà)板來(lái)適應(yīng)圖片即可。
/**
*
* 圖片過(guò)大則根據(jù)容器把原始圖片改變大小。從而適應(yīng)容器。
* 否則改變畫(huà)板大小適應(yīng)圖片
*
* @param bitmap
* @param boardView
* @return
*/
public static Bitmap resizeBitmap(Bitmap bitmap, View boardView) {
int bitmapHeight = bitmap.getHeight();
int bitmapWidth = bitmap.getWidth();
int boardHeight = boardView.getHeight();
int boardWidth = boardView.getWidth();
float scale = 1f;
if(bitmapHeight > boardHeight || bitmapWidth > boardWidth){
scale = bitmapHeight > bitmapWidth
? boardHeight / (bitmapHeight * 1f)
: boardWidth / (bitmapWidth * 1f);
}
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
ViewGroup.LayoutParams params = boardView.getLayoutParams();
params.height = resizeBitmap.getHeight();
params.width = resizeBitmap.getWidth();
boardView .setLayoutParams(params);
return resizeBitmap;
}
添加第二層Canvas。用于涂鴉
我們上面拿到了截圖的Bitmap,我們畫(huà)上去后,還要畫(huà)一層用于涂鴉的Bitmap,也就是我前面舉例的那塊透明玻璃。
也很簡(jiǎn)單。我們只要再新建一個(gè)Bitmap,大小等同于畫(huà)板的大小,然后用Canvas包裹,讓這個(gè)Bitmap能夠具有畫(huà)畫(huà)的功能,
然后再把這個(gè)新的Bitmap讓我們的畫(huà)板畫(huà)出來(lái)就可以了。
我們?cè)谧远xView 中寫(xiě)入一個(gè)方法:
/**
* 設(shè)置背景圖片及監(jiān)理新的用來(lái)涂鴉的Bitmap
*
* @param bitmap 傳入的截圖界面圖片
*/
public void setBackgroud(Bitmap bitmap) {
this.backgroudBitmap = bitmap;
this.bitmap = Bitmap.createBitmap(backgroudBitmap.getWidth(), backgroudBitmap.getHeight(), Bitmap.Config.ARGB_8888);
paintCanvas = new Canvas(this.bitmap);
}
這樣我們把第一步處理好的截圖圖片傳進(jìn)來(lái)的時(shí)候。同時(shí)建一個(gè)和這個(gè)截圖圖片一樣大小的圖片,并且用Canvas包裹。這樣等會(huì)我們就可以用這個(gè)paintCanvas在新的圖片上面進(jìn)行畫(huà)畫(huà)了。
我們?cè)趏nDraw方法中也只要畫(huà)這二個(gè)Bitmap就可以了。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (backgroudBitmap != null && !backgroudBitmap.isRecycled()) {
canvas.drawBitmap(backgroudBitmap, 0, 0, null);
}
if (bitmap != null && !bitmap.isRecycled()) {
canvas.drawBitmap(bitmap, 0, 0, null);
}
}
真正的涂鴉實(shí)現(xiàn)
真正的涂鴉功能,其實(shí)只是對(duì)我們的后面新建的Bitmap進(jìn)行各種操作,也就是用上面的paintCanvas來(lái)進(jìn)行畫(huà)線(xiàn)等操作。
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
path = new Path();
path.moveTo(startX, startY);
break;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
path.quadTo(startX, startY, endX, endY);
paintCanvas.drawPath(path, isEraser ? eraserPaint : paint);
startX = endX;
startY = endY;
postInvalidate();
break;
case MotionEvent.ACTION_UP:
drawPathList.add(new DrawPathEntry(path, isEraser ? eraserPaint.getColor() : paint.getColor(), isEraser));
break;
default:
break;
}
return true;
}
切換涂鴉顏色功能
其實(shí)用不同顏色畫(huà)筆來(lái)畫(huà),就是單純的切換Paint的顏色值即可。
/**
* 設(shè)置畫(huà)筆顏色及橡皮擦
*
* @param type
*/
public void setPaintType(int type) {
isEraser = false;
switch (type) {
case AnnotationConfig.PaintType.Paint_Red:
paint.setColor(ContextCompat.getColor(context, R.color.red_radio));
break;
case AnnotationConfig.PaintType.Paint_Orange:
paint.setColor(ContextCompat.getColor(context, R.color.orange_radio));
break;
case AnnotationConfig.PaintType.Paint_Yellow:
paint.setColor(ContextCompat.getColor(context, R.color.yellow_radio));
break;
case AnnotationConfig.PaintType.Paint_Green:
paint.setColor(ContextCompat.getColor(context, R.color.green_radio));
break;
case AnnotationConfig.PaintType.Paint_Blue:
paint.setColor(ContextCompat.getColor(context, R.color.blue_radio));
break;
case AnnotationConfig.PaintType.Paint_Purple:
paint.setColor(ContextCompat.getColor(context, R.color.purple_radio));
break;
case AnnotationConfig.PaintType.Paint_Eraser:
isEraser = true;
break;
default:
break;
}
}
橡皮擦功能
其實(shí)橡皮擦功能,你可以理解就是在畫(huà)一個(gè)透明的線(xiàn),這個(gè)線(xiàn)蓋在了你的其他的畫(huà)好的線(xiàn)的上面。我們的目標(biāo)就是他們二個(gè)交集的地方,讓原本的線(xiàn)消失。
下表就是二個(gè)線(xiàn)交集的時(shí)候,不同Mode下呈現(xiàn)的情況。我們這里就可以用Clear模式。交集的地方,讓底下的顏色消失就可以。
[圖片上傳失敗...(image-43c445-1531720247591)]
設(shè)置橡皮擦的Paint的Xfermode模式為Mode.Clear。
Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
eraserPaint.setXfermode(xfermode);
然后讓這個(gè)earserPaint按照上面涂鴉的寫(xiě)法,讓它畫(huà)線(xiàn)就可以。
撤銷(xiāo)功能
撤銷(xiāo)其實(shí)也很簡(jiǎn)單,就是我們?cè)诋?huà)的時(shí)候,把每次畫(huà)的Path和所畫(huà)這個(gè)Path的畫(huà)筆顏色保存下來(lái),放在一個(gè)List集合里面,然后每次點(diǎn)撤銷(xiāo),就把List集合里面最后一個(gè)的Path給去掉,然后把二層Bitmap(也就是那個(gè)透明玻璃)清空,再把List里面的所有的Path按照其對(duì)應(yīng)的畫(huà)筆顏色畫(huà)出來(lái)就可以了。
/**
* 撤銷(xiāo)操作
*/
public void cancelPath() {
if (drawPathList != null && drawPathList.size() <= 0) {
return;
}
drawPathList.remove(drawPathList.size() - 1);
paintCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (DrawPathEntry entry : drawPathList) {
paint.setColor(entry.getPaintColor());
paintCanvas.drawPath(entry.getPath(), entry.isEraser() ? eraserPaint : paint);
}
postInvalidate();
}
清空涂鴉
清空涂鴉就比上面撤銷(xiāo)功能更簡(jiǎn)單了。把二層Bitmap(也就是那個(gè)透明玻璃)清空,然后把我們的上面存Path的List給清空,這樣撤銷(xiāo)也就不會(huì)出現(xiàn)原來(lái)的涂鴉。
/**
* 清空涂鴉
*/
public void clearScrawlBoard() {
paintCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
drawPathList.clear();
postInvalidate();
}
返回最終的涂鴉好的圖片
新建一個(gè)Canvas。把最終的截圖圖片的bitmap和最終已經(jīng)涂鴉好的二層Bitmap(透明玻璃)給畫(huà)上去,然后獲取最終的合成的Bitmap即可。
/**
* @return 返回最終的涂鴉好的圖片
*/
public Bitmap getSrawBoardBitmap() {
Bitmap resultBitmap = Bitmap.createBitmap(backgroudBitmap.getWidth(), backgroudBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(backgroudBitmap, 0, 0, null);
canvas.drawBitmap(bitmap, 0, 0, null);
canvas.save();
return resultBitmap;
}
3.圖片分享功能
我們通過(guò)上面的getSrawBoardBitmap()方法獲得了最后的合成的圖片。然后分享到微信,QQ等第三方軟件。我這邊用的是友盟分享。
它只是幫你做了個(gè)封裝,而各個(gè)第三方的分享都要去其相應(yīng)的平臺(tái)去申請(qǐng)Key。
比如你要分享到微信和QQ,就要分別取申請(qǐng)微信和QQ的key。然后再集成到友盟分享中去,才能使用。
UMImage image = new UMImage(DrawBaseActivity.this, bit);
new ShareAction(DrawBaseActivity.this).withText("hello").withMedia(image)
.setDisplayList(SHARE_MEDIA.QQ,SHARE_MEDIA.WEIXIN,SHARE_MEDIA.ALIPAY)
.setCallback(new UMShareListener() {
@Override
public void onStart(SHARE_MEDIA share_media) {
}
@Override
public void onResult(SHARE_MEDIA share_media) {
Toast.makeText(DrawBaseActivity.this, share_media + " 分享成功啦", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(SHARE_MEDIA share_media, Throwable throwable) {
Toast.makeText(DrawBaseActivity.this,share_media + " 分享失敗啦", Toast.LENGTH_SHORT).show();
if(throwable!=null){
Log.d("throw","throw:"+throwable.getMessage());
}
}
@Override
public void onCancel(SHARE_MEDIA share_media) {
Toast.makeText(DrawBaseActivity.this,share_media + " 分享取消了", Toast.LENGTH_SHORT).show();
}
}).open();
當(dāng)然這種分享過(guò)去給別人,是會(huì)攜帶你的app相關(guān)信息,比如我分享一個(gè)圖片到微信,在微信聊天列表的圖片下面會(huì)有我們的app的名字信息。但是如果我不想一個(gè)個(gè)平臺(tái)去注冊(cè),就想單純的當(dāng)一個(gè)文本發(fā)送到其他app,我們只需要簡(jiǎn)單的寫(xiě)一下就可以:
Uri uri = Uri.fromFile(new File(path));
share("xxx截圖說(shuō)明", uri);
/**
* 圖片及文字分享
*
* @param content
* @param uri
*/
private void share(String content, Uri uri) {
Intent shareIntent = new Intent(Intent.ACTION_SEND);
if (uri != null) {
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType("image/*");
//當(dāng)用戶(hù)選擇短信時(shí)使用sms_body取得文字
shareIntent.putExtra("sms_body", content);
} else {
shareIntent.setType("text/plain");
}
shareIntent.putExtra(Intent.EXTRA_TEXT, content);
//自定義選擇框的標(biāo)題
startActivity(Intent.createChooser(shareIntent, "邀請(qǐng)好友"));
//系統(tǒng)默認(rèn)標(biāo)題
}
最終
最后的最后,貼上相應(yīng)的相關(guān)自定義View和涂鴉的所屬的Activity的代碼。大家也可以去我上面貼的Github地址中取下載demo。更方便查看:截屏及仿支付寶涂鴉功能
ScrawlActivity.java
package com.example.scrawldemo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.support.annotation.IdRes;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.RadioGroup;
import android.widget.Toast;
import com.example.scrawldemo.config.AnnotationConfig;
import com.example.scrawldemo.util.BitmapUtil;
import com.example.scrawldemo.widget.ScrawlBoardView;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class ScrawlActivity extends AppCompatActivity {
@BindView(R.id.color_group)
RadioGroup colorGroup;
@BindView(R.id.board_view)
ScrawlBoardView boardView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
String path = getIntent().getStringExtra("path");
final Bitmap bitmap = BitmapFactory.decodeFile(path);
boardView.post(new Runnable() {
@Override
public void run() {
final Bitmap resizeBitmap = BitmapUtil.resizeBitmap(bitmap,boardView);
//final Bitmap resizeBitmap = bitmap;
runOnUiThread(new Runnable() {
@Override
public void run() {
boardView.setBackgroud(resizeBitmap);
}
});
}
});
colorGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
switch (checkedId) {
case R.id.red_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Red);
break;
case R.id.orange_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Orange);
break;
case R.id.yellow_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Yellow);
break;
case R.id.green_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Green);
break;
case R.id.blue_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Blue);
break;
case R.id.purple_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Purple);
break;
case R.id.eraser_radio:
boardView.setPaintType(AnnotationConfig.PaintType.Paint_Eraser);
break;
default:
break;
}
}
});
}
@OnClick({R.id.cancel, R.id.rubbish,R.id.finish_btn,R.id.send_btn})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.cancel:
boardView.cancelPath();
break;
case R.id.rubbish:
boardView.clearScrawlBoard();
break;
case R.id.finish_btn:
finish();
break;
case R.id.send_btn:
Bitmap bitmap = boardView.getSrawBoardBitmap();
//該處的bitmap是涂鴉好的圖片。
//該例子中是把涂鴉好的圖片保存到本地
try {
FileOutputStream outputStream = new FileOutputStream(ScrawlActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES)+"/ChintScreenShot.png");
bitmap.compress(Bitmap.CompressFormat.PNG,100,outputStream);
Toast.makeText(this, "保存到本地成功", Toast.LENGTH_SHORT).show();
} catch (FileNotFoundException e) {
e.printStackTrace();
}
//我分享用的是友盟分享。也就是把上面獲取到的bitmap傳入到相應(yīng)的友盟分享中的方法即可
/*
UMImage image = new UMImage(ScrawlActivity.this, bitmap);
new ShareAction(DrawBaseActivity.this).withText("hello").withMedia(image)
.setDisplayList(SHARE_MEDIA.QQ,SHARE_MEDIA.WEIXIN,SHARE_MEDIA.ALIPAY)
.setCallback(new UMShareListener() {
@Override
public void onStart(SHARE_MEDIA share_media) {
}
@Override
public void onResult(SHARE_MEDIA share_media) {
Toast.makeText(DrawBaseActivity.this, share_media + " 分享成功啦", Toast.LENGTH_SHORT).show();
}
@Override
public void onError(SHARE_MEDIA share_media, Throwable throwable) {
Toast.makeText(DrawBaseActivity.this,share_media + " 分享失敗啦", Toast.LENGTH_SHORT).show();
if(throwable!=null){
Log.d("throw","throw:"+throwable.getMessage());
}
}
@Override
public void onCancel(SHARE_MEDIA share_media) {
Toast.makeText(DrawBaseActivity.this,share_media + " 分享取消了", Toast.LENGTH_SHORT).show();
}
}).open();
*/
break;
default:
break;
}
}
}
ScrawlBoardView.java
package com.example.scrawldemo.widget;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Xfermode;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import com.example.scrawldemo.R;
import com.example.scrawldemo.bean.DrawPathEntry;
import com.example.scrawldemo.config.AnnotationConfig;
import java.util.ArrayList;
import java.util.List;
/**
* Project:AndroidDemo
* Author:dyping
* Date:2017/4/11 10:36
*/
public class ScrawlBoardView extends View {
Canvas paintCanvas;
Paint paint, eraserPaint;
Bitmap bitmap;
Bitmap backgroudBitmap;
float startX, startY, endX, endY;
Context context;
boolean isEraser;
List<DrawPathEntry> drawPathList = new ArrayList<>();
Path path;
public ScrawlBoardView(Context context) {
super(context);
}
public ScrawlBoardView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setFilterBitmap(true);
paint.setColor(ContextCompat.getColor(context, R.color.red_radio));
paint.setStrokeWidth(10);
eraserPaint = new Paint();
eraserPaint.setStyle(Paint.Style.STROKE);
eraserPaint.setStrokeWidth(20);
eraserPaint.setColor(Color.TRANSPARENT);
Xfermode xfermode = new PorterDuffXfermode(PorterDuff.Mode.CLEAR);
eraserPaint.setXfermode(xfermode);
this.context = context;
}
public ScrawlBoardView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (backgroudBitmap != null && !backgroudBitmap.isRecycled()) {
canvas.drawBitmap(backgroudBitmap, 0, 0, null);
}
if (bitmap != null && !bitmap.isRecycled()) {
canvas.drawBitmap(bitmap, 0, 0, null);
}
}
/**
* 設(shè)置背景圖片及監(jiān)理新的用來(lái)涂鴉的Bitmap
*
* @param bitmap 傳入的截圖界面圖片
*/
public void setBackgroud(Bitmap bitmap) {
this.backgroudBitmap = bitmap;
this.bitmap = Bitmap.createBitmap(backgroudBitmap.getWidth(), backgroudBitmap.getHeight(), Bitmap.Config.ARGB_8888);
paintCanvas = new Canvas(this.bitmap);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
startX = event.getX();
startY = event.getY();
path = new Path();
path.moveTo(startX, startY);
break;
case MotionEvent.ACTION_MOVE:
endX = event.getX();
endY = event.getY();
path.quadTo(startX, startY, endX, endY);
paintCanvas.drawPath(path, isEraser ? eraserPaint : paint);
startX = endX;
startY = endY;
postInvalidate();
break;
case MotionEvent.ACTION_UP:
drawPathList.add(new DrawPathEntry(path, isEraser ? eraserPaint.getColor() : paint.getColor(), isEraser));
break;
default:
break;
}
return true;
}
/**
* 設(shè)置畫(huà)筆顏色及橡皮擦
*
* @param type
*/
public void setPaintType(int type) {
isEraser = false;
switch (type) {
case AnnotationConfig.PaintType.Paint_Red:
paint.setColor(ContextCompat.getColor(context, R.color.red_radio));
break;
case AnnotationConfig.PaintType.Paint_Orange:
paint.setColor(ContextCompat.getColor(context, R.color.orange_radio));
break;
case AnnotationConfig.PaintType.Paint_Yellow:
paint.setColor(ContextCompat.getColor(context, R.color.yellow_radio));
break;
case AnnotationConfig.PaintType.Paint_Green:
paint.setColor(ContextCompat.getColor(context, R.color.green_radio));
break;
case AnnotationConfig.PaintType.Paint_Blue:
paint.setColor(ContextCompat.getColor(context, R.color.blue_radio));
break;
case AnnotationConfig.PaintType.Paint_Purple:
paint.setColor(ContextCompat.getColor(context, R.color.purple_radio));
break;
case AnnotationConfig.PaintType.Paint_Eraser:
isEraser = true;
break;
default:
break;
}
}
/**
* 撤銷(xiāo)操作
*/
public void cancelPath() {
if (drawPathList != null && drawPathList.size() <= 0) {
return;
}
drawPathList.remove(drawPathList.size() - 1);
paintCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
for (DrawPathEntry entry : drawPathList) {
paint.setColor(entry.getPaintColor());
paintCanvas.drawPath(entry.getPath(), entry.isEraser() ? eraserPaint : paint);
}
postInvalidate();
}
/**
* 清空涂鴉
*/
public void clearScrawlBoard() {
paintCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
drawPathList.clear();
postInvalidate();
}
/**
* @return 返回最終的涂鴉好的圖片
*/
public Bitmap getSrawBoardBitmap() {
Bitmap resultBitmap = Bitmap.createBitmap(backgroudBitmap.getWidth(), backgroudBitmap.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(resultBitmap);
canvas.drawBitmap(backgroudBitmap, 0, 0, null);
canvas.drawBitmap(bitmap, 0, 0, null);
canvas.save();
return resultBitmap;
}
}
BitmapUtil.java
package com.example.scrawldemo.util;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.view.View;
import android.view.ViewGroup;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
/**
* Project:AndroidDemo
* Author:dyping
* Date:2017/4/11 10:40
*/
public class BitmapUtil {
/**
*
* 圖片過(guò)大則根據(jù)容器把原始圖片改變大小。從而適應(yīng)容器。
* 否則改變畫(huà)板大小適應(yīng)圖片
*
* @param bitmap
* @param boardView
* @return
*/
public static Bitmap resizeBitmap(Bitmap bitmap, View boardView) {
int bitmapHeight = bitmap.getHeight();
int bitmapWidth = bitmap.getWidth();
int boardHeight = boardView.getHeight();
int boardWidth = boardView.getWidth();
float scale = 1f;
if(bitmapHeight > boardHeight || bitmapWidth > boardWidth){
scale = bitmapHeight > bitmapWidth
? boardHeight / (bitmapHeight * 1f)
: boardWidth / (bitmapWidth * 1f);
}
Matrix matrix = new Matrix();
matrix.postScale(scale, scale);
Bitmap resizeBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmapWidth, bitmapHeight, matrix, false);
ViewGroup.LayoutParams params = boardView.getLayoutParams();
params.height = resizeBitmap.getHeight();
params.width = resizeBitmap.getWidth();
boardView .setLayoutParams(params);
return resizeBitmap;
}
/**
* 截屏并將圖片保存到相應(yīng)路徑下
*
* @param activity 當(dāng)前需要截屏的activity
* @param path 圖片保存路徑
*/
public static void SaveScreenShot(Activity activity, String path) {
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(path);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
} catch (FileNotFoundException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
view.setDrawingCacheEnabled(false);
}
}
}