最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Flutter自定義實現(xiàn)彈出層的示例代碼

 更新時間:2023年08月30日 08:22:54   作者:程序員一鳴  
這篇文章主要為大家詳細介紹了Flutter如何自定義組件實現(xiàn)彈出層的效果,?文中的示例代碼講解詳細,感興趣的小伙伴可以跟隨小編一起學習一下

背景

最近要使用Flutter實現(xiàn)一個下拉菜單,需求就是,在當前組件下點擊,其下方彈出一個菜單選項,如下圖所示:

實現(xiàn)起來,貌似沒什么障礙,在Flutter中本身就提供了彈出層PopupMenuButton組件和showMenu方法,于是開搞,代碼如下:

PopupMenuButton<String>(
      initialValue: '下拉菜單一',
      child: const Text("下拉菜單"),
      itemBuilder: (context) {
        return <PopupMenuEntry<String>>[
          const PopupMenuItem<String>(
            value: '下拉菜單一',
            child: Text('下拉菜單一'),
          ),
          const PopupMenuItem<String>(
            value: '下拉菜單二',
            child: Text('下拉菜單二'),
          ),
          const PopupMenuItem<String>(
            value: '下拉菜單三',
            child: Text('下拉菜單三'),
          )
        ];
      },
    )

直接使用showMenu也行,代碼如下:

 showMenu(
            context: context,
            position: const RelativeRect.fromLTRB(0, 0, 0, 0),
            items: <PopupMenuEntry>[
              const PopupMenuItem(value: "下拉菜單一",child: Text("下拉菜單一"),),
              const PopupMenuItem(value: "下拉菜單二",child: Text("下拉菜單二"),),
              const PopupMenuItem(value: "下拉菜單三",child: Text("下拉菜單三"),),
            ]);

PopupMenuButton運行看結果:

showMenu位置傳的是左上角,這個就不貼圖了。

看到效果后,我詫異了,這也不符合我的需求啊,直接把選項給我蓋住了,這還得了,況且位置也不對啊,怎么搞?還好,無論使用PopupMenuButton還是showMenu,都給我們提供了位置。

PopupMenuButton設置位置:

offset: Offset(dx, dy)

showMenu設置位置:

 position: const RelativeRect.fromLTRB(left, top, right, bottom)

使用位置后,我們再看效果:

dx設置為0,dy設置為50:

PopupMenuButton<String>(
      initialValue: '下拉菜單一',
      offset: const Offset(0, 50),
      itemBuilder: (context) {
        return <PopupMenuEntry<String>>[
          const PopupMenuItem<String>(
            value: '下拉菜單一',
            child: Text('下拉菜單一'),
          ),
          const PopupMenuItem<String>(
            value: '下拉菜單二',
            child: Text('下拉菜單二'),
          ),
          const PopupMenuItem<String>(
            value: '下拉菜單三',
            child: Text('下拉菜單三'),
          )
        ];
      },
      child: Text(
        "下拉菜單",
        key: _key,
      ),
    )

效果如下圖:

這樣看起來確實好多了,但是我的疑問就來了,如果我想實現(xiàn)在左邊展示呢?在上邊、右邊,甚至左上右上,左下右下呢?通過坐標計算,確實能實現(xiàn),但是計算起來麻煩,也不精確,很難作為上上策,再者,這種彈窗方式樣式,在實際開發(fā)中也很難滿足我們的需求。

既然原生的組件無法滿足我們的需求,怎么搞?只有自定義一個組件了。

今天的內(nèi)容大致如下:

1、自定義彈出層效果一覽

2、彈出層邏輯實現(xiàn)

3、使用注意事項

4、源碼

一、自定義彈出層效果一覽

目前自定義的組件,可以在目標組件,左、上、右、下,左上、右上,左下、右下八個方向進行精確的彈出,當然了,除此之外,也可以動態(tài)的展示到自己想要的位置,并且彈出層效果可以自定義,效果是我彈出了一個黑色矩形,你可以彈出一個列表,一個圖片等等。

二、彈出層邏輯實現(xiàn)

1、懸浮在其他頂部小部件之上

為了更好的展示彈出效果,和不影響UI層的相關邏輯,針對彈出層,我們可以懸浮在內(nèi)容層之上,做透明處理即可,這里使用到了Overlay對象,它是一個類似懸浮小彈窗,如Toast,安卓的PopupWindow效果。

相關代碼如下,創(chuàng)建OverlayEntry,并插入到Overlay中,這樣就可以把OverlayEntry中構建的小部件疊加懸浮在其他頂部小部件之上。

  OverlayState overlayState = Overlay.of(key.currentContext!);
	OverlayEntry _overlayEntry = OverlayEntry();
	overlayState.insert(_overlayEntry!);

2、獲取彈出目標組件的左上右下

