最近一直在搞水印相关的业务,整体添加水印,网上代码一大堆,但是如果接入自身业务逻辑还是必须对添加水印有一个基本了解。特别是琐碎的技能点工具类等,挺耽误时间, 所以在这里总结记录下。
- 获取屏幕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上翻一翻。