android QQ截圖 開發
使用過QQ的同學應該都用過QQ截圖,Ctrl+Alt+A進入截圖操作,通過拉伸,移動高亮區域的框體可以快速擷取我們需要的圖片。在android應用中,我們也經常需要截圖操作,以下實現了一個類似QQ截圖的應用。先貼圖看看效果:
自定義CaptureView,在CaptureView上繪製具有一個可拉伸,移動的高亮矩形框,通過FrameLayout佈局將這個CaptureView覆蓋到需要截圖的圖片顯示控制元件ImageView上,當點選截圖按鈕後,計算CaptureView矩形框的座標值及寬和高讀取圖片相映區域的畫素,並將這些畫素通過畫布重新繪製成圖片。
首先先上佈局檔案:main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#FFFFFFFF"
android:orientation="vertical" >
<FrameLayout
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1" >
<!-- 顯示圖片 -->
<ImageView
android:id="@+id/iv_image"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:scaleType="fitXY" />
<!-- 自定義的截圖View -->
<gwn.test.capture.CaptureView
android:id="@+id/capture"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
<!-- 截圖顯示 -->
<ImageView
android:id="@+id/iv_corp"
android:layout_width="100dip"
android:layout_height="100dip"
android:layout_gravity="right"
android:background="#50000000"
android:scaleType="centerInside" />
</FrameLayout>
<Button
android:id="@+id/btn_crop"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="截圖" />
</LinearLayout>
佈局檔案很簡單,接下來主角就要登場了,當然這就是CaptureViewr的實現。CaptureView需要繪製的部分有三個,分別為整個View可視範圍viewRect,矩形框體captureRect,拉伸時的顯示箭頭。CaptureView的觸控事件型別有三種:無操作、移動、拉伸,程式碼定義如下:
private enum ActionMode { // 列舉動作型別:無、移動、拉伸
None, Move, Grow
}
首先先計算viewRect,captureView的大小,我們在系統給View指派大小的地方初始化這兩個區域,即在onLayout()方法中實現。程式碼如下:
protected void onLayout(boolean changed, int left, int top, int right,
int bottom) {
super.onLayout(changed, left, top, right, bottom);
// 初始化可視範圍及框體大小
viewRect = new Rect(left, top, right, bottom);
int viewWidth = right - left;
int viewHeight = bottom - top;
int captureWidth = Math.min(viewWidth, viewHeight) * 3 / 5;
int captureHeight = viewHeight * 2 / 5;
// 將框體繪製在可視範圍中間位置
int captureX = (viewWidth - captureWidth) / 2;
int captureY = (viewHeight - captureHeight) / 2;
captureRect = new Rect(captureX, captureY, captureX + captureWidth,
captureY + captureHeight);
}
接下來重寫ondraw(Canvas canvas),將可視範圍、框體區域,箭頭繪製上去:
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub
super.onDraw(canvas);
canvas.save();
Path path = new Path();
path.addRect(new RectF(captureRect), Path.Direction.CW);// 順時針閉合框體
canvas.clipPath(path, Region.Op.DIFFERENCE);
canvas.drawRect(viewRect, outsideCapturePaint); // 繪製框體外圍區域
canvas.drawPath(path, lineCapturePaint); // 繪製框體
canvas.restore();
if (mMode == ActionMode.Grow) { // 拉伸操作時,繪製框體箭頭
int xMiddle = captureRect.left + captureRect.width() / 2; // 框體中間X座標
int yMiddle = captureRect.top + captureRect.height() / 2; // 框體中間Y座標
// 框體左邊的箭頭
horStretchArrows.setBounds(captureRect.left
- horStretchArrowsHalfWidth, yMiddle
- horStretchArrowsHalfHeigth, captureRect.left
+ horStretchArrowsHalfWidth, yMiddle
+ horStretchArrowsHalfHeigth);
horStretchArrows.draw(canvas);
// 框體右邊的箭頭
horStretchArrows.setBounds(captureRect.right
- horStretchArrowsHalfWidth, yMiddle
- horStretchArrowsHalfHeigth, captureRect.right
+ horStretchArrowsHalfWidth, yMiddle
+ horStretchArrowsHalfHeigth);
horStretchArrows.draw(canvas);
// 框體上方的箭頭
verStretchArrows.setBounds(xMiddle - verStretchArrowsHalfWidth,
captureRect.top - verStretchArrowsHalfHeigth, xMiddle
+ verStretchArrowsHalfWidth, captureRect.top
+ verStretchArrowsHalfHeigth);
verStretchArrows.draw(canvas);
// 框體下方的箭頭
verStretchArrows.setBounds(xMiddle - verStretchArrowsHalfWidth,
captureRect.bottom - verStretchArrowsHalfHeigth, xMiddle
+ verStretchArrowsHalfWidth, captureRect.bottom
+ verStretchArrowsHalfHeigth);
verStretchArrows.draw(canvas);
}
}
重頭戲來了,CaptureView的事件監聽。首先定義觸控位置及動作,程式碼:
// 觸控位置及動作
public static final int GROW_NONE = (1 << 0);//框體外部
public static final int GROW_LEFT_EDGE = (1 << 1);//框體左邊緣
public static final int GROW_RIGHT_EDGE = (1 << 2);//框體右邊緣
public static final int GROW_TOP_EDGE = (1 << 3);//框體上邊緣
public static final int GROW_BOTTOM_EDGE = (1 << 4);//框體下邊緣
public static final int GROW_MOVE = (1 << 5);//框體移動
// 確定觸控位置及動作,分別為觸控框體外圍和框體上、下、左、右邊緣以及框體內部。
private int getGrow(float x, float y) {
final float effectiveRange = 20F; // 觸控的有效範圍大小
int grow = GROW_NONE;
int left = captureRect.left;
int top = captureRect.top;
int right = captureRect.right;
int bottom = captureRect.bottom;
boolean verticalCheck = (y >= top - effectiveRange)
&& (y < bottom + effectiveRange);
boolean horizCheck = (x >= left - effectiveRange)
&& (x < right + effectiveRange);
// 觸控了框體左邊緣
if ((Math.abs(left - x) < effectiveRange) && verticalCheck) {
grow |= GROW_LEFT_EDGE;
}
// 觸控了框體右邊緣
if ((Math.abs(right - x) < effectiveRange) && verticalCheck) {
grow |= GROW_RIGHT_EDGE;
}
// 觸控了框體上邊緣
if ((Math.abs(top - y) < effectiveRange) && horizCheck) {
grow |= GROW_TOP_EDGE;
}
// 觸控了框體下邊緣
if ((Math.abs(bottom - y) < effectiveRange) && horizCheck) {
grow |= GROW_BOTTOM_EDGE;
}
// 觸控框體內部
if (grow == GROW_NONE && captureRect.contains((int) x, (int) y)) {
grow = GROW_MOVE;
}
return grow;
}
如果grow的值不為GROW_NONE,也即使用者觸控位置在框體邊緣或框體內部,那麼就鎖定使用者本次觸控,直到使用者放開觸控釋放。判斷使用者的移動事件是伸縮框體還是移動框體,如果是伸縮框體,則呼叫growBy()方法拉伸框體,否則呼叫moveBy()移動框體程式碼如下:
private void handleMotion(int grow, float dx, float dy) {
if (grow == GROW_NONE) {
return;
} else if (grow == GROW_MOVE) {
moveBy(dx, dy); // 移動框體
} else {
if (((GROW_LEFT_EDGE | GROW_RIGHT_EDGE) & grow) == 0) {
dx = 0; // 水平不伸縮
}
if (((GROW_TOP_EDGE | GROW_BOTTOM_EDGE) & grow) == 0) {
dy = 0; // 垂直不伸縮
}
growBy((((grow & GROW_LEFT_EDGE) != 0) ? -1 : 1) * dx,
(((grow & GROW_TOP_EDGE) != 0) ? -1 : 1) * dy);
}
}
下面是貼上這兩個方法,有關說明見註釋
private void moveBy(float dx, float dy) {
Rect invalRect = new Rect(captureRect);
captureRect.offset((int) dx, (int) dy);
captureRect.offset(Math.max(0, viewRect.left - captureRect.left),
Math.max(0, viewRect.top - captureRect.top));
captureRect.offset(Math.min(0, viewRect.right - captureRect.right),
Math.min(0, viewRect.bottom - captureRect.bottom));
//清除移動滯留的痕跡
invalRect.union(captureRect);//更新圍繞本身區域和指定的區域,
invalRect.inset(-100, -100);
invalidate(invalRect); // 重繪指定區域
}
private void growBy(float dx, float dy) {
float widthCap = 50F; //captureRect最小寬度
float heightCap = 50F; //captureRect最小高度
RectF r = new RectF(captureRect);
//當captureRect拉伸到寬度 = viewRect的寬度時,則調整dx的值為 0
if (dx > 0F && r.width() + 2 * dx >= viewRect.width()) {
dx = 0F;
}
//同上
if (dy > 0F && r.height() + 2 * dy >= viewRect.height()) {
dy = 0F;
}
r.inset(-dx, -dy); // 框體邊緣外移
//當captureRect縮小到寬度 = widthCap時
if (r.width() <= widthCap) {
r.inset(-(widthCap - r.width()) / 2F, 0F);
}
//同上
if (r.height() <= heightCap) {
r.inset(0F, -(heightCap - r.height()) / 2F);
}
if (r.left < viewRect.left) {
r.offset(viewRect.left - r.left, 0F);
} else if (r.right > viewRect.right) {
r.offset(-(r.right - viewRect.right), 0);
}
if (r.top < viewRect.top) {
r.offset(0F, viewRect.top - r.top);
} else if (r.bottom > viewRect.bottom) {
r.offset(0F, -(r.bottom - viewRect.bottom));
}
captureRect.set((int) r.left, (int) r.top, (int) r.right,
(int) r.bottom);
invalidate();
}
接下來看下截圖操作,由於ImageView顯示的圖片跟原始圖片有比例上的區別,因此,先取得調整比例的圖片,程式碼說明:
// ImageView中的影象是跟實際的圖片有比例縮放,因此需要調整圖片比例
private Bitmap regulationBitmap(Bitmap bitmap) {
int ivWidth = ivImage.getWidth();
int ivHeight = ivImage.getHeight();
int bmpWidth = bitmap.getWidth();
int bmpHeight = bitmap.getHeight();
// 寬和高的比例
float scaleWidth = (float) ivWidth / bmpWidth;
float scaleHeight = (float) ivHeight / bmpHeight;
Matrix matrix = new Matrix();
matrix.postScale(scaleWidth, scaleHeight);
Bitmap resizeBmp = Bitmap.createBitmap(bitmap, 0, 0, bmpWidth,
bmpHeight, matrix, true);
return resizeBmp;
}
截圖程式碼:
private Bitmap cropImage(){
Rect cropRect = mCaptureView.getCaptureRect();
int width = cropRect.width();
int height = cropRect.height();
Bitmap croppedImage = Bitmap.createBitmap(width,
height, Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(croppedImage);
Rect dstRect = new Rect(0, 0, width, height);
// 調整圖片顯示比例
mBitmap = regulationBitmap(mBitmap);
canvas.drawBitmap(mBitmap, cropRect, dstRect, null);
return croppedImage;
}
相關文章
- Android 截圖Android
- Android 普通View截圖 RecyclerView截圖 ScrollView截圖分享AndroidView
- w10系統qq怎麼截圖快捷鍵 win10系統qq如何截圖快捷鍵Win10
- win10 qq 截圖黑色怎麼解決_win10QQ截圖會突然黑屏解決辦法Win10
- win10 qq截圖不管用了怎麼解決_win10 qq截圖不了修復方法Win10
- Android截圖方案Android
- Android下截圖Android
- Android截圖和指定View生成截圖分享AndroidView
- [android]android命令列截圖Android命令列
- Android截圖監聽Android
- Android下截圖-2Android
- Win10系統下怎麼使用qq截圖【圖文教程】Win10
- android截圖功能實現Android
- android 截圖程式碼段Android
- android截圖方法總結Android
- QQbug--QQ截圖不顯示儲存型別型別
- Android長截圖的實現Android
- android 螢幕截圖原始碼Android原始碼
- 快速簡化Android截圖工作Android
- android圖片編輯,類似PC端QQ截圖後的編輯效果(畫箭頭,圓形,矩形標註)Android
- 《Visual Studio 2017 Web 開發》截圖Web
- 用electron開發了一個螢幕截圖工具
- Android 截圖的各種騷操作Android
- Android 5.0 螢幕錄製/截圖Android
- Android螢幕截圖方式總結Android
- Android 合併生成分享圖片(View截圖)AndroidView
- Android 截圖實現的幾種方式Android
- Arcgis For Android 中MapView 截圖獲取BitmapAndroidView
- MacOS專業截圖指南——截圖技巧和截圖工具分享Mac
- Android 截圖與 WebView 長圖分享經驗總結AndroidWebView
- win10qq發圖片很卡怎麼辦_win10qq發圖片很卡如何解決Win10
- 從0到1,手把手帶你開發截圖工具ScreenCap------001實現基本的截圖功能
- C#軟體開發例項.私人訂製自己的螢幕截圖工具(四)基本截圖功能實現C#
- 電腦怎麼截圖win10_win10如何截圖截圖Win10
- Python網頁截圖/螢幕截圖/截長圖如何實現?Python網頁
- win10qq聊天廣告怎樣攔截_win10電腦qq聊天廣告攔截怎麼設定Win10
- 直播app開發,保護直播內容新增的禁止截圖功能APP
- Android系統開發小記:QQ微信視訊畫面方向旋轉Android