所謂目標組件,就是,你想要在哪個組件(左上右下)進行彈出,確定了目標組件之后,為了使彈出層,精確的展示在目標組件的方位,需要拿到目標組件的位置,也就是左上右下的位置,這里使用到了GlobalKey作為獲取方式,具體的位置信息獲取如下:

///獲取組件的位置
  static WidgetSize getWidgetSize(GlobalKey key) {
    //獲取組件的位置,在左上右下
    final RenderBox renderBox =
        (key.currentContext?.findRenderObject() as RenderBox);
    final left = renderBox.localToGlobal(Offset.zero).dx; //左邊
    final top = renderBox.localToGlobal(Offset(renderBox.size.width, 0)).dy;
    final bottom = renderBox.localToGlobal(Offset(0, renderBox.size.height)).dy;
    final right = renderBox
        .localToGlobal(Offset(renderBox.size.width, renderBox.size.height))
        .dx;
    return WidgetSize(left, top, right, bottom);
  }

創(chuàng)建記錄位置對象,用來標記左上右下。

///組件對象,標記左上右下
class WidgetSize {
  double left;
  double top;
  double right;
  double bottom;
  WidgetSize(this.left, this.top, this.right, this.bottom);
}

3、設置彈出層的位置

彈出層位置,這里利用到了Positioned組件,控制其left和top位置,基本上和PopupMenuButton類似,無非就是自己實現(xiàn)了位置的測量而已。

首先根據(jù)傳遞的屬性WindowDirection,確定要設置的方位。

具體各個方位計算如下:

目標組件下邊:

top坐標:目標組件的底部坐標+邊距

left坐標:目標組件的右部坐標-彈出層的寬度/2-目標組件寬度/2

目標組件左邊:

top坐標:目標組件的底部坐標-彈出層的高度/2-目標組件的高度/2

left坐標:目標組件的左邊坐標-彈出層的寬度-邊距

目標組件上邊:

top坐標:目標組件的上邊坐標-彈出層的高度-邊距

left坐標:目標組件的右部坐標-彈出層的寬度/2-目標組件寬度/2

目標組件右邊:

top坐標:目標組件的底部坐標-彈出層的高度/2-目標組件的高度/2

left坐標:目標組件的右邊坐標+邊距

目標組件左上:

top坐標:目標組件的底部坐標-彈出層的高度-目標組件的高度-邊距

left坐標:目標組件的左邊坐標-彈出層的寬度-邊距

目標組件右上:

top坐標:目標組件的底部坐標-彈出層的高度-目標組件的高度-邊距

left坐標:目標組件的左邊坐標+邊距

目標組件左下:

top坐標:目標組件的底部坐標+邊距

left坐標:目標組件的左邊坐標-彈出層的寬度-邊距

目標組件右下:

top坐標:目標組件+邊距

left坐標:目標組件右邊的坐標+邊距

var size = getWidgetSize(key); //獲取在目標組件的位置
    double widgetTop = 0.0;
    double widgetLeft = 0.0;
    switch (direction) {
      case WindowDirection.bottom: //下面
        widgetTop = size.bottom + margin;
        widgetLeft =
            size.right - childWidth / 2 - ((size.right - size.left) / 2);
        break;
      case WindowDirection.left: //左面
        widgetTop =
            size.bottom - childHeight / 2 - ((size.bottom - size.top) / 2);
        widgetLeft = size.left - childWidth - margin;
        break;
      case WindowDirection.top: //上面
        widgetTop = size.top - childHeight - margin;
        widgetLeft =
            size.right - childWidth / 2 - ((size.right - size.left) / 2);
        break;
      case WindowDirection.right: //右面
        widgetTop =
            size.bottom - childHeight / 2 - ((size.bottom - size.top) / 2);
        widgetLeft = size.right + margin;
        break;
      case WindowDirection.topLeft: //左上
        widgetTop =
            size.bottom - childHeight - (size.bottom - size.top) - margin;
        widgetLeft = size.left - childWidth - margin;
        break;
      case WindowDirection.topRight: //右上
        widgetTop =
            size.bottom - childHeight - (size.bottom - size.top) - margin;
        widgetLeft = size.right + margin;
        break;
      case WindowDirection.bottomLeft: //左下
        widgetTop = size.bottom + margin;
        widgetLeft = size.left - childWidth - margin;
        break;
      case WindowDirection.bottomRight: //右下
        widgetTop = size.bottom + margin;
        widgetLeft = size.right + margin;
        break;
      case WindowDirection.none: //取消 自己測量位置
        widgetTop = top;
        widgetLeft = left;
        break;
    }

三、使用注意事項

1、為了能夠精確的設置彈出層的位置,其彈出層的寬度和高度是必須要傳遞的,也就是childWidth和childHeight屬性。

2、如果想自己設置位置,可以不傳childWidth和childHeight,設置direction為WindowDirection.none,并且left和top坐標需要傳遞。

