origin

In the original project, the operation direction is up, down, left and right, and the left and right buttons need to be pressed at the same time for operation.

Recently upgraded the project to a joystick operation similar to King of Glory. The diagram below:

Draw the background

To realize the remote sensing button, it is necessary to draw the background and draw the remote sensing button in the center. To draw a remote sensing background, create a RemoteViewBg class to store the background image and reduce the need to create a bitmap repeatedly. The RemoteViewBg class code looks like this:

public class RemoteViewBg { private Bitmap bitmapBg; public RemoteViewBg(Bitmap bitmap) { bitmapBg = bitmap; Public void draw(Canvas Canvas, Paint Paint,Rect src0, Rect dst0) {Canvas. DrawBitmap (bitmapBg, src0, dst0, paint); }}Copy the code

Click and touch events

Rewrite the touch time of the system to determine whether the touch point is in the background range or outside the background range

@Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN || Event.getaction () == motionEvent.action_move) {// // touch out of range if (math.sqrt (math.pow ((bigCircleX - (int) event.getx ())), 2) + Math.pow((bigCircleY - (int) event.getY()), 2)) >= bigCircleR) { double tempRad = getRad(bigCircleX, bigCircleY, event.getX(), event.getY()); getXY(bigCircleX, bigCircleY, bigCircleR, tempRad); } else {// smallCircleX = (int) event.getx (); smallCircleY = (int) event.getY(); } } else if (event.getAction() == MotionEvent.ACTION_UP) { smallCircleX = bigCircleX; smallCircleY = bigCircleY; } return true; }Copy the code

Radian calculation

Get the current touch point through event.getx () and event.gety (), and calculate with the dot to obtain radians

Public float getRad(float px1, float py1, float px2, float py2) {float x = px2 - px1; float y = py1 - py2; // Long float z = (float) math.sqrt (math.pow (x, 2) + math.pow (y, 2)); float cosAngle = x / z; float rad = (float) Math.acos(cosAngle); if (py2 < py1) { rad = -rad; } return rad; }Copy the code

Graphics rendering

Through the canvas. Methods like drawCircle () and canvas. DrawBitmap () for remote sensing, remote sensing background and the drawing of button, pay attention to the preservation of the background on the remote sensing, if every time when drawing BitmapFactory decodeResource () can increase the time consuming, Therefore, the bitmap is generated only in surfaceCreated ().

public void draw() { try { canvas = sfh.lockCanvas(); canvas.drawColor(getResources().getColor(R.color.ghostwhite)); Rect SRC = new Rect(0, 0, bitmap.getwidth (), bitmap.getheight ()); Rect DST = new Rect(bigcirclex-bigcircler, bigcircley-bigcircler, bigCircleX + bigCircleR, bigCircleX + bigCircleR, bigCircleY + bigCircleR); Remoteviewbg.draw (canvas, paint, SRC, DST); paint.setColor(0x70ff0000); DrawCircle (smallCircleX, smallCircleY, smallCircleR, paint); } catch (Exception e) { // TODO: handle exception } finally { try { if (canvas ! = null) sfh.unlockCanvasAndPost(canvas); } catch (Exception e2) { e2.printStackTrace(); }}}Copy the code

use

Add it dynamically in the activity

    RelativeLayout relativeLayout = (RelativeLayout) findViewById(R.id.dance_relative_layout);
    remoteSurfaceView = new RemoteSurfaceView(this);
    params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, 
    RelativeLayout.LayoutParams.MATCH_PARENT);
    remoteSurfaceView.setLayoutParams(params);
    relativeLayout.addView(remoteSurfaceView);
    
Copy the code

The key code

public RemoteSurfaceView(Context context) { super(context); sfh = this.getHolder(); sfh.addCallback(this); paint = new Paint(); paint.setAntiAlias(true); setFocusable(true); setFocusableInTouchMode(true); setZOrderOnTop(true); getHolder().setFormat(PixelFormat.TRANSPARENT); } public void surfaceCreated(SurfaceHolder holder) { int width = getWidth(); int height = getHeight(); bigCircleX = width / 2; bigCircleY = height / 2; bigCircleR = width / 4; smallCircleX = width / 2; smallCircleY = height / 2; smallCircleR = width / 8; bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.fangxiang); remoteViewBg = new RemoteViewBg(bitmap); th = new Thread(this); flag = true; th.start(); Public float getRad(float px1, float py1, float px2, float py2) {float x = px2 - px1; float y = py1 - py2; // Long float z = (float) math.sqrt (math.pow (x, 2) + math.pow (y, 2)); float cosAngle = x / z; float rad = (float) Math.acos(cosAngle); if (py2 < py1) { rad = -rad; } return rad; } @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_DOWN || Event.getaction () == motionEvent.action_move) {// Out of scope touch if (math.sqrt (math.pow ((bigCircleX - (int) event.getx ()), 2) + Math.pow((bigCircleY - (int) event.getY()), 2)) >= bigCircleR) { double tempRad = getRad(bigCircleX, bigCircleY, event.getX(), event.getY()); getXY(bigCircleX, bigCircleY, bigCircleR, tempRad); } else {// smallCircleX = (int) event.getx (); smallCircleY = (int) event.getY(); } } else if (event.getAction() == MotionEvent.ACTION_UP) { smallCircleX = bigCircleX; smallCircleY = bigCircleY; } return true; } public void getXY(float x, float y, float R, double rad) { smallCircleX = (float) (R * Math.cos(rad)) + x; smallCircleY = (float) (R * Math.sin(rad)) + y; } public void draw() { try { canvas = sfh.lockCanvas(); canvas.drawColor(getResources().getColor(R.color.ghostwhite)); Rect src = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); Rect dst = new Rect(bigCircleX - bigCircleR, bigCircleY - bigCircleR, bigCircleX + bigCircleR, bigCircleY + bigCircleR); Remoteviewbg.draw (canvas, paint, SRC, DST); paint.setColor(0x70ff0000); DrawCircle (smallCircleX, smallCircleY, smallCircleR, paint); } catch (Exception e) { // TODO: handle exception } finally { try { if (canvas ! = null) sfh.unlockCanvasAndPost(canvas); } catch (Exception e2) { e2.printStackTrace(); } } } public void run() { while (flag) { draw(); try { Thread.sleep(50); } catch (Exception ex) { ex.printStackTrace(); }}}Copy the code

subsequent

The blogger’s implementation mode has also been changed, from SurfaceView to View, but also increased the direction of the arrow indication, time, memory and other optimization, the subsequent update, like favorites.