(Android布局) 如何在不规则形状的图像上放置按钮或获取图片特定区域的触摸检测(可触摸区域)?

5
在我的Android应用程序中,我有三个不规则的形状横跨地球,如下所示:
所以我把整个图片放在布局中。地球只是一张图片。这里没有地球的作用。现在,我想在每个不规则的图片顶部放置一个按钮。
按钮始终是矩形的,但我想获取不规则形状的触摸事件,而不是矩形区域的触摸事件。那么,我该如何在这三个不规则形状上放置三个按钮,或者有没有其他解决方案?这样可以在活动中处理每个按钮的不同事件?
我不知道如何完成这个任务。请指导我。有什么建议或意见吗?
非常感谢您的帮助。

获取触摸位置!https://dev59.com/kXA75IYBdhLWcg3wGU-I - Rachit Mishra
1
这将有所帮助:https://dev59.com/sGXWa4cB1Zd3GeqPOpxI 此外,您还可以将布局分成虚拟的段/弧,并处理触摸事件。 - JiTHiN
1
你看到这个了吗?https://dev59.com/u1zUa4cB1Zd3GeqP1UGq#8086317 - Rachit Mishra
1
任何你想要的,我很高兴至少能够提供一些帮助 :) - Rachit Mishra
@Ponting 发布你的解决方案并接受它,这可能会帮助未来的其他人。 - Rachit Mishra
显示剩余10条评论
4个回答

1
我没有测试过这个,但我认为它会起作用。我相信你需要微调并进行更正。
创建一个背景图像的副本,在这个副本中,三个按钮是三个不同的颜色,没有锯齿,并且所有其他像素都是纯黑色。它需要是PNG格式,这样就不会有JPG压缩伪影。这将是您的掩码。您可以只使用纯红、绿和蓝色,因为您只有三个按钮。它可能比原始图像分辨率低,只要纵横比相同即可。
子类化ImageView,并使用您的子类来绘制背景。将您子类化的ImageView版本传递给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();
            }
        }
    }
}

现在您可以创建一个OnTouchedListener,处理类似于按钮的触摸逻辑。它需要跟踪状态。这是一个例子,但我不确定当有多个触摸时是否会出现问题。您可能还需要为第一个手指设置一个操作掩码,并使用getActionMasked()而不是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;
}

这有点简陋,因为您需要四个不同的图像副本来表示四种可能的状态。如果您愿意花时间节省一些内存并使其运行更快,则可以尝试使用单独的图像视图设置布局,以便在正确位置覆盖三个按钮,并针对这些进行图像更改。但考虑到您必须使其完全适配任何屏幕尺寸,这将非常具有挑战性。

兄弟,这似乎是非常高级的概念。我只是一个天真的开发者。谢谢你的回答。这个线程https://dev59.com/sGXWa4cB1Zd3GeqPOpxI解决了我的问题。 - Ponting
那个解决方案更简单,但你仍然需要做类似于我的第二段代码的事情,以使其表现得像一个按钮(当你按下它时,按钮图像会改变,并且你可以通过在释放之前将手指拖离来取消按钮按下)。你打算为每个按钮使用单独的图像视图吗? - Tenfour04
是的,我正在使用单独的图像视图。 - Ponting

0

从以上答案中,我得到了提示,最终我得到了以下解决方案:

我所做的是:

在xml文件中使用RelativeLayout

使用ImageView,如下所示:

  <ImageView
        android:id="@+id/btn1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/glob2"
        android:layout_marginBottom="24dp"
        android:layout_marginLeft="80.5dp"
        android:contentDescription="@string/profile_picture_description"
        android:src="@drawable/pick_matches_background" />

这里我根据需要设置了相应的边距(左/右/下/上)。

在活动中,

声明

Bitmap btmp; and
ImageView img;

在 onCreate 方法中,
 // initialized image view
img = (ImageView) findViewById(R.id.btn1);
img.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {

       // call your method here

  }
});

StateListDrawable sdCreateTrip = (StateListDrawable) img
            .getDrawable();

btmp = ((BitmapDrawable) sdCreateTrip.getCurrent())
            .getBitmap();

现在你已经准备好了。


看起来你的边距使用了硬编码值,那在不同的屏幕尺寸上会怎么样? - Mike

0

FLAG_WINDOW_IS_OBSCURED 标志在过去对我来说效果很好,但可能需要一些调试才能正确使用。值得一试,但老实说,我仍然不确定它如何确定什么被遮挡和什么没有被遮挡,因此可能不适用于此处。

static OnTouchListener listenerMotionEvent = new OnTouchListener() {
    @Override
    public boolean onTouch(View view, MotionEvent motionEvent) {
        if ( (motionEvent.getFlags() | MotionEvent.FLAG_WINDOW_IS_OBSCURED) != MotionEvent.FLAG_WINDOW_IS_OBSCURED ) {
            return false;
            // View is not obscured so we pass on the event
        }

        // Process the motion event here and return true if you consume it
};

0
在Photoshop中对图像进行切割,然后将该图像放置在Web视图中是否有帮助?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接