简体   繁体   中英

Android: Need help in accurate position of shape drawing

In my Android project, I encountered some difficulties in the drawing code, so I made up a MCVE below to demonstrate the problem I have.

By running this example, and perform a touch in the screen, you can see two circles coming up.

You can see that the red one is positioned accurately and consistently around the point of touch.

For the green one, you can see that its position is somehow random on repeat touching of the screen.

The red circle is created using an ImageView with the source as ball.xml . For the green one, it is done by Canvas.drawCircle() .

So:

How do I correct the code to make the red circle and green circle appear at exactly the same spot on a touch, regardless of the resolution and dpi of the screen?

Also, btw, the 500X1000 dimension ( Bitmap.createBitmap(500, 1000) )is just set arbitrarily, it should be according to the screen size of the device.

MainActivity

package com.prime.testdraw;

import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.drawable.BitmapDrawable;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.MotionEvent;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.ImageView;

public class MainActivity extends AppCompatActivity {

    ImageView ivPhoto;
    FrameLayout fl;
    ImageView ivBall;
    private Canvas myCV;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ivPhoto = ((ImageView) findViewById(R.id.ivPhoto));
        fl = ((FrameLayout) findViewById(R.id.fl));
        ivBall = ((ImageView) findViewById(R.id.ivBall));
        myCV = initDraw(ivPhoto);

        ivPhoto.setOnTouchListener(new View.OnTouchListener() {
            @Override
            public boolean onTouch(View view, MotionEvent motionEvent) {
                myCV = initDraw(ivPhoto);
                ivBall.setX(motionEvent.getX() - ivBall.getWidth()/2);
                ivBall.setY(motionEvent.getY() - ivBall.getHeight()/2);
                Paint p = new Paint();
                p.setStrokeWidth(3);
                p.setColor(Color.GREEN);
                p.setTextSize(100);

                int radius = 40;
                p.setStyle(Paint.Style.STROKE);
                myCV.drawCircle(motionEvent.getX() - radius, motionEvent.getY() - radius, radius, p);
                ivPhoto.invalidate();

                return false;
            }
        });
    }
    private Canvas initDraw(ImageView imageView) {

        Bitmap bmp = Bitmap.createBitmap(500, 1000, Bitmap.Config.RGB_565);
        Canvas cv = new Canvas(bmp);

        imageView.setImageDrawable(new BitmapDrawable(getResources(), bmp));
        imageView.invalidate();
        return cv;
    }

}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/fl">
    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/ivPhoto"
        android:layout_centerVertical="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <ImageView
        android:layout_width="52dp"
        android:layout_height="52dp"
        android:id="@+id/ivBall"
        android:layout_gravity="left|top"
        android:src="@drawable/ball" />

</FrameLayout>

ball.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval" >
    <stroke
        android:width="4dp"
        android:color="#FF0000" />

    <gradient android:startColor="#FFFF0000" android:endColor="#80FF0000"
        android:angle="270"/>
</shape>

Canvas.drawCircle works with these parameters :

  1. cx float: The x-coordinate of the center of the cirle to be drawn
  2. cy float: The y-coordinate of the center of the cirle to be drawn
  3. radius float: The radius of the cirle to be drawn
  4. paint Paint: The paint used to draw the circle

Therefore instead of substracting the radius when calling it, simply call drawCircle directly :

myCV.drawCircle(motionEvent.getX(), motionEvent.getY(), radius, p);

Source : Android Canvas doc

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM