最近一直在搞水印相關的業務,整體添加水印,網上代碼一大堆,但是如果接入自身業務邏輯還是必須對添加水印有一個基本瞭解。特別是瑣碎的技能點工具類等,挺耽誤時間, 所以在這裏總結記錄下。
- 獲取屏幕View大小,測量擺放等。
- 根據屏幕View控件生成Bitmap並返回
- 選擇圖片 - 一個好用的選擇圖片,裁剪的輪子
- 一個完整的圖片添加水印,美顏,磨皮等Demo
屏幕相關,View寬高度測量,擺放。
1、工具類 ScreenUtils 提供功能:獲取屏幕高度, 寬度, 狀態欄高度, 當前屏幕截屏
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.view.View;
import android.view.WindowManager;
//獲得屏幕相關的輔助類
public class ScreenUtils
{
private ScreenUtils()
{
/* cannot be instantiated */
throw new UnsupportedOperationException("cannot be instantiated");
}
/**
* 獲得屏幕高度
*
* @param context
* @return
*/
public static int getScreenWidth(Context context)
{
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.widthPixels;
}
/**
* 獲得屏幕寬度
*
* @param context
* @return
*/
public static int getScreenHeight(Context context)
{
WindowManager wm = (WindowManager) context
.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics outMetrics = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(outMetrics);
return outMetrics.heightPixels;
}
/**
* 獲得狀態欄的高度
*
* @param context
* @return
*/
public static int getStatusHeight(Context context)
{
int statusHeight = -1;
try
{
Class<?> clazz = Class.forName("com.android.internal.R$dimen");
Object object = clazz.newInstance();
int height = Integer.parseInt(clazz.getField("status_bar_height")
.get(object).toString());
statusHeight = context.getResources().getDimensionPixelSize(height);
} catch (Exception e)
{
e.printStackTrace();
}
return statusHeight;
}
/**
* 獲取當前屏幕截圖,包含狀態欄
*
* @param activity
* @return
*/
public static Bitmap snapShotWithStatusBar(Activity activity)
{
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, 0, width, height);
view.destroyDrawingCache();
return bp;
}
/**
* 獲取當前屏幕截圖,不包含狀態欄
*
* @param activity
* @return
*/
public static Bitmap snapShotWithoutStatusBar(Activity activity)
{
View view = activity.getWindow().getDecorView();
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
Bitmap bmp = view.getDrawingCache();
Rect frame = new Rect();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(frame);
int statusBarHeight = frame.top;
int width = getScreenWidth(activity);
int height = getScreenHeight(activity);
Bitmap bp = null;
bp = Bitmap.createBitmap(bmp, 0, statusBarHeight, width, height
- statusBarHeight);
view.destroyDrawingCache();
return bp;
}
}
2、獲取控件的高度,寬度
方法一:
int w = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
int h = View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED);
mTextView.measure(w, h);
int height = mTextView.getMeasuredHeight();
int width = mTextView.getMeasuredWidth();
這個方法限制挺大,我使用的結果是並沒有返回正確的高度,和寬度。猜測應該是我直接在XML 中寫死了控件的寬高,所以並沒有正確返回。並且網上代碼都有說明需要在oncreat中書寫。那麼一些動態佈局就無法使用。
方法二:
ViewTreeObserver vto = _root.getViewTreeObserver();
vto.addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
_root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int _view2_w = _view2.getWidth();
int _view2_h = _view2.getHeight();
}
});
測試有效,ViewTreeObserver 是監聽屏幕視圖發生改變時候的監聽。在這裏獲取 你所要view 的高度寬度是可以去到具體值,不過個監聽既然是監聽屏幕視圖發生變化,所以肯定會發揮多次結果。猜測我是使用_root xml最外成父佈局獲取監聽才導致獲取多個結果。(前幾次都是 0),可以使用直接測量的控件去獲取 屏幕的寬度。
方法三:
@Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
if (hasFocus)
{
System.out.println("onWindowFocusChanged width=" + mTextView.getWidth() + " height=" + mTextView.getHeight());
}
}
方法未測試,先記錄下來,以免特殊場景下使用。
3、計算控件寬高,擺放位置,view隨手指一動滑動 仿Keep 水印功能。
我使用獲取屏幕高度,動態設置控件高度,把水印添加至圖片相對位置。然後重寫onTouch ,控制手指控制水印。
_view2.setOnTouchListener(this);
@Override
public boolean onTouch(View v, MotionEvent event) {
final int X = (int) event.getRawX();
final int Y = (int) event.getRawY();
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
RelativeLayout.LayoutParams lParams = (RelativeLayout.LayoutParams) _view2.getLayoutParams();
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_POINTER_DOWN:
break;
case MotionEvent.ACTION_POINTER_UP:
break;
case MotionEvent.ACTION_MOVE:
int dx = (int) event.getRawX() - lastX;
int dy = (int) event.getRawY() - lastY;
int left = _view2.getLeft() + dx;
int top = _view2.getTop() + dy;
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) _view2.getLayoutParams();
layoutParams.leftMargin = left;
layoutParams.topMargin = top;
// _view2 就是屏幕上添加一個控件,當成水印。這樣水印就可以根據手指一動而滑動。
_view2.setLayoutParams(layoutParams);
lastX = (int) event.getRawX();
lastY = (int) event.getRawY();
Log.e("lipeng", "lastX:" + lastX + "lastY:" + lastY);
break;
}
_root.invalidate();
return true;
動態擺放控件位置,其實看到上面代碼,已經寫的很清楚了,直接利用 layoutParams API 達到控件動態擺放的功能
RelativeLayout.LayoutParams lParams;
lParams = (RelativeLayout.LayoutParams) _view2.getLayoutParams();
lParams.leftMargin = width;
lParams.topMargin = height;
_view2.setLayoutParams(lParams);
根據屏幕View控件生成Bitmap並返回
剛剛知道要做一個添加水印的功能的時候,我就打算使用這個方法。
其實我們看看一般添加水印的做法,
// 創建一個新的和SRC長度寬度一樣的位圖
Bitmap newb = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//將該圖片作爲畫布
Canvas canvas = new Canvas(newb);
//在畫布 0,0座標上開始繪製原始圖片
canvas.drawBitmap(src, 0, 0, null);
//在畫布上繪製水印圖片
canvas.drawBitmap(watermark, paddingLeft, paddingTop, null);
// 保存
canvas.save(Canvas.ALL_SAVE_FLAG);
// 存儲
canvas.restore();
但是使用這樣的方法添加水印,無法達到keep那種手指控制
所以就想使用RelativeLayout 佈局包裹,直接每次添加水印就 new imageview 最後使用RelativeLayout生成一個bitmap對象。
————————————————————————————————————————————————————————————————
整個屏幕截圖
public static Bitmap getNormalViewScreenshot(View view) {
view.setDrawingCacheEnabled(true);
view.buildDrawingCache();
return view.getDrawingCache();
}
scrollview的整體截屏
public static Bitmap getWholeScrollViewToBitmap(View view) {
view.measure(MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
view.layout(0, 0, view.getMeasuredWidth(), view.getMeasuredHeight());
view.buildDrawingCache();
Bitmap bitmap = view.getDrawingCache();
return bitmap;
}
webview的整體截圖
public static Bitmap getWholeWebViewToBitmap(WebView webView) {
Picture snapShot = webView.capturePicture();
Bitmap bmp = Bitmap.createBitmap(snapShot.getWidth(), snapShot.getHeight(), Bitmap.Config.ARGB_8888);
Canvas canvas = new Canvas(bmp);
snapShot.draw(canvas);
return bmp;
}
listview的整體截圖
public static Bitmap getWholeListViewItemsToBitmap(ListView listview) {
ListAdapter adapter = listview.getAdapter();
int itemscount = adapter.getCount();
int allitemsheight = 0;
List<Bitmap> bmps = new ArrayList<Bitmap>();
for (int i = 0; i < itemscount; i++) {
View childView = adapter.getView(i, null, listview);
childView.measure(MeasureSpec.makeMeasureSpec(listview.getWidth(), MeasureSpec.EXACTLY),
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
childView.layout(0, 0, childView.getMeasuredWidth(), childView.getMeasuredHeight());
childView.setDrawingCacheEnabled(true);
childView.buildDrawingCache();
bmps.add(childView.getDrawingCache());
allitemsheight += childView.getMeasuredHeight();
}
Bitmap bigbitmap = Bitmap.createBitmap(listview.getMeasuredWidth(), allitemsheight, Bitmap.Config.ARGB_8888);
Canvas bigcanvas = new Canvas(bigbitmap);
Paint paint = new Paint();
int iHeight = 0;
for (int i = 0; i < bmps.size(); i++) {
Bitmap bmp = bmps.get(i);
bigcanvas.drawBitmap(bmp, 0, iHeight, paint);
iHeight += bmp.getHeight();
bmp.recycle();
bmp = null;
}
return bigbitmap;
}
需要多次截圖的話,需要用到 view.destroyDrawingCache();
Bitmap normalViewScreenshot = ScreenShotUtils.getNormalViewScreenshot(mFrameContent);
if (normalViewScreenshot != null) {
Bitmap b = Bitmap.createBitmap(normalViewScreenshot);
mImageResult.setImageBitmap(b);
mFrameContent.destroyDrawingCache();
}
當然這樣的方式也可以使用到屏幕截圖的相關業務上,如果產品需要加一個截圖成功的效果,可以參考
Android屏幕截圖,View截圖(乾貨)
android 獲取界面部分view,view截圖,生成bitmap圖片
——————————————————————————————————————————————————————————————
選擇圖片 - 一個好用的選擇圖片,裁剪的輪子
詳細使用流程可以去項目地址看下,目前項目中使用的就是這個輪子,目前沒有發現致命bug
——————————————————————————————————————————————————————————————
一個完整的圖片添加水印,美顏,磨皮等Demo
這個項目發現的有點晚了,自己琢磨了三四天,上週五完成業務demo,交差的時候,產品告訴我如果可以的話,添加美顏,磨皮等功能。然後我github上開始找相關輪子。然後發現了這個demo,原版demo地址已經找不到了,自己傳是csdn一份
我拍了一個視頻,但是做gif圖片太。
CSDN 資源地址,github上的鏈接沒有找到所以就打包上傳到csdn上了,沒有積分的可以github上翻一翻。