Добавление маркерных булавок в положение касания с использованием представления изображения в масштабе субдискретизации

Я использую «представление изображения в масштабе субдискретизации» в своем приложении, и я хотел бы динамически добавлять маркеры в PinView, когда пользователь делает на нем длинный щелчок. Маркер должен появиться в месте щелчка.

Я добился того, что булавка маркера появляется после долгого щелчка, но в неправильном месте. Вот метод onCreateView моего фрагмента:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    pinCounter=0;

    View rootView = inflater.inflate(R.layout.fragment_edit_plan, container, false);
    src = getArguments().getString("src");
    imageView = (PinView)rootView.findViewById(R.id.imageView);

    imageView.setImage(ImageSource.uri(src));
    imageView.isLongClickable();
    imageView.isClickable();
    imageView.hasOnClickListeners();

    MapPins = new ArrayList();
    imageView.setPins(MapPins);

    imageView.setOnLongClickListener(this);
    imageView.setOnTouchListener(this);

    return  rootView;
}

Методы слушателя:

@Override
public boolean onLongClick(View view) {
    if (view.getId() == R.id.imageView) {
        Toast.makeText(getActivity(), "Long clicked "+lastKnownX+" "+lastKnownY, Toast.LENGTH_SHORT).show();
        Log.d("EditPlanFragment","Scale "+imageView.getScale());
        MapPins.add(new MapPin(lastKnownX,lastKnownY,pinCounter));
        imageView.setPins(MapPins);

        imageView.post(new Runnable(){
            public void run(){
                imageView.getRootView().postInvalidate();
            }
        });

        return true;
    }
    return false;
}

@Override
public boolean onTouch(View v, MotionEvent event) {
    if (v.getId()== R.id.imageView && event.getAction() == MotionEvent.ACTION_DOWN){
        lastKnownX= event.getX();
        lastKnownY= event.getY();
    }
    return false;
}

Мой XML-файл:

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingTop="50dp"
>

<com.example.viktoriabock.phoenixversion1.PinView
    android:id="@+id/imageView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:longClickable="true"

   />

And the PinView-Class:

public class PinView extends SubsamplingScaleImageView {

    private PointF sPin;

    ArrayList<MapPin> mapPins;
    ArrayList<DrawPin> drawnPins;
    Context context;
    String tag = getClass().getSimpleName();

    public PinView(Context context) {
        this(context, null);
        this.context = context;
    }

    public PinView(Context context, AttributeSet attr) {
        super(context, attr);
        this.context = context;
        initialise();
    }

    public void setPins(ArrayList<MapPin> mapPins) {
        this.mapPins = mapPins;
        initialise();
        invalidate();
    }

    public void setPin(PointF pin) {
        this.sPin = pin;
    }

    public PointF getPin() {
        return sPin;
    }

    private void initialise() {

    }

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

        // Don't draw pin before image is ready so it doesn't move around during       setup.
        if (!isReady()) {
            return;
        }

        drawnPins = new ArrayList<>();

        Paint paint = new Paint();
        paint.setAntiAlias(true);
        float density = getResources().getDisplayMetrics().densityDpi;


        for (int i = 0; i < mapPins.size(); i++) {
            MapPin mPin = mapPins.get(i);
            //Bitmap bmpPin = Utils.getBitmapFromAsset(context, mPin.getPinImgSrc());
            Bitmap bmpPin = BitmapFactory.decodeResource(this.getResources(), R.drawable.pushpin_blue);

            float w = (density / 420f) * bmpPin.getWidth();
            float h = (density / 420f) * bmpPin.getHeight();
            bmpPin = Bitmap.createScaledBitmap(bmpPin, (int) w, (int) h, true);

            PointF vPin = sourceToViewCoord(mPin.getPoint());
            //in my case value of point are at center point of pin image, so we need to adjust it here

            float vX = vPin.x - (bmpPin.getWidth() / 2);
            float vY = vPin.y - bmpPin.getHeight();

            canvas.drawBitmap(bmpPin, vX, vY, paint);

            //add added pin to an Array list to get touched pin
            DrawPin dPin = new DrawPin();
            dPin.setStartX(mPin.getX() - w / 2);
            dPin.setEndX(mPin.getX() + w / 2);
            dPin.setStartY(mPin.getY() - h / 2);
            dPin.setEndY(mPin.getY() + h / 2);
            dPin.setId(mPin.getId());
            drawnPins.add(dPin);
        }
    }

    public int getPinIdByPoint(PointF point) {
        for (int i = drawnPins.size() - 1; i >= 0; i--) {
            DrawPin dPin = drawnPins.get(i);
            if (point.x >= dPin.getStartX() && point.x <= dPin.getEndX()) {
                if (point.y >= dPin.getStartY() && point.y <= dPin.getEndY()) {
                    return dPin.getId();
                }
            }
        }
        return -1; //negative no means no pin selected
    }
}

person Vik Toria    schedule 01.11.2016    source источник


Ответы (1)


Вы собираете экранные координаты длительного нажатия, затем в пользовательском представлении вы конвертируете их из исходных координат в экранные координаты. Вам нужно преобразовать координаты события в исходные координаты, когда вы получите событие касания, используя метод представления viewToSourceCoord.

Есть более простой способ сделать это, чем использовать ваши значения lastKnown — используйте свои собственные значения GestureDetector.

Полный рабочий пример детектора жестов длительного нажатия см. в AdvancedEventHandlingActivity пример класса.

person Dave Morrissey    schedule 04.11.2016