在具有相同点Android的独立画布上绘制2条线

时间:2016-01-10 23:09:17

标签: java android canvas

如何在一个画布上绘制一条线,同时在另一个画布上的完全相同的点上复制该线。我的朋友告诉我要为两者使用相同的听众事件,但我无法弄清楚如何做到这一点。我会给你画布和线条的代码。

package com.mypackage.morphing;

import android.content.Context;
import android.graphics.*;
import android.graphics.Paint.Style;
import android.util.AttributeSet;
import android.view.*;

import java.util.ArrayList;

public class FingerLine extends View {
private ArrayList<Line> lines = new ArrayList<Line>();
private final Paint mPaint;
private float startX;
private float startY;
private float endX;
private float endY;
private Line tempL;
private int idx = 0;

private boolean firstCanContext = false;

public FingerLine(Context context, AttributeSet attrs) {
    super(context, attrs);
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStyle(Style.STROKE);
    mPaint.setStrokeWidth(5);
    mPaint.setColor(Color.RED);
}

@Override protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    for(Line l : lines) {
        canvas.drawLine(l.startX, l.startY, l.endX, l.endY, mPaint);
    }
}

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lines.add(new Line(event.getX(), event.getY()));
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            lines.get(idx).endX = event.getX();
            lines.get(idx).endY = event.getY();
            invalidate();
            break;
        case MotionEvent.ACTION_UP: // when the user lifts up
            lines.get(idx).endX = event.getX();
            lines.get(idx).endY = event.getY();
            idx++;
            invalidate();
            break;
    }
    return true;
}

public void clearList(){
    lines.clear();
    idx = 0;
    invalidate();
}

public void removeLineNumber(int indexR){
    lines.remove(indexR);
    idx--;
    invalidate();
}
}

package com.mypackage.morphing;

public class Line {
float startX, startY, endX, endY;
public Line(float startX, float startY, float endX, float endY) {
    this.startX = startX;
    this.startY = startY;
    this.endX = endX;
    this.endY = endY;
}
public Line(float startX, float startY) { // for convenience
    this(startX, startY, startX, startY);
}
}

3 个答案:

答案 0 :(得分:0)

如果您要在一个画布上绘图,并且您希望看到绘制的线条出现在第二个画布上,只需在您的班级中创建一个方法,然后添加一行&#34;。每当您使用该方法添加一行(并随后绘制它)时,请通知侦听器(在此实例中为第二个画布)已添加一行。然后,第二个画布也可以决定绘制该行(或者从第一个画布中获取行并重新绘制所有行)。

答案 1 :(得分:0)

所以你有2个类,都扩展了View。 当用户触摸屏幕时,FirstView获取事件。 你希望SecondView绘制与FirstView相同的东西。

你的朋友说你要为这两个课程添加一个听众。 但你也可以从FirstView发送Line到SecondView。 所以你在firstView中创建了一个SecondView实例:

public class FirstView extends View {
    SecondView secondView;

现在有两个选择,

1)两个类都有ArrayList,当创建或修改一行时,你在两个类中都这样做。别忘了刷新SecondView!

public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            Line line = new Line(event.getX(), event.getY());
            lines.add(line);
            secondView.lines.add(line);
            invalidate();
            break;
        case MotionEvent.ACTION_MOVE:
            lines.get(idx).endX = event.getX();
            lines.get(idx).endY = event.getY();
            secondView.lines.get(idx).endX = event.getX();
            secondView.lines.get(idx).endY = event.getY();

2)只有FirstView具有ArrayList,并且你在onDraw方法中的两个classe中绘制所有行。这是一个坏主意,因为经常调用onDraw,所以你必须在内部做最少的工作。

答案 2 :(得分:0)

我找到了答案(但它可能看起来很可怕)

我有3个班级正在研究这个课程(不包括主要课程,我将会这样做)。 这些类是LineController.java,Line.java和EditingView.java。 LineController包含对象的arraylist,line是行对象(我只是为了方便起见)而EditingView是我在上面绘制的视图类型。

LineController类

public class LineController {
    public ArrayList<Line> firstCanvas;
    public ArrayList<Line> secondCanvas;
    private int idx;
    LineController(){
        firstCanvas = new ArrayList<>();
        secondCanvas = new ArrayList<>();
        idx = 0;
    }
    public void addLine(Line l){
        firstCanvas.add(l);
        secondCanvas.add(l);
        idx++;
    }

    public void addLine(float x, float y){
        firstCanvas.add(new Line(x, y));
        secondCanvas.add(new Line(x, y));
        idx++;
    }

