Andriod applet-simply making a wheel to control the movement of tasks in the game

Keywords: Mobile Android xml less SurfaceView

Andriod applet - Simply making the wheel that controls the movement of characters in the game

Explain

Recently, there is a project, one of the requirements of the project is to make a control device around the wheel. Many of them are turntables for guessing awards on the internet. This rookie expresses his complex mood. So it took 19 hours for this chicken to make a simple moulding, not to mention much, first of all, the picture above.

The two numbers that appear above are moving parameters, which I will explain in a moment.
This effect is fairly simple to implement and contains the whole class at the end of the article. As long as there is a little android foundation, you can understand it at a glance. The next step is to explain it step by step.

Customizing your own view inherits from the View class

Generally, they inherit from the View class and look at their own needs.
Surface View, of course, can be inherited, but here, it won't be refreshed all the time. I don't think it's necessary.

public class DiscView extends View {
	//Some people may not understand the meaning of the three constructions. Let me explain.

	//Call this when new in the main program
	//DiscView disc = new DiscView(this);
	public DiscView(Context context) {
        this(context,null);
    }

	//To create a control in an xml file is to call this
    public DiscView(Context context,AttributeSet attrs) {
        this(context, attrs, 0 );
    }

	//Create a control in an xml file and use this method when specifying style attributes, otherwise default to the second
    public DiscView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        manager = LocalBroadcastManager.getInstance(context);
    }
}

Override onDraw() method

Here is the point, the core of the whole control step by step.

When we see this control, it looks like that, as shown in the figure.

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.TRANSPARENT);

        //Setting the radius of the background map
        radiusBack = getWidth() / 2;
        //Setting the radius of a small circle
        radiusPre = getWidth() / 4;
        //Center of a circle
        circleX = getWidth() / 2;
        circleY = getHeight() / 2;

        if (paint == null) {
            paint = new Paint();
        }
        //Setting the basic attributes of the brush
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0x7f111111);
        //Draw the inner circle
        canvas.drawCircle(circleX,circleY,(float) radiusBack,paint);
        //Draw the outer circle, the inner circle and the outer circle have different colors, so use different colors.
        paint.setColor(0xFF744041);
        canvas.drawCircle(btnX,btnY,(float) radiusPre,paint);
        canvas.save();
    }

But this is certainly not the effect we need.
So it must be refreshed dynamically. Let's sort out our ideas.

To refresh the inner circle when finger clicks or moves
Fingers off the screen
static state
Refreshed graphics
The inner circle returns to its original position while recording the parameters
End

Next, implement the process

Perfecting onDraw() Method

Because the position of the finger is to be captured, rewriting onTouch() is indispensable.

Rewrite the OnTouch() method

	@Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_MOVE:
            	//This method is called when the finger moves on the screen, (btnX,btnY) is the center of the inner circle.
            	//We need to drive the inner circle according to the position of our fingers at any time, so we need to record the center of the circle in the process of finger movement.
                btnX = (int) event.getX();
                btnY = (int) event.getY();
                //Record the center of the circle and judge it. We don't want our inner circle to go outside completely. So we should judge it. When the center of the inner circle leaves the outer circle, we should control him not to leave the outer circle.
                //The Pythagorean theorem is used here.
                if ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX) >= radiusBack * radiusBack){
                	//Change the position of the center of a circle
                    changeBtnLocation();
                }
                //Each time the screen is submitted and refreshed, invalidate calls the OnDraw() method
                this.invalidate();
                break;
            case MotionEvent.ACTION_UP:
            	//When the finger leaves, set both btnX and btnY to zero, and judge in onMesure, when both are zero.
            	btnX = 0;
                btnY = 0;
                //Likewise refresh
                this.invalidate();
                break;
        }
        //When you return to true, the screen will intercept and consume your gestures.
        return true;
    }

For the changeBtnLocation() method, mathematical knowledge is used here.
Here I drew a picture. It's easy to understand.

	/**
     * Mathematical knowledge, similar triangles, will be used here.
     */
    private void changeBtnLocation() {
        //Similarity ratio
        double similarity = Math.sqrt((radiusBack * radiusBack) / ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX)));
        //Change the location of (btnX,btnY)
        btnX = (int) ((btnX - circleX)*similarity + circleX);
        btnY = (int) ((btnY - circleY)*similarity + circleY);
    }

The previous onDraw() method is only the previous version. Here, we need to change it so that he can refresh it differently according to the value of the generated btnX btnY.

Update onDraw() method

	@Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.TRANSPARENT);

        //Setting the radius of the background map
        radiusBack = getWidth() / 2;
        //Setting the radius of a small circle
        radiusPre = getWidth() / 4;
        //Center of a circle
        circleX = getWidth() / 2;
        circleY = getHeight() / 2;

        if (paint == null) {
            paint = new Paint();
        }
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0x7f111111);
        canvas.drawCircle(circleX,circleY,(float) radiusBack,paint);
        //If the finger leaves the screen
        if (btnX <= 0 && btnY <= 0){
            paint.setColor(0xFFF10159);
            canvas.drawCircle(circleX,circleY,(float) radiusPre,paint);
            canvas.save();
            return;
        }
        //The reason why finger clicks on the screen has different color parameters is to let the clicks have feedback.
        paint.setColor(0xFF744041);
        canvas.drawCircle(btnX,btnY,(float) radiusPre,paint);
        canvas.save();
    }

