赞
踩
二、在github里面种找到了一个类似度挺高的开源项目:
github中的第三方的开源项目地址:
在第三方的FabricView的项目中已经实现了:
1.控件的可以绘制;4.手势滑动的识别?
5.缩放之后的滑动识别?
三、需求改造:
把开源项目经过修剪和添加来实现自己项目中的画布功能
1.在画板上连线已经实现:
- public boolean onTouchDrawMode(MotionEvent event)
- {
- // get location of touch
- float eventX = event.getX();
- float eventY = event.getY();
-
- // based on the users action, start drawing
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // create new path and paint
- currentPath = new CPath();
- currentPaint = new Paint();
- currentPaint.setAntiAlias(true);
- currentPaint.setColor(mColor);
- currentPaint.setStyle(mStyle);
- currentPaint.setStrokeJoin(Paint.Join.ROUND);
- currentPaint.setStrokeWidth(mSize);
- currentPath.moveTo(eventX, eventY);
- currentPath.setPaint(currentPaint);
- // capture touched locations
- lastTouchX = eventX;
- lastTouchY = eventY;
- Log.i("Everbrilliant","点下去位置lastTouchX:"+lastTouchX+">>lastTouchY:"+lastTouchY);
- mDrawableList.add(currentPath);
- return true;
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_UP:
- currentPath.lineTo(eventX, eventY);
- // When the hardware tracks events faster than they are delivered, the
- // event will contain a history of those skipped points.
- int historySize = event.getHistorySize();
- for (int i = 0; i < historySize; i++) {
- float historicalX = event.getHistoricalX(i);
- float historicalY = event.getHistoricalY(i);
- Log.i("everb","存在缓存中的值historicalX:"+historicalX+">>historicalY:"+historicalY);
- if (historicalX < dirtyRect.left) {
- dirtyRect.left = historicalX;
- } else if (historicalX > dirtyRect.right) {
- dirtyRect.right = historicalX;
- }
- if (historicalY < dirtyRect.top) {
- dirtyRect.top = historicalY;
- } else if (historicalY > dirtyRect.bottom) {
- dirtyRect.bottom = historicalY;
- }
- currentPath.lineTo(historicalX, historicalY);
- }
-
- // After replaying history, connect the line to the touch point.
- currentPath.lineTo(eventX, eventY);
- cleanDirtyRegion(eventX, eventY);
- break;
- default:
- return false;
- }
-
- // Include some padding to ensure nothing is clipped
- invalidate(
- (int) (dirtyRect.left - 20),
- (int) (dirtyRect.top - 20),
- (int) (dirtyRect.right + 20),
- (int) (dirtyRect.bottom + 20));
-
- // register most recent touch locations
- lastTouchX = eventX;
- lastTouchY = eventY;
- return true;
- }

2.绘制控件只要一类实现CDrawable的接口并把这控件添加FabricView画布的onDraw方法中的数组中既可以
- private ArrayList<CDrawable> mDrawableList = new ArrayList<>();
- /*
- * Called when there is the canvas is being re-drawn.
- */
- @Override
- protected void onDraw(Canvas canvas) {
- // check if background needs to be redrawn
- mBackgroundMode=BACKGROUND_STYLE_NOTEBOOK_PAPER;
- drawBackground(canvas, mBackgroundMode);
-
- // go through each item in the list and draw it
- for (int i = 0; i < mDrawableList.size(); i++) {
- try {
- mDrawableList.get(i).draw(canvas);
- }
-
- catch(Exception ex)
- {
-
- }
- }
- }

3.至于画布的缩放方法可以用view中的setScaleX、setScaleY来实现缩放。这里在放大后还要画布是可以拖动到:
- private void updateScaleStep(int newScaleIndex) {
- if (newScaleIndex != mCurrentZoomScaleIndex) {
- final float oldViewScale = mViewScale;
-
- mCurrentZoomScaleIndex = newScaleIndex;
- mViewScale = ZOOM_SCALES[mCurrentZoomScaleIndex];
- final float scaleDifference = mViewScale - oldViewScale;
- scrollBy((int) (scaleDifference * getMeasuredWidth() / 2),
- (int) (scaleDifference * getMeasuredHeight() / 2));
-
- if (shouldDrawGrid()) {
- mGridRenderer.updateGridBitmap(mViewScale);
- }
-
- mWorkspaceView.setScaleX(mViewScale);
- mWorkspaceView.setScaleY(mViewScale);
- mWorkspaceView.requestLayout();
- }
- }

