Android 自定义区域截图实现

来源:互联网 发布:java memset函数 编辑:程序博客网 时间:2024/06/14 20:24

最近做项目中截图的实现,实现了截图的功能,废话不多,上图才是王道




                                                                                                                            截图之前



                                                                                                                   截图之后






实现原理:

1、得到点击截图按钮时候全屏的截图
View view = activity.getWindow().getDecorView();    
view.setDrawingCacheEnabled(true);    
view.buildDrawingCache();    
Bitmap b1 = view.getDrawingCache();

2、把上面得到的全屏截图,作为surfaceview的背景图。(或设置透明背景的surfaceview)
在当前截图区域判断用户的点击滑动(画矩形、平移、拉伸)得到用户最终画出来的矩形。
具体处理比较复杂,详情见shotView中的事件处理。

3、从第一步中的得到的图片中截取出要截取的图片。
saveBitmap = Bitmap.createBitmap( ShotView.this.bitmap, rect.left, rect.top, rect.width( ), rect.height( ) );


主要截图实现类如下

package com.eebbk.view;import com.eebbk.activity.R;import android.app.AlertDialog;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.PaintFlagsDrawFilter;import android.graphics.Path;import android.graphics.PixelFormat;import android.graphics.Point;import android.graphics.Rect;import android.graphics.Paint.Style;import android.util.AttributeSet;import android.util.Log;import android.view.Gravity;import android.view.KeyEvent;import android.view.LayoutInflater;import android.view.MotionEvent;import android.view.SurfaceHolder;import android.view.SurfaceView;import android.view.View;import android.view.ViewGroup.LayoutParams;import android.widget.ImageView;import android.widget.PopupWindow;import android.widget.Toast;import static com.eebbk.util.Calc.getPointDis;public class ShotView extends SurfaceView implements SurfaceHolder.Callback, Runnable{private static final int RAD = 5;private Paint paint;private SurfaceHolder sh;private boolean isRunning = true;private Canvas canvas;private Bitmap bitmap = null;private Rect rect;private Point[] points = new Point[8];private Point startPoint;private Point endPoint;private Path path;private PopupWindow popupWindow;private Bitmap saveBitmap;// 截图画矩形的状态标志位 0未开始 1完成 2修改 3平移private int drawState = 0;// 修改点中的点private int index = -1;public void setIsRunning( boolean b ){// TODO Auto-generated method stubthis.isRunning = b;}public void setBitmap( Bitmap bitmap ){this.bitmap = bitmap;}public Bitmap getBitmap( ){return bitmap;}public ShotView( Context context ){super( context );// TODO Auto-generated constructor stubinit( );}public ShotView( Context context, AttributeSet attrs ){super( context, attrs );// TODO Auto-generated constructor stubinit( );}private void init( ){//注释的为实现透明画布效果//setZOrderOnTop(true);paint = new Paint( );sh = this.getHolder( );sh.addCallback( this );//sh.setFormat(PixelFormat.TRANSLUCENT);rect = new Rect( );startPoint = new Point( );endPoint = new Point( );path = new Path( );this.setFocusable( true );}@Overridepublic void surfaceCreated( SurfaceHolder holder ){// TODO Auto-generated method stubnew Thread( this ).start( );}@Overridepublic void surfaceChanged( SurfaceHolder holder, int format, int width, int height ){// TODO Auto-generated method stub}@Overridepublic void surfaceDestroyed( SurfaceHolder holder ){// TODO Auto-generated method stubisRunning = false;try {Thread.sleep(300);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic boolean onTouchEvent( MotionEvent event ){switch ( event.getAction( ) ){case MotionEvent.ACTION_DOWN:System.out.println( " down " );Point downPoint = new Point( ( int ) event.getX( ), ( int ) event.getY( ) );index = checkDownpoint( downPoint );if ( drawState == 1 && index != -1 ){// 如果点击的是4个顶点if ( index == 0 || index == 2 || index == 5 || index == 7 ){// 点中哪个点,选择对角点为画图起始点(类似于开始作图故不改drawState)startPoint = points[7 - index];}else if(index == 1 || index == 3 || index == 4 || index == 6){drawState = 2;}else if ( index == 8 ){ //平移drawState = 3;startPoint = downPoint;}}else{startPoint = downPoint;}path.moveTo( event.getX( ), event.getY( ) );break;case MotionEvent.ACTION_MOVE:path.lineTo( event.getX( ), event.getY( ) );endPoint.x = ( int ) event.getX( );endPoint.y = ( int ) event.getY( );int left = 0;int top = 0;int right = 0;int bottom = 0;// 第一次画 或者 画完之后第二次改变4个顶点if ( drawState == 0 || drawState == 1 ){left = Math.min( startPoint.x, endPoint.x );top = Math.min( startPoint.y, endPoint.y );right = Math.max( startPoint.x, endPoint.x );bottom = Math.max( startPoint.y, endPoint.y );rect.set( left, top, right, bottom );}// 第二次修改边上的中点else if ( drawState == 2 ){// 如果点击的是截图矩形宽的中点if ( index == 1 || index == 6 ){top = points[index - 1].y;bottom = points[index + 1].y;left = Math.min( points[7 - index].x, endPoint.x );right = Math.max( points[7 - index].x, endPoint.x );}// 点击的是截图矩形长的中点else if ( index == 3 || index == 4 ){left = points[index - 2].x;right = points[index + 2].x;top = Math.min( points[7 - index].y, endPoint.y );bottom = Math.max(  points[7 - index].y, endPoint.y );}rect.set( left, top, right, bottom );}//平移画好的四边形else if (drawState == 3) {int dx = endPoint.x - startPoint.x;int dy = endPoint.y - startPoint.y;//在屏幕区域内移动矩形框if ( rect.left > 0 && rect.right < getWidth( ) && rect.top > 0 && rect.bottom < getHeight( )){//如果这步移动之后截图矩形出去了,就不要移动了if ( !(rect.left + dx > 0 && rect.right + dx < getWidth( ) && rect.top + dy > 0 && rect.bottom + dy < getHeight( )) ){break;}rect.offset( dx,  dy);startPoint.x = endPoint.x;startPoint.y = endPoint.y;}System.out.println(rect);}break;case MotionEvent.ACTION_UP:Log.i( "MotionEvent.ACTION_UP", event.getX( ) + " " + event.getY( ) );if ( popupWindow != null ){popupWindow.dismiss( );popupWindow = null;}drawState = 1;View view = LayoutInflater.from( getContext( ) ).inflate( R.layout.popwindow_confirm, null );popupWindow = new PopupWindow( view, LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT );popupWindow.setOutsideTouchable( true );popupWindow.showAtLocation( this, Gravity.LEFT | Gravity.TOP, rect.right, rect.bottom );setPopListener( view );break;}return true;}// 检查down的点是否在画好的rect关键点上, 如果在返回-1,否则返回改点的indexprivate int checkDownpoint( Point downPoint ){// TODO Auto-generated method stubpoints[0] = new Point( rect.left, rect.top );points[1] = new Point( rect.left, ( rect.top + rect.bottom ) / 2 );points[2] = new Point( rect.left, rect.bottom );points[3] = new Point( ( rect.left + rect.right ) / 2, rect.top );points[4] = new Point( ( rect.left + rect.right ) / 2, rect.bottom );points[5] = new Point( rect.right, rect.top );points[6] = new Point( rect.right, ( rect.top + rect.bottom ) / 2 );points[7] = new Point( rect.right, rect.bottom );for ( int i = 0; i < points.length; i++ ){if ( getPointDis( points[i], downPoint ) < 3 * RAD ){return i;}}if ( downPoint.x > rect.left && downPoint.x < rect.right && downPoint.y > rect.top && downPoint.y < rect.bottom){return 8;}return -1;}private void setPopListener( View view ){// TODO Auto-generated method stubpopupWindow.getContentView( ).setOnTouchListener( new View.OnTouchListener( ){@Overridepublic boolean onTouch( View v, MotionEvent event ){if ( event.getAction( ) == MotionEvent.ACTION_OUTSIDE ){System.out.println( " 点击了外部,销毁啦!!!" );popupWindow.dismiss( );popupWindow = null;}return true;}} );view.findViewById( R.id.cancle_ll ).setOnClickListener( new OnClickListener( ){@Overridepublic void onClick( View v ){// TODO Auto-generated method stubToast.makeText( getContext( ), "重新截图!", Toast.LENGTH_SHORT ).show( );rect.setEmpty( );invalidate( );if ( popupWindow != null ){popupWindow.dismiss( );popupWindow = null;}}} );view.findViewById( R.id.back_ll ).setOnClickListener( new OnClickListener( ){@Overridepublic void onClick( View v ){// TODO Auto-generated method stubToast.makeText( getContext( ), "回到原来视图!", Toast.LENGTH_SHORT ).show( );rect.setEmpty( );invalidate( );if ( popupWindow != null ){popupWindow.dismiss( );popupWindow = null;}isRunning = false;setVisibility( View.INVISIBLE );}} );view.findViewById( R.id.ok_ll ).setOnClickListener( new OnClickListener( ){@Overridepublic void onClick( View v ){// TODO Auto-generated method stubToast.makeText( getContext( ), "截图完成!", Toast.LENGTH_SHORT ).show( );saveBitmap = Bitmap.createBitmap( ShotView.this.bitmap, rect.left, rect.top , rect.width( ), rect.height( ) );ImageView imgView = new ImageView( getContext());imgView.setImageBitmap( saveBitmap );new AlertDialog.Builder(getContext( ))  .setTitle("截取到的图片")  .setView(imgView)  .setPositiveButton("确定", null)  .show();  }} );}@Overridepublic void run( ){// TODO Auto-generated method stubwhile ( isRunning ){drawView( );try{Thread.sleep( 100 );}catch ( InterruptedException e ){// TODO Auto-generated catch blocke.printStackTrace( );}}}private void drawView( ){// TODO Auto-generated method stubtry{if ( sh != null ){canvas = sh.lockCanvas( );//抗锯齿canvas.setDrawFilter( new PaintFlagsDrawFilter( 0, Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG ) );canvas.drawBitmap( bitmap, 0,0, null );// 不填充paint.setStyle( Style.STROKE );// canvas.drawPath( path, paint );paint.setColor( Color.BLUE );paint.setStrokeWidth( 2 );canvas.drawRect( rect, paint );paint.setStyle( Paint.Style.FILL );paint.setColor( Color.GREEN );//paint.setStrokeWidth( 3 );canvas.drawCircle( rect.left, rect.top, RAD, paint );// 画点,参数一水平x轴,参数二垂直y轴,第三个参数为Paint对象。canvas.drawCircle( rect.left, ( rect.top + rect.bottom ) / 2, RAD, paint );canvas.drawCircle( rect.left, rect.bottom, RAD, paint );canvas.drawCircle( ( rect.left + rect.right ) / 2, rect.top, RAD, paint );canvas.drawCircle( ( rect.left + rect.right ) / 2, rect.bottom, RAD, paint );canvas.drawCircle( rect.right, rect.top, RAD, paint );canvas.drawCircle( rect.right, ( rect.top + rect.bottom ) / 2, RAD, paint );canvas.drawCircle( rect.right, rect.bottom, RAD, paint );}}catch ( Exception e ){e.printStackTrace( );}finally{if ( canvas != null )sh.unlockCanvasAndPost( canvas );}}@Override    public boolean onKeyDown(int keyCode, KeyEvent event)    {        if(keyCode == KeyEvent.KEYCODE_BACK)        {            isRunning = false;        }        return super.onKeyDown(keyCode, event);    }}


经过测试,没有明显严重bug,最后附上demo源码

http://download.csdn.net/detail/tianmi1988/4859217

难免会有疏漏,欢迎大家指正,共同进步!