Button 默認矩形點擊區域由 View.onTouchEvent 判斷。**繼承 Button/AppCompatButton,覆寫 onTouchEvent,按幾何圓形判斷觸摸點是否在半徑內**。
public class RoundButton extends AppCompatButton {
public RoundButton(Context context) { super(context); }
public RoundButton(Context context, AttributeSet attrs) { super(context, attrs); }
public RoundButton(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); }
@Override
public boolean onTouchEvent(MotionEvent event) {
// 1. 獲取觸摸點相對 View 左上角坐標
float x = event.getX();
float y = event.getY();
// 2. 計算 View 中心點與半徑(取寬高較小值一半,保證正圓)
float cx = getWidth() / 2f;
float cy = getHeight() / 2f;
float radius = Math.min(cx, cy);
// 3. 判斷點是否在圓內:距離平方 <= 半徑平方
float dx = x - cx;
float dy = y - cy;
boolean inside = (dx * dx + dy * dy) <= (radius * radius);
// 4. 若不在圓內,直接返回 false → 事件向下傳遞/忽略
if (!inside) {
return false;
}
// 5. 在圓內,交給父類處理(包含點擊反饋、點擊監聽器觸發)
return super.onTouchEvent(event);
}
}
<com.example.widget.RoundButton
android:id="@+id/btnRound"
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@drawable/bg_circle_blue"
android:text="GO"
android:textColor="@android:color/white" />
<!-- res/drawable/bg_circle_blue.xml -->
<shape xmlns:android="https://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#2196F3" />
<stroke android:width="2dp" android:color="#1976D2" />
</shape>
// attrs.xml
<declare-styleable name="RoundButton">
<attr name="touchRadiusRatio" format="float" /> <!-- 0.5 = 正圓,<0.5 為橢圓內切圓 -->
</declare-styleable>
// RoundButton.java
private float touchRadiusRatio = 0.5f;
public RoundButton(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundButton);
touchRadiusRatio = a.getFloat(R.styleable.RoundButton_touchRadiusRatio, 0.5f);
a.recycle();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float cx = getWidth() / 2f;
float cy = getHeight() / 2f;
float radius = Math.min(cx, cy) * touchRadiusRatio;
// ... 後續判斷同前
}
| 方案 | 缺點 |
|---|---|
只設置圓形背景 android:background | 點擊區域仍為矩形,四角空白處仍能觸發點擊 |
setTouchDelegate 擴大/縮小觸摸區域 | 只能矩形區域,無法實現圓形 |
覆寫 dispatchTouchEvent | 同 onTouchEvent,但更早攔截,易影響父佈局攔截邏輯 |
| 自定義 View 繪製 + 手動判斷 | 需自行實現文字、圖標、狀態(pressed/disabled)繪製,工作量大 |
shape=oval 背景,視覺與交互完美一致。幾行代碼,讓方形 Button 真正變身圓形點擊區域。