Flutter 中 GestureDetector 的使用誤區

蕭文翰發表於2020-06-09

在實際開發中,我們通常需要實現某個元件的更多點選事件。比如:原生的RaisedButton元件是無法響應諸如拖拽或是按下、抬起等細化的動作,它只有一個onPressed()方法來表示。當我們想實現這些細化事件時,通常使用的元件是GestureDetector。
我們先來看下面這段程式碼:

GestureDetector(
    onTap: () {
        debugPrint("RaisedButton點選阻斷");
    },
    child: RaisedButton(
    child: Text("點我試試"),
    onPressed: () {
        debugPrint("我被點選了");
    })
)
複製程式碼

各位覺得這端程式碼的執行結果,當RaisedButton被點選時,控制檯將如何輸出呢?
再看下面這段程式碼:

GestureDetector(
	behavior: HitTestBehavior.opaque,
    onTap: () {
        debugPrint("RaisedButton點選阻斷");
    },
    child: RaisedButton(
    child: Text("點我試試"),
    onPressed: () {
        debugPrint("我被點選了");
    })
)
複製程式碼

和上面的問題一樣,當RaisedButton被點選時,控制檯將輸出什麼內容呢?
答案無一例外地,都輸出:

我被點選了
複製程式碼

可以看到,單純地使用GestureDetector並不能將子元件的點選事件阻斷,即使新增了behavior,也無能為力。
所以,我們得到結論:當子元件可響應點選事件時,GestureDetector是不能阻斷子元件響應點選事件的
那麼,如果我們想阻斷子元件對點選事件的響應,該怎麼辦呢?
正確的做法是:使用AbsorbPointer元件
我們來看下面這段程式碼:

AbsorbPointer(
    child: RaisedButton(
    child: Text("點我試試"),
    onPressed: () {
        debugPrint("我被點選了");
    })
)
複製程式碼

再次點選RaisedButton,控制檯將不輸出任何內容。
那麼?如何讓GestureDetector可以作用在RaisedButton上呢?很簡單,只需要將RaisedButton變為不可響應點選事件就可以了,其他控制元件同理。實現程式碼如下:

GestureDetector(
    behavior: HitTestBehavior.opaque,
    onTap: () {
        debugPrint("RaisedButton點選阻斷");
    },
    child: AbsorbPointer(
        child: RaisedButton(
        child: Text("點我試試"),
            onPressed: () {
                debugPrint("我被點選了");
            }
        )
    )
)
複製程式碼

再次點選RaisedButton,控制檯將輸出:

RaisedButton點選阻斷
複製程式碼

當然,如此一來,原有的按鈕點選動畫也會失效。

相關文章