Как предотвратить метод onClick на прозрачной части загруженного PNG ImageView

В настоящее время я разрабатываю приложение для Android, которое отображает несколько изображений (как ImageView's), уложенных друг на друга. Вот как настроены слои:

  • Фоновый слой: масштабирует весь экран, должен быть доступен для клика
  • Уровень переднего плана: масштабирует весь экран, должен быть доступен для кликов, содержит прозрачность, которая позволяет пользователю видеть некоторые из фоновый слой

Проблема, с которой я сталкиваюсь, - это слой переднего плана. Я назначаю метод onClick() для изображения, но метод вызывается, попадают ли они на часть видимого изображения, а также на часть, содержащую прозрачность. Мне нужен только метод переднего плана ImageView onClick(), когда пользователь нажимает на часть этого изображения, которая не прозрачна.

Вот как выглядит сценарий:

enter image description here

Диагональные линии представляют собой прозрачную часть изображения переднего плана. Если пользователь коснется этого пространства, я хочу, чтобы он имел доступ к фоновому изображению вместо изображения переднего плана. Спасибо за любую помощь, которую вы можете предоставить.

Вот решение, которое я выполнил (спасибо ниже):

//ontouchlistener - gets X and Y from event
private void setClick(View view)
{
    view.setOnTouchListener(new View.OnTouchListener() 
    {
        public boolean onTouch(View v, MotionEvent event) 
        {
            int imageId = getImageId((int)event.getX(), (int)event.getY());
            if (imageId >= 0)
                performActions(imageId);
            return false;
        }
    });
}

//get the ID of the first imageview (starting from foreground, 
//working backwards) which contains a non-transparent pixel
private int getImageId(int x, int y)
{
    ViewGroup parent = (ViewGroup) findViewById(R.id.relative_layout);
    for (int a = parent.getChildCount()-1; a >= 0; a--)
    {
        if (parent.getChildAt(a) instanceof ImageView)
            if (!checkPixelTransparent((ImageView)parent.getChildAt(a), x, y))
                return parent.getChildAt(a).getId();
    }
    return -1;
}

//get bitmap from imageview, get pixel from x, y coord
//check if pixel is transparent
private boolean checkPixelTransparent(ImageView iv, int x, int y)
{
    Bitmap bitmap = ((BitmapDrawable) iv.getDrawable()).getBitmap();
    if (Color.alpha(bitmap.getPixel(x, y)) == 0)
        return true;
    else
        return false;
}

Ответ 1

Этот один образец делает прозрачную область ImageView недоступной.

ImageView:

ImageView imgView= (ImageView) findViewById(R.id.color_blue);
imgView.setDrawingCacheEnabled(true);
imgView.setOnTouchListener(changeColorListener);

OnTouchListener:

private final OnTouchListener changeColorListener = new OnTouchListener() {

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        Bitmap bmp = Bitmap.createBitmap(v.getDrawingCache());
        int color = bmp.getPixel((int) event.getX(), (int) event.getY());
        if (color == Color.TRANSPARENT)
            return false;
        else {
            //code to execute
            return true;
        }
    }
};

Ответ 2

Если ваше изображение переднего плана - это не просто прямоугольное, а сложное изображение, и вам действительно нужно, чтобы прикосновение было точным для пикселя, вы можете использовать

http://developer.android.com/reference/android/view/View.OnTouchListener.html

foregroundImage.setOnTouchListener(new View.OnTouchListener(){...});

MotionEvent в обратном вызове будет содержать действия (например, Touch up) и точное местоположение.

Если вы знаете точный размер изображения переднего плана, как он отображается, вы можете определить, какой пиксель его был нажат, а затем проверить, является ли этот пиксель альфа 0. Или вам может потребоваться применить некоторое масштабирование, если изображение было масштабируется. Это может стать довольно сложным, поскольку в зависимости от размера экрана и пропорций изображение может быть масштабировано/расположено по-разному. Это также зависит от используемых вами макетов.

Для проверки значения пикселя вам, вероятно, потребуется сохранить в памяти объект Bitmap, содержащий ваши данные переднего плана.

Честно говоря, я сомневаюсь, что вам действительно понадобится вся эта точность, если ваше изображение переднего плана не имеет очень неправильной формы.

Ответ 3

Bitmap.createBitmap(v.getDrawingCache() и imageView.setDrawingCacheEnabled(true) устарели, поэтому вы можете сделать это с помощью следующего фрагмента кода:

imageView.setOnTouchListener { v, event ->
            val bmp = convertViewToDrawable(v)
            val color: Int = bmp.getPixel(event.x.toInt(), event.y.toInt())
            if (color == Color.TRANSPARENT)
                [email protected] false
            else {
                Toast.makeText(baseContext, "image clicked", Toast.LENGTH_SHORT).show()
                [email protected] true
            }
        }

private fun convertViewToDrawable(view: View): Bitmap {
        val b = Bitmap.createBitmap(view.measuredWidth, view.measuredHeight,
            Bitmap.Config.ARGB_8888)
        val c = Canvas(b)
        c.translate((-view.scrollX).toFloat(), (-view.scrollY).toFloat())
        view.draw(c)
        return b
    }