Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(Android Layout) Solution for Place button on top of the irregular shaped image or get touch detection(touchable area) of particular area of image?

In my Android Application, I have three irregular shape across globe as below :

enter image description here

So I placed this whole image in layout.Globe is just an image .There is no role of globe here. Now I want to place one buttons on top of the each irregular shaped images which are across the globe.

Button is always rectangular but I want to get touch event for irregular shape,not for rectangular area. So How can I put three buttons on these three irregular shape or is there any solution? so that different event for each button can be handled in activity?

I don't have idea on how to achieve this task. Please guide me on this.

Any advice or suggestions ?

Any help will be appreciated.

like image 940
Ponting Avatar asked Nov 12 '22 23:11

Ponting


1 Answers

I haven't tested this, but I think it will work. I'm sure you'll have to tweak it and make corrections.

Create a copy of your background image where the three buttons are three distinct colors with no aliasing, and all other pixels are pure black. It needs to be a PNG so it won't have JPG compression artifacts. This will be your mask. You can just use pure red, green, and blue since you have only three buttons. It can probably be lower resolution than your original image, as long as the aspect ratio is the same.

Subclass ImageView and use your subclass instead for drawing the background. Pass your subclassed version of ImageView your mask image as a Bitmap.

class TouchMaskImageView extends ImageView {
    ...constructors

    public void setTouchMask(Bitmap mask){
        this.mMask = mask;
    }

    public interface OnTouchedListener{
        public void onTouched(MotionEvent event, int colorTouched);
        public void onTouchCanceled();
    }

    public void setOnTouchedListener(OnTouchedListener listener){
        this.mOnTouchedListener = listener;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float x = event.getX();
        float y = event.getY();
        if (mOnTouchedListener  != null && mMask != null ) {
            if (x >=0 && x < (float)getWidth() &&
                y >=0 && y < (float)getHeight()) {
                //Next two lines will be more complicated if 
                  // you aren't using scaleType fitXY
                int maskX = (int) x * mMask.getWidth() / getWidth();
                int maskY = (int) y * mMask.getWidth() / getHeight();
                int maskColor = mask.getPixel(maskX, maskY);
                mOnTouchedListener.onTouched(event, maskColor);
            } else if (event.getAction()==MotionEvent.UP){
                //released finger outside image view
                mOnTouchedListener.onTouchCanceled();
            }
        }
    }
}

Now you can create an OnTouchedListener that handles touch logic similar to a button. It will need to track states. Here's an example, but I'm not sure if this will break when there are multi-touches. You may need to also set an action mask for the first finger and use getActionMasked() instead of getAction().

public void onTouched(MotionEvent event, int colorTouched){
    switch(mState){
    case STATE_WAITING:
        if (event.getAction()==MotionEvent.ACTION_DOWN){
            switch (colorTouched){
            case 0xffff0000: //red
                mTouchMaskImageView.setImageResource(R.drawable.redButtonDown);
                mState = STATE_LATCHED_RED;
                break;
            case 0xff00ff00: //green
                mTouchMaskImageView.setImageResource(R.drawable.greenButtonDown);
                mState = STATE_LATCHED_GREEN;
                break;
            case 0xff0000ff: //blue
                mTouchMaskImageView.setImageResource(R.drawable.blueButtonDown);
                mState = STATE_LATCHED_BLUE;
                break;
            }
        }
        break;
   case STATE_LATCHED_RED:
        switch (event.getAction()){
        case (MotionEvent.ACTION_MOVE):
            if (colorTouched = 0xffff0000)
                mTouchMaskImageView.setImageResource(R.drawable.redButtonDown);
            else
                mTouchMaskImageView.setImageResource(R.drawable.defaultImage);
            break;
        case (MotionEvent.ACTION_UP)
            if (colorTouched = 0xffff0000)
                performRedButtonAction();
            mTouchMaskImageView.setImageResource(R.drawable.defaultImage);
            mState = STATE_WAITING;
            break;
        }
        break;
   case etc. for other two latched colors...
        break;
   }
}

public void onTouchCanceled(){
    mTouchMaskImageView.setImageResource(R.drawable.defaultImage);
    mState = STATE_WAITING;
}

This is somewhat crude, since you would need four different copies of your image to represent the four possible states. If you want to put the time in to save some memory and make it run faster, you could try to set up your layout with separate image views for the three buttons overlayed in the correct positions and target those for the image changes. But this would be very challenging, considering you would have to make it line up perfectly for any screen size.

like image 158
Tenfour04 Avatar answered Nov 14 '22 23:11

Tenfour04