废话少说代码备注很详细,直接上代码。
1.画图工具类
public class LogicView extends View {
//背景点集合
private ArrayList<Circle> bgCircles;
//所有线的集合
private ArrayList<Line> allLines;
private Paint bgPaint;
private Paint linePaint;
public static final int LINE_TAG=1;
public static final int MOVE_TAG=2;
private int currOperateTag=LINE_TAG;
public LogicView(Context context) {
super(context);
initData();
initView();
}
public LogicView(Context context, AttributeSet attrs) {
super(context, attrs);
initData();
initView();
}
private void initData() {
bgCircles=new ArrayList<>();
allLines=new ArrayList<>();
}
public ArrayList<Line> getAllLines() {
return allLines;
}
private void initView() {
bgPaint=new Paint();
bgPaint.setAntiAlias(true);
bgPaint.setColor(Color.BLACK);
linePaint=new Paint();
linePaint.setAntiAlias(true);
linePaint.setStrokeWidth(2);
linePaint.setColor(Color.RED);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//canvas.drawColor(Color.WHITE);
canvas.drawColor(Color.argb(255,223,233,223));
for (int i=0;i<bgCircles.size();i++){
Circle circle=bgCircles.get(i);
canvas.drawCircle(circle.getX(),circle.getY(),circle.getR(),bgPaint);
}
for (int i=0;i<allLines.size();i++){
Line line=allLines.get(i);
canvas.drawLine(bgCircles.get(line.startCirclePosition).x,bgCircles.get(line.startCirclePosition).y,
bgCircles.get(line.endCirclePosition).x,bgCircles.get(line.endCirclePosition).y,linePaint);
}
}
/**
* 画底部点
* author LH
* date 2016/11/25 17:47
*/
public void setBgCircle(ArrayList<Circle> bgCircles){
this.bgCircles=bgCircles;
postInvalidate();
}
/**
* 清空画的线
* author LH
* date 2016/11/25 18:45
*/
public void clear() {
allLines.clear();
tag=DOWN;
currOperateTag=LINE_TAG;
postInvalidate();
}
/**
* 整体放大或者缩小
* author LH
* date 2016/11/28 10:02
*
*/
public void changeZoom(int row,float twoPointW,float twoPointH) {
int centerPosition = getCenterNearPoint();
int centerRow = centerPosition / row;
int centerLine = centerPosition % row;
for (int i = 0; i < bgCircles.size(); i++) {
int currentRow = i / row;
int currentLine = i % row;
bgCircles.get(i).x = bgCircles.get(centerPosition).x - (centerLine - currentLine) * twoPointW;
bgCircles.get(i).y = bgCircles.get(centerPosition).y - (centerRow - currentRow) * twoPointH;
}
Log.e("allLines", allLines.toString());
postInvalidate();
}
/**
* 设置当前的操作
* author LH
* date 2016/11/25 18:52
*/
public void setCurrOperateTag(int currOperateTag) {
this.currOperateTag = currOperateTag;
}
/**
* 画移动时的临时直线
* author LH
* date 2016/11/25 20:07
*/
public void drawMoveLine(Line line){
if(tag==DOWN){
allLines.add(line);
}else {
allLines.set(allLines.size() - 1,line);
}
postInvalidate();
}
/**
* 求两点之间的距离
* author LH
* date 2016/11/25 17:06
*/
private float twoPointW(float moveX,float moveY,float toX,float toY){
return (float) Math.sqrt(Math.pow(moveX-toX,2)+Math.pow(moveY-toY,2));
}
/**
* 获取距离目标点最近的点的位置
* author LH
* date 2016/11/25 17:32
*/
private int getNearestCircle(float moveX,float moveY){
int point=0;
float near=twoPointW(moveX,moveY,bgCircles.get(0).x,bgCircles.get(0).y);
for (int i=0;i<bgCircles.size();i++){
float currentW=twoPointW(moveX,moveY,bgCircles.get(i).x,bgCircles.get(i).y);
if(near>currentW){
near=currentW;
point=i;
}
}
return point;
}
/**
* 获取画线的中心点的相近的点
* author LH
* date 2016/11/28 10:44
* @return 点的位置
*/
public int getCenterNearPoint(){
if(allLines.size()>0) {
float nearX = bgCircles.get(allLines.get(0).startCirclePosition).x;
float nearY = bgCircles.get(allLines.get(0).startCirclePosition).y;
float farX = bgCircles.get(allLines.get(0).startCirclePosition).x;
float farY = bgCircles.get(allLines.get(0).startCirclePosition).y;
for (int i = 0; i < allLines.size(); i++) {
Line line = allLines.get(i);
if (nearX > bgCircles.get(line.startCirclePosition).x) {
nearX = bgCircles.get(line.startCirclePosition).x;
}
if (nearX > bgCircles.get(line.endCirclePosition).x) {
nearX = bgCircles.get(line.endCirclePosition).x;
}
if (nearY > bgCircles.get(line.startCirclePosition).y) {
nearY = bgCircles.get(line.startCirclePosition).y;
}
if (nearY > bgCircles.get(line.endCirclePosition).y) {
nearY = bgCircles.get(line.endCirclePosition).y;
}
if (farX < bgCircles.get(line.startCirclePosition).x) {
farX = bgCircles.get(line.startCirclePosition).x;
}
if (farX < bgCircles.get(line.endCirclePosition).x) {
farX = bgCircles.get(line.endCirclePosition).x;
}
if (farY < bgCircles.get(line.startCirclePosition).y) {
farY = bgCircles.get(line.startCirclePosition).y;
}
if (farY < bgCircles.get(line.endCirclePosition).y) {
farY = bgCircles.get(line.endCirclePosition).y;
}
}
float centerX = (nearX + farX) / 2;
float centerY = (nearY + farY) / 2;
return getNearestCircle(centerX, centerY);
}else {
return bgCircles.size()/2;
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (currOperateTag) {
case LINE_TAG:
lineOperate(event);
break;
case MOVE_TAG:
if(allLines.size()>0) {
moveOperate(event);
}
break;
}
return true;
}
ArrayList<LinePoint> linePoints;
int down_nearPoint,up_nearPoint,move_nearPoint;
private void moveOperate(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
float x_down = event.getRawX();
float y_down = event.getRawY();
down_nearPoint = getNearestLinePoints(x_down,y_down);
Log.e("getNearestLinePoints",linePoints.toString());
break;
case MotionEvent.ACTION_UP:
break;
case MotionEvent.ACTION_MOVE:
float x_move = event.getRawX();
float y_move = event.getRawY();
move_nearPoint = getNearestCircle(x_move, y_move);
drawMoveLinePoint(move_nearPoint);
break;
}
}
/**
* 画拖动时的直线
* author LH
* date 2016/11/26 15:54
*/
private void drawMoveLinePoint(int move_nearPoint) {
for(int i=0;i<linePoints.size();i++){
LinePoint linePoint=linePoints.get(i);
Line addLine;
if(linePoint.type==0){
addLine=new Line(move_nearPoint,linePoint.line.endCirclePosition);
}else {
addLine=new Line(linePoint.line.startCirclePosition,move_nearPoint);
}
allLines.set(linePoint.position,addLine);
}
postInvalidate();
}
/**
* 获取拉伸是距离点击点最近的直线
* author LH
* date 2016/11/26 10:50
*/
private int getNearestLinePoints(float x_down, float y_down) {
linePoints=new ArrayList<>();
int position=allLines.get(0).startCirclePosition;
float near=twoPointW(x_down,y_down,bgCircles.get(allLines.get(0).startCirclePosition).x,bgCircles.get(allLines.get(0).startCirclePosition).y);
for (int i=0;i<allLines.size();i++){
float currentStart=twoPointW(x_down,y_down,bgCircles.get(allLines.get(i).startCirclePosition).x,bgCircles.get(allLines.get(i).startCirclePosition).y);
float currentEnd=twoPointW(x_down,y_down,bgCircles.get(allLines.get(i).endCirclePosition).x,bgCircles.get(allLines.get(i).endCirclePosition).y);
if (near>currentStart){
near=currentStart;
position=allLines.get(i).startCirclePosition;
}
if (near>currentEnd){
near=currentEnd;
position=allLines.get(i).endCirclePosition;
}
}
for (int i=0;i<allLines.size();i++){
if(allLines.get(i).startCirclePosition==position){
LinePoint linePoint=new LinePoint(0,i,allLines.get(i));
linePoints.add(linePoint);
}else if(allLines.get(i).endCirclePosition==position){
LinePoint linePoint=new LinePoint(1,i,allLines.get(i));
linePoints.add(linePoint);
}
}
return position;
}
float x_down,y_down,x_up,y_up;
int tag=1;
int DOWN=1,MOVE=2;
private void lineOperate(MotionEvent event) {
switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN:
x_down = event.getRawX();
y_down = event.getRawY();
down_nearPoint = getNearestCircle(x_down, y_down);
tag=DOWN;
break;
case MotionEvent.ACTION_UP:
x_up = event.getRawX();
y_up = event.getRawY();
up_nearPoint = getNearestCircle(x_up, y_up);
break;
case MotionEvent.ACTION_MOVE:
float x_move = event.getRawX();
float y_move = event.getRawY();
move_nearPoint = getNearestCircle(x_move, y_move);
drawMoveLine(new Line(down_nearPoint, move_nearPoint));
tag=MOVE;
break;
}
}
}
2.调用主函数
public class MainActivity extends Activity {
@Bind(R.id.logicView)
LogicView logicView;
@Bind(R.id.btn_line)
ImageView btnLine;
@Bind(R.id.btn_move)
ImageView btnMove;
@Bind(R.id.btn_zoomIn)
ImageView btnZoomIn;
@Bind(R.id.btn_zoomOut)
ImageView btnZoomOut;
@Bind(R.id.btn_clean)
ImageView btnClean;
@Bind(R.id.activity_main)
RelativeLayout activityMain;
private ArrayList<Circle> bgCircles;
private float rightBtnW = 150;//右侧按钮宽度
private float bottomH = 20;//底部宽度
private int bgPointRow = 24;//背景的行数
private int bgPointLine = 15;//背景的列数
float useW,useH;
private double allZooms[]=new double[]{1.2,1.5,1.8,2.0,2.2,2.5,2.8,3.0};
private int currentZoom=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
btnLine.setSelected(true);
btnMove.setSelected(false);
getBgCirclePosition();
logicView.setBgCircle(bgCircles);
}
/**
* 设置背景圆的坐标和半径
* author LH
* date 2016/11/25 16:06
*/
private void getBgCirclePosition() {
bgCircles = new ArrayList<>();
WindowManager wm = (WindowManager) this.getSystemService(Context.WINDOW_SERVICE);
int width = wm.getDefaultDisplay().getWidth();
int height = wm.getDefaultDisplay().getHeight();
Log.e("position", "width:" + width + " height:" + height);
useW = width - rightBtnW;
useH = height - bottomH;
for (int j = 0; j < bgPointLine; j++) {
for (int i = 0; i < bgPointRow; i++) {
Circle circle = new Circle(useW / (bgPointRow + 1) * (i + 1), useH / (bgPointLine + 1) * (j + 1), 5);
bgCircles.add(circle);
}
}
}
@OnClick({R.id.btn_line, R.id.btn_move, R.id.btn_zoomIn, R.id.btn_zoomOut, R.id.btn_clean})
public void onClick(View view) {
switch (view.getId()) {
case R.id.btn_line:
btnLine.setSelected(true);
btnMove.setSelected(false);
logicView.setCurrOperateTag(LogicView.LINE_TAG);
break;
case R.id.btn_move:
btnLine.setSelected(false);
btnMove.setSelected(true);
logicView.setCurrOperateTag(LogicView.MOVE_TAG);
break;
case R.id.btn_zoomIn:
if(currentZoom<allZooms.length-1) {
currentZoom++;
logicView.changeZoom(bgPointRow, (float) (useW / (bgPointRow + 1) * allZooms[currentZoom]), (float) (useH / (bgPointLine + 1) * allZooms[currentZoom]));
}
break;
case R.id.btn_zoomOut:
if(currentZoom>0) {
currentZoom--;
logicView.changeZoom(bgPointRow, (float) (useW / (bgPointRow + 1) * allZooms[currentZoom]), (float) (useH / (bgPointLine + 1) * allZooms[currentZoom]));
}
break;
case R.id.btn_clean:
btnLine.setSelected(true);
btnMove.setSelected(false);
logicView.setCurrOperateTag(LogicView.LINE_TAG);
currentZoom=0;
getBgCirclePosition();
logicView.setBgCircle(bgCircles);
logicView.clear();
break;
}
}
}
3.用到的实体类
/**
* Created by LH on 2016/11/25.
*/
public class Circle {
float x;
float y;
float r;
public Circle(float x, float y, float r) {
this.x = x;
this.y = y;
this.r = r;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
public float getR() {
return r;
}
}
/**
* Created by LH on 2016/11/25.
*/
public class Line {
//起始的点的位置
int startCirclePosition;
//终止点的位置
int endCirclePosition;
public Line(int startCirclePosition, int endCirclePosition) {
this.startCirclePosition = startCirclePosition;
this.endCirclePosition = endCirclePosition;
}
@Override
public String toString() {
return "Line{" +
"startCirclePosition=" + startCirclePosition +
", endCirclePosition=" + endCirclePosition +
'}';
}
}
/**
* Created by LH on 2016/11/26.
*/
public class LinePoint {
//0起点 1终点
int type;
//直线在集合中的位置
int position;
//直线
Line line;
public LinePoint(int type, int position, Line line) {
this.type = type;
this.position = position;
this.line = line;
}
@Override
public String toString() {
return "LinePoint{" +
"type=" + type +
", position=" + position +
", line=" + line +
'}';
}
}
4.布局文件
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.lh.pointpicture.MainActivity">
<RelativeLayout
android:id="@+id/rl_control"
android:layout_width="150px"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:background="#606060">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true"
android:gravity="center_horizontal">
<ImageView
android:id="@+id/btn_line"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/zhixian_selector"/>
<ImageView
android:id="@+id/btn_move"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:background="@drawable/yidong_selector"/>
<ImageView
android:id="@+id/btn_zoomIn"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:background="@drawable/fangda_selector"/>
<ImageView
android:id="@+id/btn_zoomOut"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:background="@drawable/suoxia_selector"/>
<ImageView
android:id="@+id/btn_clean"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="30dp"
android:background="@drawable/chongzuo_selector"/>
</LinearLayout>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toLeftOf="@id/rl_control">
<com.example.lh.pointpicture.LogicView
android:id="@+id/logicView"
android:layout_width="1130px"
android:layout_height="800px"
android:layout_centerInParent="true"
android:clickable="true"/>
</RelativeLayout>
</RelativeLayout>