- mTapGestureDetector = new GestureDetector(getContext(), new TapGestureListener()); //设置手势的监听
-
- private class TapGestureListener implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
-
- @Override
- public boolean onDown(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent motionEvent) {
-
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent motionEvent) {
- // TODO: 2017/6/29 长按可以设置模式为连线
- Toast.makeText(mContext,"实现了长按手势",Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
- return false;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent motionEvent) {
- return false;
- }
- }

- mScaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureListener()); //设置手势缩放的监听
-
- private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
- private float mStartFocusX;
- private float mStartFocusY;
- private float mStartScale;
- private int mStartScrollX;
- private int mStartScrollY;
-
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- mStartFocusX = detector.getFocusX();
- mStartFocusY = detector.getFocusY();
- mStartScrollX = getScrollX();
- mStartScrollY = getScrollY();
-
- mStartScale = mViewScale;
- return true;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- final float oldViewScale = mViewScale;
-
- final float scaleFactor = detector.getScaleFactor();
- mViewScale *= scaleFactor;
-
- if (mViewScale < ZOOM_SCALES[0]) {
- mCurrentZoomScaleIndex = 0;
- mViewScale = ZOOM_SCALES[mCurrentZoomScaleIndex];
- } else if (mViewScale > ZOOM_SCALES[ZOOM_SCALES.length - 1]) {
- mCurrentZoomScaleIndex = ZOOM_SCALES.length - 1;
- mViewScale = ZOOM_SCALES[mCurrentZoomScaleIndex];
- } else {
- float minDist = Float.MAX_VALUE;
- int index = ZOOM_SCALES.length - 1;
- for (int i = 0; i < ZOOM_SCALES.length; i++) {
- float dist = Math.abs(mViewScale - ZOOM_SCALES[i]);
- if (dist < minDist) {
- minDist = dist;
- } else {
- index = i - 1;
- break;
- }
- }
- mCurrentZoomScaleIndex = index;
- }
- ActionEditorCanvasView.this.setScaleX(mViewScale);
- ActionEditorCanvasView.this.setScaleY(mViewScale);
- final float scaleDifference = mViewScale - mStartScale;
- final int scrollScaleX = (int) (scaleDifference * mStartFocusX);
- final int scrollScaleY = (int) (scaleDifference * mStartFocusY);
- final int scrollPanX = (int) (mStartFocusX - detector.getFocusX());
- final int scrollPanY = (int) (mStartFocusY - detector.getFocusY());
- scrollTo(mStartScrollX + scrollScaleX + scrollPanX,
- mStartScrollY + scrollScaleY + scrollPanY);
- return true;
- }
- }