Write here, there will be a problem can almost run. But there are a few more questions.

  • The layout_width and layout_height of the control are the same.
  • When the inner circle moves to the edge, it will be cut off. It's ugly.
  • Control is finished, but how do we use our main program? You can't create a control to look good.

On the first question, I am too lazy to write about many solutions on the Internet. I set the same solution directly when I use it. If necessary, rewrite the onMeasure() method.

Solving legacy problems

Solving Cutting Problem

Simply, let the diameter of the inner circle and the outer circle add up to less than the width of the control, that is, getWidth().

	//Setting the radius of the background map
    radiusBack = getWidth() / 3;
	//Setting the radius of a small circle
    radiusPre = getWidth() / 8;
    // 2 / 3 + 2 / 8 = 11 / 12 < 1

Solve the problem of calling main program

It's also simple; just send a broadcast as needed while moving or leaving your fingers.
Just receive the broadcast in the main program.

	private void sendAction(int x,int y) {
        Intent intent = new Intent(DISC_BROADCAST);
        intent.putExtra("move",(x - circleX) + " " + (y - circleY));
        manager.sendBroadcast(intent);
    }

Finally, put in the complete code of the program.

Rewritten controls

package com.example.administrator.myapplication;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.support.v4.content.LocalBroadcastManager;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.Toast;

public class DiscView extends View {

    private Paint paint;
    private int btnX;
    private int btnY;
    //Radius of inner and outer circles
    private int radiusBack;
    private int radiusPre;
    //Center of Circle
    private float circleX;
    private float circleY;

    //Broadcasting action
    public static final String DISC_BROADCAST = "com.scsdesign.DISCVIEW";
    private LocalBroadcastManager manager;


    public DiscView(Context context) {
        this(context,null);
    }

    public DiscView(Context context,AttributeSet attrs) {
        this(context, attrs, 0 );
    }

    public DiscView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        manager = LocalBroadcastManager.getInstance(context);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawColor(Color.TRANSPARENT);

        //Setting the radius of the background map
        radiusBack = getWidth() / 3;
        //Setting the radius of a small circle
        radiusPre = getWidth() / 8;
        //Center of a circle
        circleX = getWidth() / 2;
        circleY = getHeight() / 2;

        if (paint == null) {
            paint = new Paint();
        }
        paint.setAntiAlias(true);
        paint.setStyle(Paint.Style.FILL);
        paint.setColor(0x7f111111);
        canvas.drawCircle(circleX,circleY,(float) radiusBack,paint);
        if (btnX <= 0 && btnY <= 0){
            paint.setColor(0xFFF10159);
            canvas.drawCircle(circleX,circleY,(float) radiusPre,paint);
            canvas.save();
            return;
        }
        paint.setColor(0xFF744041);
        canvas.drawCircle(btnX,btnY,(float) radiusPre,paint);
        canvas.save();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()){
            case MotionEvent.ACTION_MOVE:
                System.out.println(event.getX() + " " + event.getY());
                btnX = (int) event.getX();
                btnY = (int) event.getY();
                if ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX) >= radiusBack * radiusBack){
                    changeBtnLocation();
                }
                this.invalidate();
                break;
            case MotionEvent.ACTION_UP:
                System.out.println(event.getX() + " " + event.getY() + "TAG");
                //Broadcasting
                sendAction(btnX,btnY);
                btnX = 0;
                btnY = 0;
                this.invalidate();
                break;
        }

        return true;
    }



    private void sendAction(int x,int y) {
        Intent intent = new Intent(DISC_BROADCAST);
        intent.putExtra("move",(x - circleX) + " " + (y - circleY));
        manager.sendBroadcast(intent);
    }

    /**
     * Mathematical knowledge will be used here.
     */
    private void changeBtnLocation() {
        //Similarity ratio
        double similarity = Math.sqrt((radiusBack * radiusBack) / ((btnY - circleY)*(btnY - circleY) + (btnX - circleX)*(btnX - circleX)));
        btnX = (int) ((btnX - circleX)*similarity + circleX);
        btnY = (int) ((btnY - circleY)*similarity + circleY);
    }

}

Call in main program

package com.example.administrator.myapplication;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v4.content.LocalBroadcastManager;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.widget.TextView;

public class MainActivity extends AppCompatActivity {

    private TextView textView;
    private String message;
    private MyBroadCastReceiver receiver;
    private LocalBroadcastManager manager;
    private DiscView view;
    private boolean is = false;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        view = findViewById(R.id.view);
        textView = findViewById(R.id.textView2);

		/**
		 * Register local broadcasting receivers to receive broadcasts
		 **/
        manager = LocalBroadcastManager.getInstance(this);
        IntentFilter filter = new IntentFilter();
        filter.addAction(view.DISC_BROADCAST);
        receiver = new MyBroadCastReceiver();
        manager.registerReceiver(receiver,filter);
    }

    class MyBroadCastReceiver extends BroadcastReceiver {

        @Override
        public void onReceive(Context context, Intent intent) {
            String string = intent.getStringExtra("move");
            textView.setText(string);
        }
    }

}

Posted by Zomie on Tue, 29 Jan 2019 02:54:15 -0800