Flutter實戰之手勢基礎篇

前言

平常開發應用中少不了交互功能,而交互就包括了點擊觸碰。好比點擊一個按鈕對操做作出響應又或者是拖拽列表作下拉刷新操做等一些常規交互的實現離不開手勢功能。那麼在Flutter中是如何實現經過手勢操做實現交互操做的,下面就來介紹一下Flutter手勢功能。app

手勢(GestureDetector)

Flutter經過使用GestureDetector組件使得其餘Widget支持手勢功能。手勢能夠響應多種操做,主要分爲如下幾類:Tap、Double tap、Long press、Vertical drag、Horizontal drag、Pan。同時能夠經過動做分爲點擊、雙擊、長按、拖拽、縮放等。學習

點擊(Tap)& 雙擊(DoubleTap)& 長按(LongPress)

通用的操做方法,例如點擊、雙擊、長按功能,只須要編寫Function就能實現功能。固然在這些操做過程當中也具有中間過程的狀態監聽,例如點擊按下時,擡起時,取消點擊等。 動畫

GestureDetector(
  onTap: (){
    showSnack(context, "OnTap");
  },
  onDoubleTap: (){
    showSnack(context, "onDoubleTap");
  },
  onLongPress: (){
    showSnack(context, "onLongPress");
  },
  child: Transform.translate(
    offset: offset,
    child: Text(
      "Transform",
      style: TextStyle(fontSize: 25),
    ),
  ),
);
複製代碼

拖拽(Drag)

GestureDetector爲拖拽功能提供水平方向拖拽(Horizontal drag)、垂直方向拖拽(Vertical drag)、同時支持兩個方向拖拽(Pan)。 ui

水平和垂直兩個拖拽監聽只能獲取對應方向偏移量變化,對應的垂直方向的數值返回始終爲0,若在開發需求中若同時須要監聽兩個方向則推薦使用綜合拖拽監聽回調Pan同時監聽水平和垂直方向的偏移量的變化。

在監聽中Down、Start、Update三個過程能夠監聽到Details對象,從而知道當前手勢定位值對於組件頂點位置的偏移量。spa

偏移量

在GestureDetector中兩個重要屬性值globalPosition和localPosition,二者都是Offset對象。globalPosition就像它的命名錶示當前手勢觸點在全局座標系位置與對應組件頂點座標的偏移量(dx,dy),而localPosition則就表示當前手勢觸點在對應組件座標系位置與對應組件頂點座標的偏移量(dx,dy)也就是說若是當前手勢位置在組件頂點座標那麼dx和dy都爲0。指針

例如以下代碼中,爲Container設置了GestureDetector手勢監聽,在update回調中獲取updateDetail對象,在Text中顯示globalPosition偏移量。從中獲取到的globalPosition和localPosition中dx都是相同值,dy卻不一樣。也就是由於Scaffold中設置了AppBar,相對於body他的全局座標系並不是它自身。但若將Scaffold中的AppBar去除,讓body撐滿整個Scaffold,那麼在手勢監聽中獲取到的globalPosition和localPosition將相同。code

須要注意的是對於globalPosition在安卓中還包含了手機狀態欄的高度。orm

MaterialApp(
      theme: AppTheme.themes[store.state.appThemeState.themeType],
      home: Scaffold(
        appBar: AppBar(),
        body: GestureDetector(
          onPanStart: (detail) {
            showLog(detail.runtimeType, detail.localPosition,
                detail.globalPosition);
          },
          onPanUpdate: (detail) {
            showLog(detail.runtimeType, detail.localPosition,
                detail.globalPosition);
            setState(() {
              offsetText = "globalPosition: ${Offset(detail.globalPosition.dx, detail.globalPosition.dy).toString()} \n"
                  "localPosition: ${Offset(detail.localPosition.dx, detail.localPosition.dy).toString()}";
            });
          },
          onPanEnd: (detail) {
            setState(() {
              offsetText = "end";
            });
          },
          child: Container(
            color: Colors.red,
            width: double.infinity,
            height: double.infinity,
            child: Center(
              child: Text(
                 offsetText,
                style: TextStyle(
                  color: Colors.white,
                  fontSize: 25,
                ),
              ),
            ),
          ),
        ),
      ),
    );
複製代碼

能夠看到當Scaffold包含和未包含AppBar時,Container兩個偏移量輸出的差別。cdn

縮放(Scale)

縮放操做則須要兩個指針對象配合才能發揮做用。當在屏幕上只有一個指針對象時也就是一個觸點時,對應的縮放比爲1和角度爲0;當屏幕上出現兩個指針對象時,根據兩個初始位置做爲基準點,也就是起始位置初始化縮放比爲1和角度爲0,經過手勢變化得出兩點的距離位置和夾角大小來計算縮放比和角度值。對象

GestureDetector(
          onScaleStart: (detail) {
            print(detail);
            setState(() {
              offsetText = "focalPoint: ${detail.focalPoint.toString()} \n"
                  "localFocalPoint: ${detail.localFocalPoint.toString()}";
            });
          },
          onScaleUpdate: (details) {
            print(details);
            Vector.Matrix3 matrix3 = Vector.Matrix3.zero();
            setState(() {
              offsetText = "focalPoint: ${details.focalPoint.toString()} \n"
                  "localFocalPoint: ${details.localFocalPoint.toString()}";
              scaleUpdateDetails = details;
            });
          },
          onScaleEnd: (details) {
            print(details);
            setState(() {
              scaleUpdateDetails = ScaleUpdateDetails();
            });
          },
          child: Container(
            color: Colors.red,
            width: double.infinity,
            height: double.infinity,
            child: Center(
                // 組件的動畫效果
              child: Transform(
                transform: Matrix4.rotationZ(scaleUpdateDetails.rotation)
                    .scaled(
                        scaleUpdateDetails.scale),
                child: Text(
                  offsetText,
                  style: TextStyle(
                    color: Colors.white,
                    fontSize: 20,
                  ),
                ),
              ),
            ),
          ),
        ),
複製代碼

在onScaleUpdate方法中獲取ScaleUpdateDetails對象,其包含了兩觸點實現的縮放值scale、角度值rotation、偏移量focalPoint信息。經過上述代碼並可實現手勢再結合上Transform的組件動效,關於Transform不作過多介紹,主要爲實現組件動畫效果的組件,以後如有時間再作學習。

結尾

這篇只能算是手勢功能基礎篇,還有一些手勢高階功能實現未探究相似於Android中的手勢衝突等一些功能性自定義開發,暫且先熟悉手勢基本功能以後如有對這方面開發需求再作更深層次學習和研究。

相關文章
相關標籤/搜索