3、margin屬性設置彈出層距離目標組件的距離。

四、源碼

源碼地址

github.com/AbnerMing888/flutter_widget/blob/master/lib/utils/popup_window.dart

使用方式

PopupWindow.create(
              _key,
              const BaseWidget(
                width: 100,
                height: 100,
                backgroundColor: Colors.black,
              ),
              direction: direction,
              margin: 10,
              childWidth: 100,
              childHeight: 100);

參數(shù)介紹

屬性類型概述
keyGlobalKey目標組件的key
childWidget彈出層
childWidthdouble彈出層的寬
childHeightdouble彈出層的高
directionWindowDirection位置:left//左top//上right//右bottom//下topLeft, //左上角topRight, //右上角bottomLeft, //左下bottomRight, //右下none//取消位置,自己定義
leftdouble相對于屏幕的左側坐標
topdouble相對于屏幕的頂部坐標
margindouble彈出層距離目標組件的距離

到此這篇關于Flutter自定義實現(xiàn)彈出層的示例代碼的文章就介紹到這了,更多相關Flutter彈出層內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • Android之自定義實現(xiàn)BaseAdapter(通用適配器三)

    Android之自定義實現(xiàn)BaseAdapter(通用適配器三)

    這篇文章主要為大家詳細介紹了Android之自定義實現(xiàn)BaseAdapter通用適配器第三篇,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-12-12
  • Android基于Sensor感應器獲取重力感應加速度的方法

    Android基于Sensor感應器獲取重力感應加速度的方法

    這篇文章主要介紹了Android基于Sensor感應器獲取重力感應加速度的方法,涉及Android使用Sensor類實現(xiàn)感應重力變化的功能,需要的朋友可以參考下
    2015-12-12
  • Kotlin Job啟動流程源碼層深入分析

    Kotlin Job啟動流程源碼層深入分析

    如果要我拿現(xiàn)實中的一事物與Kotlin協(xié)程中的Job做一個類比,那么我會把Job比作成海洋中的冰山。自由漂浮的冰山約有90%體積沉在海水表面下,因此看著浮在水面上的形狀并猜不出水下的形狀
    2022-11-11
  • Android實現(xiàn)3D翻轉動畫效果

    Android實現(xiàn)3D翻轉動畫效果

    這篇文章主要為大家詳細介紹了Android實現(xiàn)3D翻轉動畫效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-12-12
  • Android 改變圖標原有顏色和搜索框的實例代碼

    Android 改變圖標原有顏色和搜索框的實例代碼

    讓Android也能有iOS那么方便的圖片色調(diào)轉換,就像同一個圖標,但是有多個地方使用,并且顏色不一樣,就可以用這個方法了。 本文實現(xiàn)TextView圖片和文字居中,鍵盤搜索功能,具體實現(xiàn)代碼大家跟隨腳本之家小編看看吧
    2017-09-09
  • Android高亮引導控件的實現(xiàn)代碼

    Android高亮引導控件的實現(xiàn)代碼

    這篇文章主要介紹了Android高亮引導控件的實現(xiàn)代碼,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-07-07
  • Android點擊Button實現(xiàn)功能的幾種方法總結

    Android點擊Button實現(xiàn)功能的幾種方法總結

    當Button有多個或者Button的使用次數(shù)很多時,我們需要采用綁定監(jiān)聽器的做法,其實,綁定監(jiān)聽器也有幾種方法,不過,我在這里就不一一列舉了,畢竟那些方法在實際的應用中也不常見
    2013-10-10
  • Android中TabLayout結合ViewPager實現(xiàn)頁面切換

    Android中TabLayout結合ViewPager實現(xiàn)頁面切換

    這篇文章主要為大家詳細介紹了Android中TabLayout結合ViewPager實現(xiàn)頁面切換效果,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android Studio導入jar包過程詳解

    Android Studio導入jar包過程詳解

    這篇文章主要介紹了Android Studio導入jar包過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-11-11
  • flutter 中監(jiān)聽滑動事件

    flutter 中監(jiān)聽滑動事件

    這篇文章主要介紹了flutter 中監(jiān)聽滑動事件,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-11-11

最新評論

上杭县| 翼城县| 富裕县| 隆安县| 普洱| 罗定市| 临泽县| 鄯善县| 沁水县| 汉源县| 当涂县| 金堂县| 孝感市| 上饶市| 克什克腾旗| 连山| 两当县| 桐庐县| 凌云县| 六安市| 江北区| 平定县| 莒南县| 四平市| 响水县| 红河县| 嵊泗县| 石屏县| 龙里县| 张家港市| 丁青县| 永吉县| 五莲县| 闽清县| 十堰市| 庆阳市| 朔州市| 昌江| 哈巴河县| 新田县| 临夏市|