四.核心类的分析:- CDrawable {
- Paint getPaint(); //获取Paint
- int getXcoords(); //获取X轴坐标
- int getYcoords(); //获取Y轴坐标
- void setXcoords(int x); //设置X轴坐标
- void setYcoords(int y); //设置Y轴坐标
- void setPaint(Paint p); //设置画笔
- void draw(Canvas canvas); //绘制画板
- }
2.FabricView抽象类继承于View,主要功能是把控件绘制到这个画布中、绘制画布的背景、区分了几种绘制模式。
- public abstract class FabricView extends View {
- // painting objects and properties
- public ArrayList<CDrawable> mDrawableList = new ArrayList<>();
- private int mColor = Color.BLACK;
-
- // Canvas interaction modes
- private int mInteractionMode = DRAW_MODE;
-
- // background color of the library
- private int mBackgroundColor = Color.WHITE;
- // default style for the library
- private Paint.Style mStyle = Paint.Style.STROKE;
-
- // default stroke size for the library 默认点击的尺寸
- private float mSize = 5f;
-
- // flag indicating whether or not the background needs to be redrawn
- private boolean mRedrawBackground;
-
- // background mode for the library, default to blank
- private int mBackgroundMode = BACKGROUND_STYLE_BLANK;
-
- // Default Notebook left line color
- public static final int NOTEBOOK_LEFT_LINE_COLOR = Color.RED;
-
- // Flag indicating that we are waiting for a location for the text
- private boolean mTextExpectTouch;
-
- // Vars to decrease dirty area and increase performance
- private float lastTouchX, lastTouchY;
- private final RectF dirtyRect = new RectF();
-
- // keep track of path and paint being in use
- CPath currentPath;
- Paint currentPaint;
-
- /*********************************************************************************************/
- /************************************ FLAGS *******************************************/
- /*********************************************************************************************/
- // Default Background Styles 背景颜色
- public static final int BACKGROUND_STYLE_BLANK = 0;
- public static final int BACKGROUND_STYLE_NOTEBOOK_PAPER = 1;
- public static final int BACKGROUND_STYLE_GRAPH_PAPER = 2;
-
- // Interactive Modes
- public static final int DRAW_MODE = 0;
- public static final int SELECT_MODE = 1; // TODO Support Object Selection.
- public static final int ROTATE_MODE = 2; // TODO Support Object ROtation.
- public static final int LOCKED_MODE = 3;
-
- /*********************************************************************************************/
- /********************************** CONSTANTS *****************************************/
- /*********************************************************************************************/
- public static final int NOTEBOOK_LEFT_LINE_PADDING = 120;
-
- /*********************************************************************************************/
- /************************************ TO-DOs ******************************************/
- /*********************************************************************************************/
- private float mZoomLevel = 1.0f; //TODO Support Zoom 要去做支持放大缩小的功能
- private float mHorizontalOffset = 1, mVerticalOffset = 1; // TODO Support Offset and Viewport 支持可以偏移的功能
- public int mAutoscrollDistance = 100; // TODO Support Autoscroll
-
-
- /**
- * Default Constructor, sets sane values.
- *
- * @param context the activity that containts the view
- * @param attrs view attributes
- */
- public FabricView(Context context, AttributeSet attrs) {
- super(context, attrs);
- setFocusable(true);
- setFocusableInTouchMode(true);
- this.setBackgroundColor(mBackgroundColor);
- mTextExpectTouch = false;
-
- }
-
- /**
- * Called when there is the canvas is being re-drawn.
- */
- @Override
- protected void onDraw(Canvas canvas) {
- // check if background needs to be redrawn
- mBackgroundMode=BACKGROUND_STYLE_NOTEBOOK_PAPER;
- drawBackground(canvas, mBackgroundMode);
-
- // go through each item in the list and draw it
- for (int i = 0; i < mDrawableList.size(); i++) {
- try {
- mDrawableList.get(i).draw(canvas);
- }
-
- catch(Exception ex)
- {
-
- }
- }
- }
-
-
- /*********************************************************************************************/
- /******************************* Handling User Touch **********************************/
- /*********************************************************************************************/
-
- /**
- * Handles user touch event
- *
- * @param event the user's motion event
- * @return true, the event is consumed.
- */
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- // delegate action to the correct method
- if (getInteractionMode() == DRAW_MODE) //绘画的模式
- return onTouchDrawMode(event);
- else if (getInteractionMode() == SELECT_MODE) //选择的模式
- return onTouchSelectMode(event);
- else if (getInteractionMode() == ROTATE_MODE)
- return onTouchRotateMode(event);
- // if none of the above are selected, delegate to locked mode
- else
- return onTouchLockedMode(event);
- }
-
- /**
- * Handles touch event if the mode is set to locked
- * @param event the event to handle
- * @return false, shouldn't do anything with it for now
- */
- private boolean onTouchLockedMode(MotionEvent event) {
- // return false since we don't want to do anything so far
- return true;
- }
-
- /**
- * Handles the touch input if the mode is set to rotate
- * @param event the touch event
- * @return the result of the action
- */
- private boolean onTouchRotateMode(MotionEvent event) {
- return false;
- }
-
-
- /**
- * Handles the touch input if the mode is set to draw
- * @param event the touch event
- * @return the result of the action
- */
- public boolean onTouchDrawMode(MotionEvent event)
- {
- // get location of touch
- float eventX = event.getX();
- float eventY = event.getY();
- Log.i("everb", "划线或的位置X信息:"+ event.getX()+"划线或的位置Y信息:"+eventY);
-
-
- // based on the users action, start drawing
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- // create new path and paint
- currentPath = new CPath();
- currentPaint = new Paint();
- currentPaint.setAntiAlias(true);
- currentPaint.setColor(mColor);
- currentPaint.setStyle(mStyle);
- currentPaint.setStrokeJoin(Paint.Join.ROUND);
- currentPaint.setStrokeWidth(mSize);
- currentPath.moveTo(eventX, eventY);
- currentPath.setPaint(currentPaint);
- // capture touched locations
- lastTouchX = eventX;
- lastTouchY = eventY;
- mDrawableList.add(currentPath);
- return true;
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_UP:
- currentPath.lineTo(eventX, eventY);
- // When the hardware tracks events faster than they are delivered, the
- // event will contain a history of those skipped points.
- int historySize = event.getHistorySize();
- for (int i = 0; i < historySize; i++) {
- float historicalX = event.getHistoricalX(i);
- float historicalY = event.getHistoricalY(i);
- if (historicalX < dirtyRect.left) {
- dirtyRect.left = historicalX;
- } else if (historicalX > dirtyRect.right) {
- dirtyRect.right = historicalX;
- }
- if (historicalY < dirtyRect.top) {
- dirtyRect.top = historicalY;
- } else if (historicalY > dirtyRect.bottom) {
- dirtyRect.bottom = historicalY;
- }
- currentPath.lineTo(historicalX, historicalY);
- }
-
- // After replaying history, connect the line to the touch point.
- currentPath.lineTo(eventX, eventY);
- cleanDirtyRegion(eventX, eventY);
- break;
- default:
- return false;
- }
-
- // Include some padding to ensure nothing is clipped
- invalidate(
- (int) (dirtyRect.left - 20),
- (int) (dirtyRect.top - 20),
- (int) (dirtyRect.right + 20),
- (int) (dirtyRect.bottom + 20));
-
- // register most recent touch locations
- lastTouchX = eventX;
- lastTouchY = eventY;
- return true;
- }
-
- /**
- * Handles the touch input if the mode is set to select
- * @param event the touch event
- */
- private boolean onTouchSelectMode(MotionEvent event) {
- // TODO Implement Method
- return false;
- }
-
-
- /*******************************************
- * Drawing Events
- ******************************************/
- /**
- * Draw the background on the canvas
- * @param canvas the canvas to draw on
- * @param backgroundMode one of BACKGROUND_STYLE_GRAPH_PAPER, BACKGROUND_STYLE_NOTEBOOK_PAPER, BACKGROUND_STYLE_BLANK
- */
- public void drawBackground(Canvas canvas, int backgroundMode) {
- canvas.drawColor(mBackgroundColor);
- if(backgroundMode != BACKGROUND_STYLE_BLANK) {
- Paint linePaint = new Paint();
- linePaint.setColor(Color.argb(50, 0, 0, 0));
- linePaint.setStyle(mStyle);
- linePaint.setStrokeJoin(Paint.Join.ROUND);
- linePaint.setStrokeWidth(mSize - 2f);
- switch (backgroundMode) {
- case BACKGROUND_STYLE_GRAPH_PAPER:
- drawGraphPaperBackground(canvas, linePaint);
- break;
- case BACKGROUND_STYLE_NOTEBOOK_PAPER:
- drawNotebookPaperBackground(canvas, linePaint);
- default:
- break;
- }
- }
- mRedrawBackground = false;
- }
-
- /**
- * Draws a graph paper background on the view
- * @param canvas the canvas to draw on
- * @param paint the paint to use
- */
- private void drawGraphPaperBackground(Canvas canvas, Paint paint) {
- int i = 0;
- boolean doneH = false, doneV = false;
-
- // while we still need to draw either H or V
- while (!(doneH && doneV)) {
-
- // check if there is more H lines to draw
- if (i < canvas.getHeight())
- canvas.drawLine(0, i, canvas.getWidth(), i, paint);
- else
- doneH = true;
-
- // check if there is more V lines to draw
- if (i < canvas.getWidth())
- canvas.drawLine(i, 0, i, canvas.getHeight(), paint);
- else
- doneV = true;
-
- // declare as done
- i += 75;
- }
- }
-
- /**
- * Draws a notebook paper background on the view
- * @param canvas the canvas to draw on
- * @param paint the paint to use
- */
- private void drawNotebookPaperBackground(Canvas canvas, Paint paint) {
- int i = 0;
- boolean doneV = false;
- // draw horizental lines
- while (!(doneV)) {
- if (i < canvas.getHeight())
- canvas.drawLine(0, i, canvas.getWidth(), i, paint);
- else
- doneV = true;
- i += 75;
- }
- // change line color
- paint.setColor(NOTEBOOK_LEFT_LINE_COLOR);
- // draw side line
- canvas.drawLine(NOTEBOOK_LEFT_LINE_PADDING, 0,
- NOTEBOOK_LEFT_LINE_PADDING, canvas.getHeight(), paint);
-
-
- }
-
- /**
- * Draw text on the screen
- * @param text the text to draw
- * @param x the x location of the text
- * @param y the y location of the text
- * @param p the paint to use
- */
- public void drawText(String text, int x, int y, Paint p) {
- mDrawableList.add(new CText(text, x, y, p));
- invalidate();
- }
-
- /**
- * Capture Text from the keyboard and draw it on the screen
- * //TODO Implement the method
- */
- private void drawTextFromKeyboard() {
- Toast.makeText(getContext(), "Touch where you want the text to be", Toast.LENGTH_LONG).show();
- //TODO
- mTextExpectTouch = true;
- }
-
- /**
- * Retrieve the region needing to be redrawn
- * @param eventX The current x location of the touch
- * @param eventY the current y location of the touch
- */
- private void cleanDirtyRegion(float eventX, float eventY) {
- // figure out the sides of the dirty region
- dirtyRect.left = Math.min(lastTouchX, eventX);
- dirtyRect.right = Math.max(lastTouchX, eventX);
- dirtyRect.top = Math.min(lastTouchY, eventY);
- dirtyRect.bottom = Math.max(lastTouchY, eventY);
- }
-
- /**
- * Clean the canvas, remove everything drawn on the canvas.
- */
- public void cleanPage() {
- // remove everything from the list
- while (!(mDrawableList.isEmpty())) {
- mDrawableList.remove(0);
- }
- // request to redraw the canvas
- invalidate();
- }
-
- /**
- * Draws an image on the canvas
- *
- * @param x location of the image
- * @param y location of the image
- * @param width the width of the image
- * @param height the height of the image
- * @param pic the image itself
- */
- public void drawImage(int x, int y, int width, int height, Bitmap pic) {
- CBitmap bitmap = new CBitmap(pic, x, y);
- bitmap.setWidth(width);
- bitmap.setHeight(height);
- mDrawableList.add(bitmap);
- invalidate();
- }
-
-
- /*******************************************
- * Getters and Setters
- ******************************************/
-
-
- /**
- * Gets what has been drawn on the canvas so far as a bitmap
- * @return Bitmap of the canvas.
- */
- public Bitmap getCanvasBitmap()
- {
- // build drawing cache of the canvas, use it to create a new bitmap, then destroy it.
- buildDrawingCache();
- Bitmap mCanvasBitmap = Bitmap.createBitmap(getDrawingCache());
- destroyDrawingCache();
-
- // return the created bitmap.
- return mCanvasBitmap;
- }
-
- public int getColor() {
- return mColor;
- }
-
- public void setColor(int mColor) {
- this.mColor = mColor;
- }
-
- public int getBackgroundColor() {
- return mBackgroundColor;
- }
-
- public int getBackgroundMode() {
- return mBackgroundMode;
- }
-
- public void setBackgroundMode(int mBackgroundMode) {
- this.mBackgroundMode = mBackgroundMode;
- invalidate();
- }
-
- public void setBackgroundColor(int mBackgroundColor) {
- this.mBackgroundColor = mBackgroundColor;
- }
-
- public Paint.Style getStyle() {
- return mStyle;
- }
-
- public void setStyle(Paint.Style mStyle) {
- this.mStyle = mStyle;
- }
-
- public float getSize() {
- return mSize;
- }
-
- public void setSize(float mSize) {
- this.mSize = mSize;
- }
-
-
- public int getInteractionMode() {
- return mInteractionMode;
- }
-
- public void setInteractionMode(int interactionMode) {
-
- // if the value passed is not any of the flags, set the library to locked mode
- if (interactionMode > LOCKED_MODE)
- interactionMode = LOCKED_MODE;
- else if (interactionMode < DRAW_MODE)
- interactionMode = LOCKED_MODE;
-
- this.mInteractionMode = interactionMode;
- }
- }

