Small Demo, Big Knowledge - Learn Android Coordinates by Controlling Button Movement

Small Demo, Big Knowledge - Learn Android Coordinates by Controlling Button Movement

Today I will share a simple demo. The function implemented by the demo is that when you click the button with your mouse, you drag the button. At this time, the button will move according to the movement of your mouse. At the same time, the position of the button you clicked will not change. For example, if you click on the upper left corner of the button, when you move it, the mouse is still in the upper left corner of the button.

The effect picture of a disagreement

Don't mind the blurry gif above, after all, I took it with my phone. (What can you do to me if you mind? Haha)

Let's get some basic knowledge first:

The methods involved are as follows:

  • view gets its own coordinates: getLeft(), getTop(), getRight(), getBottom()
  • View gets its own width and height: getHeight(), getWidth()
  • motionEvent gets coordinates: getX(), getY(), getRawX(), getRawY()

1.view obtains its own coordinates

As shown in the figure above, the parent view of the green area is the yellow area, so left is 55 and top is 55.

The parent view of the yellow area is the blue area, so the left is 60 and the top is 115.

2.view gets its own width and height

That's right. As the name suggests, it means getting the width and height of the View.

Here is a problem I encountered before, that is, sometimes the width and height of a View in the Activity will be 0.

3. motionEvent gets coordinates

  • getX(): Gets the x-axis coordinate of the click event relative to the left side of the control, that is, the distance from the click event to the left side of the control
  • getY(): Gets the y-axis coordinate of the click event relative to the top edge of the control, that is, the distance between the click event and the top edge of the control
  • getRawX(): Gets the x-axis coordinate of the click event relative to the left side of the entire screen, that is, the distance from the click event to the left side of the entire screen
  • getRawY(): Gets the y-axis coordinate of the click event relative to the top edge of the entire screen, that is, the distance between the click event and the top edge of the entire screen

So when we click the middle of the Button with the mouse, getX() is the distance between the position where the mouse is clicked and the left border of the Button. getY() is the distance between the position where the mouse is clicked and the top border of the Button.

In fact, it is very simple to set the Button to follow the mouse. Just reset the x and y coordinates of the Button when the mouse is moved. That is, use setX() and setY(). Now there is a problem. What values ​​should be filled in these two methods? Let's draw a picture to see it.

First, let's set setX(200) and setY(200) for a Button, as shown in the following figure:

So actually setting setX(m) and setY(n) for a Button actually means that the coordinates of the upper left corner of the Button are (m,n). So when we drag, we can't simply pass the X and Y coordinates we clicked.

As shown in the figure above, if we click on the red area to move the button, and move the mouse to the green area, the button will also move to the position shown in the figure. This is what we expect.

However, if we simply pass the X and Y coordinates of the green area and let the Button perform setX and setY, the position of the Button will appear as shown below. So we find that it is further to the right and below than we expected.

At this time, we find that the extra position is exactly the X and Y coordinates of the relative position of the green area inside the Button.

Now we can think of setting setX(getRawX()-getX()) and setY(getRawY()- getY()) for Button. If you have thought of this, congratulations, you are one step away from the final success. When you write this happily, you will find that the Button you moved is always below the mouse click. You will find that the X axis is indeed correct, but the Y axis is still wrong. As shown in the following figure:

At this point you must be asking, WHY???

It turns out that this analysis is fine. But our previous assumptions are all in this coordinate system, but where is the location of this coordinate system???

Cause:

Because the getRawY() method we call gets the Y-axis distance from the upper left corner of the screen to the area we clicked, that is, the blue coordinate system is used as a reference. When we set the setY() method for Button, it is the Y-axis distance from the upper left corner of the green area to the area we clicked, that is, the red coordinate system is used as a reference. So we know. We also need to subtract the height of the status bar and the height of the application title bar on the Y axis.

Then there is a new problem. How to get the height of the status bar and the height of the application title bar:

Get the status bar height

  1. int statusBarHeight = -1;
  2. //Get the ID of the status_bar_height resource
  3. int resourceId = getResources().getIdentifier( "status_bar_height" , "dimen" , "android" );
  4. if (resourceId > 0) {
  5. //Get the size value of the response based on the resource ID
  6. statusBarHeight = getResources().getDimensionPixelSize(resourceId);
  7. }