    public void addX(int index, float x){
        if(index <= idx){
            firstCanvas.get(index).endX = x;
            secondCanvas.get(index).endX = x;
        }
    }

    public void addX(float x){
        firstCanvas.get(firstCanvas.size() - 1).endX = x;
        secondCanvas.get(secondCanvas.size() - 1).endX = x;
    }

    public void addY(int index, float y){
        if(index <= idx){
            firstCanvas.get(index).endY = y;
            secondCanvas.get(index).endY = y;
        }
    }

    public void addY(float y){
        firstCanvas.get(firstCanvas.size() - 1).endY = y;
        secondCanvas.get(secondCanvas.size() - 1).endY = y;
    }

    public void clearLists(){
        firstCanvas.clear();
        secondCanvas.clear();
        idx = 0;
    }

    public boolean removeLast(){
        if(firstCanvas.isEmpty()){
            return false;
        }
        if(firstCanvas.size() == 1){
            idx = 0;
            firstCanvas.clear();
            secondCanvas.clear();
        }else{
            idx--;
            firstCanvas.remove(idx);
            secondCanvas.remove(idx);
        }
        return true;
    }
}

EditingView类

public class EditingView extends View {
    private LineController lc;
    private final Paint mPaint;
    private boolean drawingMode = true;
    private int closestIndex = -1;
    private Paint editDot;
    private Paint editLine;

    private boolean endOfLine;
    private boolean noLine = true;
    private Point lastTouch;
    private final static int MAX_DISTANCE = 100;
    private Line editingLine = null;

    private int viewIndex;

    public EditingView(Context context){
        super(context);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        editDot = new Paint(Paint.ANTI_ALIAS_FLAG);
        editLine = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.RED);
        editDot.setColor(Color.BLUE);
        editLine.setColor(Color.CYAN);
    }

    public EditingView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStyle(Style.STROKE);
        mPaint.setStrokeWidth(5);
        mPaint.setColor(Color.RED);
    }

    public void init(LineController controller){
        lc = controller;
    }

    @Override protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(viewIndex == 0){ // first View
            for (Line l : lc.firstCanvas) {
                canvas.drawLine(l.startX, l.startY, l.endX, l.endY, mPaint);
            }
            if(!drawingMode){
                // if in edit, draw a line around the index we found
                if(closestIndex != -1) {
                    canvas.drawCircle(lc.firstCanvas.get(closestIndex).startX,
                            lc.firstCanvas.get(closestIndex).startY, 20, editDot);
                    canvas.drawCircle(lc.firstCanvas.get(closestIndex).endX,
                            lc.firstCanvas.get(closestIndex).endY, 20, editDot);
                }
            }
        }else if(viewIndex == 1){
            for (Line l : lc.secondCanvas) {
                canvas.drawLine(l.startX, l.startY, l.endX, l.endY, mPaint);
            }
            if(!drawingMode){
                // if in edit, draw a line around the index we found
                if(closestIndex != -1) {
                    canvas.drawCircle(lc.secondCanvas.get(closestIndex).startX,
                            lc.secondCanvas.get(closestIndex).startY, 20, editDot);
                    canvas.drawCircle(lc.secondCanvas.get(closestIndex).endX,
                            lc.secondCanvas.get(closestIndex).endY, 20, editDot);
                }
            }
        }
    }

    public void drawLine(MotionEvent event){
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                lc.addLine(event.getX(), event.getY());
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                lc.addX(event.getX());
                lc.addY(event.getY());
                invalidate();
                break;
            case MotionEvent.ACTION_UP:
                lc.addX(event.getX());
                lc.addY(event.getY());
                invalidate();
                break;
        }
    }
    public void editLine(MotionEvent event){
        switch (event.getAction()){
            case MotionEvent.ACTION_DOWN:
                // run function to find the closest point based on that object
                lastTouch = new Point((int)event.getX(), (int)event.getY());
                editingLine = findClosestLine(); // this should be for any point on the screen
                if(editingLine == null){
                    noLine = true;
                }else{
                    noLine = false;
                    endOfLine = checkPointStartEnd(editingLine);
                }
                invalidate();
                break;
            case MotionEvent.ACTION_MOVE:
                // edit the point to have the new points from the touch event
                if(!noLine){
                    // we found one
                    if(!endOfLine){
                        editingLine.startX = event.getX();
                        editingLine.startY = event.getY();
                    }else{
                        editingLine.endX = event.getX();
                        editingLine.endY = event.getY();
                    }
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
                if(!noLine){
                    // we found one
                    if(!endOfLine){
                        editingLine.startX = event.getX();
                        editingLine.startY = event.getY();
                    }else{
                        editingLine.endX = event.getX();
                        editingLine.endY = event.getY();
                    }
                    editingLine = null;
                    invalidate();
                }
                lastTouch = null;
                break;
        }
    }

    public void editMode(int index){
        drawingMode = false;
        closestIndex = index;
    }

    public void clear() { closestIndex = -1; }

    public void drawingMode(){
        drawingMode = true;
    }

    public void viewIndex(int index){
        viewIndex = index;
    }

    // finds the closest line in either array (checks the screen right?)
    private Line findClosestLine(){
        int temp1, temp2;
        Line tempLine = null;
        int closestDistance = MAX_DISTANCE;
        // needs to loop through the array list, for both startX,Y and endX,Y of each line in the array
        // then needs to get the index to that point and draw a circle around that point
        // also change the colour of the line and the corresponding line based on that index

        if(viewIndex == 0){
            for(int i = 0; i < lc.firstCanvas.size(); i++){
                temp1 = checkPoint(lc.firstCanvas.get(i));
                if(temp1 < closestDistance && temp1 != -1) {
                    tempLine = lc.firstCanvas.get(i);
                    closestIndex = i;
                }
            }
        }else{
            for(int i = 0; i < lc.firstCanvas.size(); i++){
                temp2 = checkPoint(lc.secondCanvas.get(i));
                if(temp2 < closestDistance && temp2 != -1){
                    tempLine = lc.secondCanvas.get(i);
                    closestIndex = i;
                }
            }
        }
        return tempLine;
    }
    // Checks the point of a line to see if it is close
    private int checkPoint(Line l){
        int firstDistance = pyth((lastTouch.x - l.startX), (lastTouch.y - l.startY));
        int secondDistance = pyth((lastTouch.x - l.endX), (lastTouch.y - l.endY));
        if(MAX_DISTANCE > firstDistance) {
            return (int)firstDistance;
        }else if(MAX_DISTANCE > secondDistance){
            return (int)secondDistance;
        }
        return -1;
    }
    // Checks the line we have found for the close point being start or end
    private boolean checkPointStartEnd(Line l){
        boolean start = false;
        int firstDistance = pyth((lastTouch.x - l.startX), (lastTouch.y - l.startY));
        int secondDistance = pyth((lastTouch.x - l.endX), (lastTouch.y - l.endY));
        if(MAX_DISTANCE < firstDistance) {
            start = true;
        }else if(MAX_DISTANCE < secondDistance){
            start = false;
        }
        return start;
    }
    // returns pythagorian theorum
    private int pyth(double x, double y){
        int z;
        z = (int)Math.sqrt(((x * x) + (y * y)));
        return z;
    }
}