- package com.lejurobot.aelos.aelosmini.view;
-
- import android.content.Context;
- import android.graphics.Point;
- import android.util.AttributeSet;
- import android.util.Log;
- import android.view.GestureDetector;
- import android.view.MotionEvent;
- import android.view.ScaleGestureDetector;
- import android.widget.Toast;
-
- import com.lejurobot.aelos.aelosmini.activities.ActionEditorActivity;
- import com.lejurobot.aelos.aelosmini.view.FabricView.CDrawable;
- import com.lejurobot.aelos.aelosmini.view.FabricView.FabricView;
-
-
- /**
- * @author wangyao
- * @package com.example.administrator.myapplication
- * @date 2017/6/27 14:05
- * @describe 实现一个画布的放置控件、缩放画布、控件之间的连线、画布的手势识别、缩放后手势滑动的识别
- * @project
- */
-
- public class ActionEditorCanvasView extends FabricView {
-
- private Context mContext;
- // Scale and zoom in/out factor.
- private static final int INIT_ZOOM_SCALES_INDEX = 0;
- private int mCurrentZoomScaleIndex = INIT_ZOOM_SCALES_INDEX;
- private static final float[] ZOOM_SCALES = new float[]{1.0f, 1.25f, 1.5f, 1.75f, 2.0f};
- private float mViewScale = ZOOM_SCALES[INIT_ZOOM_SCALES_INDEX];
-
- protected boolean mScrollable = true;
- private ScaleGestureDetector mScaleGestureDetector; //缩放手势
- private GestureDetector mTapGestureDetector; //手势监听类
- private int mPanningPointerId = MotionEvent.INVALID_POINTER_ID;
- private Point mPanningStart = new Point();
- private int mOriginalScrollX;
- private int mOriginalScrollY;
- private float mOffSetViewScroll;
-
- // Default desired width of the view in pixels.
- private static final int DESIRED_WIDTH = 2048;
- // Default desired height of the view in pixels.
- private static final int DESIRED_HEIGHT = 2048;
- // Interactive Modes
- public static final int DRAW_MODE = 0; //可以绘制线段的模式
- public static final int SELECT_MODE = 1; // TODO Support Object Selection.
- public static final int ROTATE_MODE = 2; // TODO Support Object ROtation.
- public static final int LOCKED_MODE = 3; //空模式
-
- // Default Background Styles 背景颜色
- public static final int BACKGROUND_STYLE_BLANK = 0;
- public static final int BACKGROUND_STYLE_NOTEBOOK_PAPER = 1;
- public static final int BACKGROUND_STYLE_GRAPH_PAPER = 2;
-
-
- public ActionEditorCanvasView(Context context, AttributeSet attrs) {
- super(context, attrs);
- this.mContext=context;
- }
-
- /**
- * The method onFinishInflate() will be called after all children have been added.
- * 这个方法是所有的子view被添加之后调用
- */
- @Override
- public void onFinishInflate() {
- super.onFinishInflate();
-
- // Setting the child view's pivot point to (0,0) means scaling leaves top-left corner in
- // place means there is no need to adjust view translation.
- this.setPivotX(0);
- this.setPivotY(0);
-
- setWillNotDraw(false);
- setHorizontalScrollBarEnabled(mScrollable); //水平滑动滚动条的设置
- setVerticalScrollBarEnabled(mScrollable); //竖直滑动滚动条的设置
- setBackgroundMode(BACKGROUND_STYLE_GRAPH_PAPER);
- mScaleGestureDetector = new ScaleGestureDetector(getContext(), new ScaleGestureListener()); //设置手势缩放的监听
-
- mTapGestureDetector = new GestureDetector(getContext(), new TapGestureListener()); //设置手势的监听
-
- }
-
- public void setBackgroundMode(int mBackgroundMode) {
- super.setBackgroundMode(mBackgroundMode);
- }
-
- /**
- * 设置画布所处在的模式,可以添加并设置其他的模式
- */
- public void setInteractionMode(int interactionMode) {
- if (interactionMode == DRAW_MODE) {
- super.setInteractionMode(DRAW_MODE);
- } else if (interactionMode == LOCKED_MODE) {
- super.setInteractionMode(LOCKED_MODE);
- }else if (interactionMode==SELECT_MODE){
- super.setInteractionMode(SELECT_MODE);
- }
-
- }
-
- /**
- * 增加画布里面的控件或其他实现了CDrawable接口的类
- */
- public boolean addCanvasDrawable(CDrawable cDrawable) {
- super.mDrawableList.add(cDrawable);
- return true;
- }
-
- /**
- * 清除画布里面的控件
- */
- public void cleanPager() {
- super.cleanPage();
- }
-
- /**
- * 重置画布的大小尺寸
- */
- public void resetView() {
- // Reset scrolling state.
- mPanningPointerId = MotionEvent.INVALID_POINTER_ID;
- mPanningStart.set(0, 0);
- mOriginalScrollX = 0;
- mOriginalScrollY = 0;
- updateScaleStep(INIT_ZOOM_SCALES_INDEX);
- scrollTo((int) this.getX(), (int) this.getY());
- }
-
-
- @Override
- public boolean onTouchDrawMode(MotionEvent event) {
- event.offsetLocation(getScrollX(), getScrollY()); //缩放后偏移的距离,保证缩放后触点跟缩放前对应
- return super.onTouchDrawMode(event);
- }
-
- @Override
- public boolean onTouchSelectMode(MotionEvent event) {
- return super.onTouchSelectMode(event);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- mScaleGestureDetector.onTouchEvent(event);
- mTapGestureDetector.onTouchEvent(event);
- // TODO: 2017/6/29 可根据触发事件做到动作控件的拖动
- return super.onTouchEvent(event);
- }
-
- /**
- * 画布实现缩小的方法
- *
- * @return
- */
- public boolean zoomOut() {
- // if (mScrollable && mCurrentZoomScaleIndex > 0) {
- if (mCurrentZoomScaleIndex > 0) {
- updateScaleStep(mCurrentZoomScaleIndex - 1);
- return true;
- }
- return false;
- }
-
-
- /**
- * 画布实现放大的方法
- *
- * @return
- */
- public boolean zoomIn() {
- if (mCurrentZoomScaleIndex < ZOOM_SCALES.length - 1) {
- updateScaleStep(mCurrentZoomScaleIndex + 1);
- return true;
- }
- return false;
- }
-
- /**
- * 缩放的具体实现
- *
- * @param newScaleIndex
- */
- private void updateScaleStep(int newScaleIndex) {
- if (newScaleIndex != mCurrentZoomScaleIndex) {
- final float oldViewScale = mViewScale;
-
- mCurrentZoomScaleIndex = newScaleIndex;
- mViewScale = ZOOM_SCALES[mCurrentZoomScaleIndex];
-
- final float scaleDifference = mViewScale - oldViewScale;
- scrollBy((int) (scaleDifference * getMeasuredWidth() / 2),
- (int) (scaleDifference * getMeasuredHeight() / 2));
-
- this.setScaleX(mViewScale);
- this.setScaleY(mViewScale);
- this.requestLayout();
- }
- }
-
- @Override
- public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- setMeasuredDimension(
- getMeasuredSize(widthMeasureSpec, DESIRED_WIDTH),
- getMeasuredSize(heightMeasureSpec, DESIRED_HEIGHT));
-
- }
-
- private static int getMeasuredSize(int measureSpec, int desiredSize) {
- int mode = MeasureSpec.getMode(measureSpec);
- int size = MeasureSpec.getSize(measureSpec);
-
- if (mode == MeasureSpec.EXACTLY) {
- return size;
- } else if (mode == MeasureSpec.AT_MOST) {
- return Math.min(size, desiredSize);
- } else {
- return desiredSize;
- }
-
- }
-
-
- private class TapGestureListener implements GestureDetector.OnGestureListener, GestureDetector.OnDoubleTapListener {
-
- @Override
- public boolean onDown(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent motionEvent) {
-
- }
-
- @Override
- public boolean onSingleTapUp(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public boolean onScroll(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
- return false;
- }
-
- @Override
- public void onLongPress(MotionEvent motionEvent) {
- // TODO: 2017/6/29 长按可以设置模式为连线
- Toast.makeText(mContext,"实现了长按手势",Toast.LENGTH_SHORT).show();
- }
-
- @Override
- public boolean onFling(MotionEvent motionEvent, MotionEvent motionEvent1, float v, float v1) {
- return false;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public boolean onDoubleTap(MotionEvent motionEvent) {
- return false;
- }
-
- @Override
- public boolean onDoubleTapEvent(MotionEvent motionEvent) {
- return false;
- }
- }
-
- private class ScaleGestureListener extends ScaleGestureDetector.SimpleOnScaleGestureListener {
- // Focus point at the start of the pinch gesture. This is used for computing proper scroll
- // offsets during scaling, as well as for simultaneous panning.
- private float mStartFocusX;
- private float mStartFocusY;
- // View scale at the beginning of the gesture. This is used for computing proper scroll
- // offsets during scaling.
- private float mStartScale;
- // View scroll offsets at the beginning of the gesture. These provide the reference point
- // for adjusting scroll in response to scaling and panning.
- private int mStartScrollX;
- private int mStartScrollY;
-
- @Override
- public boolean onScaleBegin(ScaleGestureDetector detector) {
- mStartFocusX = detector.getFocusX();
- mStartFocusY = detector.getFocusY();
- mStartScrollX = getScrollX();
- mStartScrollY = getScrollY();
-
- mStartScale = mViewScale;
- return true;
- }
-
- @Override
- public boolean onScale(ScaleGestureDetector detector) {
- final float oldViewScale = mViewScale;
-
- final float scaleFactor = detector.getScaleFactor();
- mViewScale *= scaleFactor;
-
- if (mViewScale < ZOOM_SCALES[0]) {
- mCurrentZoomScaleIndex = 0;
- mViewScale = ZOOM_SCALES[mCurrentZoomScaleIndex];
- } else if (mViewScale > ZOOM_SCALES[ZOOM_SCALES.length - 1]) {
- mCurrentZoomScaleIndex = ZOOM_SCALES.length - 1;
- mViewScale = ZOOM_SCALES[mCurrentZoomScaleIndex];
- } else {
- // find nearest zoom scale
- float minDist = Float.MAX_VALUE;
- // If we reach the end the last one was the closest
- int index = ZOOM_SCALES.length - 1;
- for (int i = 0; i < ZOOM_SCALES.length; i++) {
- float dist = Math.abs(mViewScale - ZOOM_SCALES[i]);
- if (dist < minDist) {
- minDist = dist;
- } else {
- // When it starts increasing again we've found the closest
- index = i - 1;
- break;
- }
- }
- mCurrentZoomScaleIndex = index;
- }
-
- /* if (shouldDrawGrid()) {
- mGridRenderer.updateGridBitmap(mViewScale);
- }*/
-
- ActionEditorCanvasView.this.setScaleX(mViewScale);
- ActionEditorCanvasView.this.setScaleY(mViewScale);
-
- // Compute scroll offsets based on difference between original and new scaling factor
- // and the focus point where the gesture started. This makes sure that the scroll offset
- // is adjusted to keep the focus point in place on the screen unless there is also a
- // focus point shift (see next scroll component below).
- final float scaleDifference = mViewScale - mStartScale;
- final int scrollScaleX = (int) (scaleDifference * mStartFocusX);
- final int scrollScaleY = (int) (scaleDifference * mStartFocusY);
-
- // Compute scroll offset based on shift of the focus point. This makes sure the view
- // pans along with the focus.
- final int scrollPanX = (int) (mStartFocusX - detector.getFocusX());
- final int scrollPanY = (int) (mStartFocusY - detector.getFocusY());
-
- // Apply the computed scroll components for scale and panning relative to the scroll
- // coordinates at the beginning of the gesture.
- scrollTo(mStartScrollX + scrollScaleX + scrollPanX,
- mStartScrollY + scrollScaleY + scrollPanY);
-
- return true;
- }
- }
- }

项目地址为:http://download.csdn.net/download/wangyongyao1989/9886503
六、关于所用的方法总结:
1.setScaleX、setScaleY:这是View中方法,设定View轴心点缩放能用于缩放View的大小;
2.offsetLocation(float deltaX,float deltaY):调整event的位置,参数的含义是调整横纵坐标的在event的数值;
3.getScrollX(),getScrollY():是View中的方法,返回View在坐标系中横纵坐标的数值;
4.getAction:获取触摸时间的类型值,比如说ACTION_DOWN、ACTION_MOVE、ACTION_UP等的动作;
5.getActionMask:返回正在执行被屏蔽的操作,没有指针索引信息。
6.getActionIndex:返回ACTION_POINTER_DOWN、ACTION_POINTER_MOVE、ACTION_POINTER_UP相关的指针;
7.getHistoricalX.getHistoricalY:返回在native中存储的坐标的值,比getX()/getY()获取得粒度更细。
8.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。