二次采样比例图像视图 - 在 Imageview 上使引脚标记可点击

Posted

技术标签:

【中文标题】二次采样比例图像视图 - 在 Imageview 上使引脚标记可点击【英文标题】:Subsampling scale image view - make pin markers clickable on Imageview 【发布时间】:2016-05-20 08:34:50 【问题描述】:

我正在使用 Dave Morrissey 的 Subsampling Scale Image View。我修改了 Pinview 示例(如下所示:https://github.com/davemorrissey/subsampling-scale-image-view/blob/master/sample/src/com/davemorrissey/labs/subscaleview/sample/extension/views/PinView.java)以支持引脚数组。现在我想让每个引脚都可以点击以触发点击功能。下面的代码正确放置了多个标记。请让我知道如何使每个图钉可点击,我想读取点击事件函数中的 id 并在 toast 示例中显示 MapPin(1718f, 581f, (id) 1)。

修改PinView.java

   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(), 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


MapPin.java

    public class MapPin 
    float X, Y;
    int id;

        public MapPin(float X, float Y, int id) 
            this.X = X;
            this.Y = Y;
            this.id = id;
        

        public MapPin() 
        

        public float getX() 
            return X;
        

        public void setX(float X) 
            this.X = X;
        

        public float getY() 
            return Y;
        

        public void setY(float Y) 
            this.Y = Y;
        

        public PointF getPoint() 
            return new PointF(this.X, this.Y);
        

        public int getId() 
            return id;
        

        public void setId(int id) 
            this.id = id;
        
    

DrawPin.java

public class DrawPin 

    float startX, startY, endX, endY;
    int id;

    public DrawPin(float startX, float startY, float endX, float endY, int id) 
        this.startX = startX;
        this.startY = startY;
        this.endX = endX;
        this.endY = endY;
        this.id = id;
    

    public DrawPin() 
        //empty
    

    public float getStartX() 
        return startX;
    

    public void setStartX(float startX) 
        this.startX = startX;
    

    public float getStartY() 
        return startY;
    

    public void setStartY(float startY) 
        this.startY = startY;
    

    public float getEndX() 
        return endX;
    

    public void setEndX(float endX) 
        this.endX = endX;
    

    public float getEndY() 
        return endY;
    

    public void setEndY(float endY) 
        this.endY = endY;
    

    public int getId() 
        return id;
    

    public void setId(int id) 
        this.id = id;
    

ExtensionPinFragment

public class ExtensionPinFragment extends Fragment 
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
        View rootView = inflater.inflate(layout.extension_pin_fragment, container, false);
        rootView.findViewById(id.next).setOnClickListener(new OnClickListener() 
            @Override
            public void onClick(View view) 
                ((ExtensionActivity) getActivity()).next();
            
        );
        PinView imageView = (PinView)rootView.findViewById(id.imageView);
        imageView.setImage(ImageSource.asset("squirrel.jpg"));

        MapPin mapPin = new MapPin(1718f, 581f, 1);
        MapPin mapPin1 = new MapPin(500f, 681f, 2);

        ArrayList<MapPin> MapPins = new ArrayList();
        MapPins.add(new MapPin(1718f, 581f, 1));
        MapPins.add(new MapPin(500f, 681f, 2));
        imageView.setPins(MapPins);

        // Below on click listener associated with entire image but I want the click event listener for individual pins

        imageView.setOnClickListener(new OnClickListener() 
                                         @Override
                                         public void onClick(View view) 
                                             ((ExtensionActivity) getActivity()).next();
                                         
                                     
        );
        return rootView;
    

【问题讨论】:

您是否设法添加了点击标记,如果是,请分享那部分代码。谢谢 【参考方案1】:

目前正在处理相同的问题: 您可以按照以下建议向您的自定义视图添加一个手势检测器和一个触摸侦听器: https://github.com/davemorrissey/subsampling-scale-image-view/wiki/09.-Events

在 GestureDetector 中重写 onSingleTapConfirmed() 方法并检查点击的触摸坐标是否与针坐标匹配(使用 sourceToView 转换触摸和针坐标...),如果匹配,则处理您要执行的任何代码。

这是我的自定义 SubsamplingScaleImageView 中的部分代码,在将 pin 添加到视图后调用:

  private void setTouchListener() 
    /** https://github.com/davemorrissey/subsampling-scale-image-view/wiki/09.-Events:
     *  ...you must check that the view is ready with the isReady() method before attempting to convert screen
     *  coordinates to image coordinates. A NullPointerException may be thrown if you don't. It is safe to override
     *  onSingleTapUp, onSingleTapConfirmed, onLongPress and onDown from the SimpleOnGestureListener class. If you
     *  override other methods, you will prevent the view from properly handling double taps, zoom and pan gestures.
     */

    final GestureDetector gestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() 
        @Override
        public boolean onSingleTapConfirmed(MotionEvent e) 
            if (isReady() && deeplinkCoordinates != null) 
                PointF tappedCoordinate = new PointF(e.getX(), e.getY());

                int blockWidth = deepLinkBitmap.getWidth();
                int blockHeight = deepLinkBitmap.getHeight();

                // check if deepLinkBitmap is touched
                for (PointF deeplink : deeplinkCoordinates) 
                    PointF deeplinkCoordinate = sourceToViewCoord(deeplink);
                    int deeplinkX = (int) (deeplinkCoordinate.x - (deepLinkBitmap.getWidth() / 2));
                    int deeplinkY = (int) (deeplinkCoordinate.y - deepLinkBitmap.getHeight());

                    // center coordinate -/+ blockWidth actually sets touchable area to 2x icon size
                    if (tappedCoordinate.x >= deeplinkX - blockWidth && tappedCoordinate.x <= deeplinkX + blockWidth &&
                            tappedCoordinate.y >= deeplinkY - blockHeight && tappedCoordinate.y <= deeplinkY + blockHeight) 
                        // App.toast("You tapped on a deeplink!");
                     
                
            
            return true;
        
    );

    setOnTouchListener(new OnTouchListener() 
        @Override
        public boolean onTouch(View view, MotionEvent motionEvent) 
            return gestureDetector.onTouchEvent(motionEvent);
        
    );

【讨论】:

请详细说明什么是 deeplinkCoordinates? @dev_ry DeeplinkCoordinates 是一个 ArrayList,其中填充了已放置的坐标,因此您可以检查 SinglePress 是否“命中”标记。 什么是 deepLinkBitmap ?

以上是关于二次采样比例图像视图 - 在 Imageview 上使引脚标记可点击的主要内容,如果未能解决你的问题,请参考以下文章

在 imageview 中缩放图像

Android imageview不尊重maxWidth?

在LaunchScreen处ImageView的宽度填充父级宽度时保存图像比例(高度)

android:如何在imageview的水平中心对齐图像?

如何正确裁剪图像以适合 imageview

ImageView setScaleX / Y,比例因子<1