RegionとPathを用いた特定の部分のTouchEventの取り方

前回書いたViewの記事の補足を少し。
なんか日本語の記事が見つからなかったので書いちゃう。

TouchEventの制御

そもそもViewのonTouchEventが呼ばれる時はpaddingやTouchDelegateをしない限り四角いViewを触った時に呼ばれるはずです。

f:id:amyu_dev:20150204162935p:plain
例えば、上のようなViewがあるとして、望まれる挙動は空白の白い部分にはClickListenerを付けず、六角形の内部のみClickListenerを付けイベントを飛ばしたいと考えると思います。
そんな時役に立つのがRegionでした。

IngressAchievements/AchievementView.java at develop · amyu/IngressAchievements · GitHub
このViewを見てもらえればさくっと伝わるんですが、

/**
 * Pathを引きながらRegionにいろいろとセットする処理
 */
for (int i = 0; i < VERTEX_NUM + 1; i++) {
    double cos = Math.cos(Math.toRadians(60 * i + 30));    
    double sin = Math.sin(Math.toRadians(60 * i + 30));

    double innerX = centerX + radius * cos;
    double innerY = centerY + radius * sin;
    mInnerPath.lineTo((float) innerX, (float) innerY);
}

mRectF.setEmpty();

//RectFに対してPathの外枠の座標をセットする
mInnerPath.computeBounds(mRectF, true);

mRegion.setEmpty();

mClipRegion.setEmpty();

//ClipとなるRegionに外枠の座標をセットしたRectFをセットする
mClipRegion.set((int) mRectF.left, (int) mRectF.top, (int) mRectF.right, (int) mRectF.bottom);

//Regionに対してPathとClipとなるRegionをセットする
mRegion.setPath(mInnerPath, mClipRegion);

と言った感じでRegionをセットしていきます。

続いてonTouchEvent内での処理。

@Override
public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            //Regionに触られた部分の座標が含まれているか
            if (mRegion.contains((int) event.getX(), (int) event.getY())) {
                if (mOnClickListener == null) {
                    return true;
                }
                //何事もなかったらイベントを飛ばしてあげる
                mOnClickListener.onClick(this);
            }
            break;
    }
    return false;
}

と言った感じで実装できます。

最後に

Unityに浮気したい。
ではではー