Get the title bar height

  1. // Get the title bar height
  2. Window window = getWindow();
  3. int contentViewTop = getWindow()
  4. .findViewById(Window.ID_ANDROID_CONTENT).getTop();
  5. // statusBarHeight is the height of the status bar required above
  6. titleBarHeight = contentViewTop - statusBarHeight;

in conclusion:

So when we drag the Button again, we will setX(getRawX()-getX()) and setY(getRawY()-getY()-status bar height-title bar height) for it. getX() and getY() are obtained when you click it. That is, when motionEvent.getAction() == MotionEvent.ACTION_DOWN, you can get these two values. Because when motionEvent.getAction() == MotionEvent.ACTION_MOVE, getting getX() and getY() may cause different values ​​due to the speed of your dragging. For example, if you drag very fast, the mouse goes over first, and the Button follows. At this time, getX() and getY() are different.

Since the Button can be dragged after clicking it, the OnTouch listener must be set for the Button. Here are the key codes:  

  1. package yunyuan.androiddemo.coordinatelayout;
  2. import android.app.Activity;
  3. import android.os.Bundle;
  4. import android.view.MotionEvent ;
  5. import android. view . View ;
  6. import android.view.Window ;
  7. import android.widget.Button;
  8.  
  9. import butterknife.BindView;
  10. import butterknife.ButterKnife;
  11. import yunyuan.androiddemo.R;
  12.  
  13. /**
  14. * Created by willy on 16/12/19.
  15. */
  16.  
  17. public class Act_CoordinateLayout extends Activity{
  18.  
  19. @BindView(R.id.btn)
  20. Button btn;
  21.  
  22. float dx,dy;
  23.  
  24.  
  25. @Override
  26. protected void onCreate(Bundle savedInstanceState) {
  27. super.onCreate(savedInstanceState);
  28. setContentView(R.layout.act_coordinatelayout);
  29. ButterKnife.bind(this);
  30.  
  31. btn.setOnTouchListener(new Button.OnTouchListener() {
  32. @Override
  33. public boolean onTouch( View   view , MotionEvent motionEvent) {
  34. if(motionEvent.getAction() == MotionEvent.ACTION_DOWN){
  35. dx = motionEvent.getX();
  36. dy = motionEvent.getY();
  37.  
  38. } else if(motionEvent.getAction() == MotionEvent.ACTION_MOVE){
  39.  
  40. view .setX(motionEvent.getRawX() - dx);
  41. view .setY(motionEvent.getRawY()- dy - getStatusBarHeight() - getTitleBarHeight());
  42. }
  43. return   true ;
  44. }
  45. });
  46. }
  47.  
  48.  
  49. public   int getStatusBarHeight(){
  50. int result = 0;
  51. int resourceId = getResources().getIdentifier( "status_bar_height" , "dimen" , "android" );
  52. if (resourceId > 0) {
  53. result = getResources().getDimensionPixelSize(resourceId);
  54. }
  55. return result;
  56. }
  57.  
  58.  
  59. public   int getTitleBarHeight(){
  60. Window window = getWindow();
  61. int contentViewTop = getWindow()
  62. .findViewById(Window.ID_ANDROID_CONTENT).getTop();
  63. // statusBarHeight is the height of the status bar required above
  64. int titleBarHeight = contentViewTop - getStatusBarHeight();
  65. return titleBarHeight;
  66. }
  67. }

<<:  Understanding SharedPreferences in Android API

>>:  React Native touch event processing detailed explanation

Recommend

Where does the wind from a bladeless fan come from?

Nowadays, some parts of the country are still hot...

How does private domain operation conduct private domain operation?

Burning money, building up scale, raising funds, ...

What! Snow Rhon Rhon has grown in the ground? And it tastes sour! ?

During the Lantern Festival, everything is bright...

Apple releases major update iOS 13: iPhone is finally not green anymore!

This morning, Apple officially released iOS 13.6....

Is WeChat Phonebook really causing operators to lose sleep?

On November 11, 2014, WeChat officially added a h...

The so-called capital winter is nothing but the collapse of wishful thinking

Last year, we mentioned that winter is coming. Th...

APP advertising: How to choose the right delivery channel?

If you don’t advertise, you’re waiting for death;...

User operation: operation skills and channel establishment for user feedback

In operational work, there is a position that req...