线类

public class Line {
    float startX, startY, endX, endY;
    public Line(float startX, float startY, float endX, float endY) {
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
    }
    public Line(float startX, float startY) { // for convenience
        this(startX, startY, startX, startY);
    }
}

MainActivity(唯一重要的)

protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            lc = new LineController();
            firstCanvas = new EditingView(this);
            secondCanvas = new EditingView(this);
            firstCanvas.viewIndex(0);
            secondCanvas.viewIndex(1);
            firstCanvas.init(lc);
            secondCanvas.init(lc);
            firstCanvas.setOnTouchListener(new TouchListener());
            secondCanvas.setOnTouchListener(new TouchListener());
            firstFrame = (FrameLayout)findViewById(R.id.firstFrame);
            secondFrame = (FrameLayout)findViewById(R.id.secondFrame);
            firstFrame.addView(firstCanvas);
            secondFrame.addView(secondCanvas);
    }

private class TouchListener implements View.OnTouchListener{
        @Override
        public boolean onTouch(View v, MotionEvent event) {
            EditingView temp = (EditingView)v;
            if(drawingMode) {
                // drawing mode
                temp.drawLine(event);
                updateCanvas();
            }else{
                // edit mode
                temp.editLine(event);
                updateCanvas();
            }
            return true;
        }
    }

这就是我所用的一切。发生的事情是我在main中创建了一个控制器对象,并传递给EditViews来保存数组。然后,我只根据正在使用的视图访问数组。然后我设置了一个在MainActivity(可能被拆分)类中创建的触摸侦听器,该类将用于处理用户所处的模式(绘制或编辑)。使用这一切将允许我使用MainActivity内部整个屏幕的监听器(以编程方式)创建新视图。

我知道这不是做这一切的最佳方式,但它可以解决,我找不到任何其他东西。希望这有助于其他想要做同样事情的人。或者至少为自己的解决方案而努力。