麻豆黑色丝袜jk制服福利网站-麻豆精品传媒视频观看-麻豆精品传媒一二三区在线视频-麻豆精选传媒4区2021-在线视频99-在线视频a

千鋒教育-做有情懷、有良心、有品質(zhì)的職業(yè)教育機(jī)構(gòu)

手機(jī)站
千鋒教育

千鋒學(xué)習(xí)站 | 隨時(shí)隨地免費(fèi)學(xué)

千鋒教育

掃一掃進(jìn)入千鋒手機(jī)站

領(lǐng)取全套視頻
千鋒教育

關(guān)注千鋒學(xué)習(xí)站小程序
隨時(shí)隨地免費(fèi)學(xué)習(xí)課程

當(dāng)前位置:首頁(yè)  >  技術(shù)干貨  > Flutter鍵盤(pán)頂起底部

Flutter鍵盤(pán)頂起底部

來(lái)源:千鋒教育
發(fā)布人:xqq
時(shí)間: 2023-11-23 00:46:24 1700671584

在Flutter中,打開(kāi)鍵盤(pán)后,我們可能希望底部的內(nèi)容不被覆蓋。Flutter提供了一些方法來(lái)實(shí)現(xiàn)這一點(diǎn)。下面將從多個(gè)方面詳細(xì)闡述如何使用Flutter實(shí)現(xiàn)鍵盤(pán)頂起底部的效果。

一、使用SingleChildScrollView

使用SingleChildScrollView可以讓底部?jī)?nèi)容在鍵盤(pán)彈出時(shí)自動(dòng)滾動(dòng)到可見(jiàn)區(qū)域。我們只需要將底部?jī)?nèi)容包裹在SingleChildScrollView中,并在頁(yè)面初始化時(shí)獲得一個(gè)GlobalKey,然后在鍵盤(pán)彈出后通過(guò)該GlobalKey定位到bottom widget的位置,再通過(guò)動(dòng)畫(huà)滾動(dòng)到該位置。

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State {
  final GlobalKey _bottomWidgetKey = GlobalKey();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: SingleChildScrollView(
        child: Column(
          children: [
            // other widgets
            Container(
              key: _bottomWidgetKey,
              child: // bottom widget
            ),
          ],
        ),
      ),
      appBar: AppBar(
        title: Text("Keyboard"),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // Show the keyboard
          FocusScope.of(context).requestFocus(FocusNode());
        },
        child: Icon(Icons.add),
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    final BottomWidgetRenderBox =
        _bottomWidgetKey.currentContext.findRenderObject() as RenderBox;
    SchedulerBinding.instance!.addPostFrameCallback((_) {
      Future.delayed(const Duration(milliseconds: 300)).then((_) {
        final RenderBox keyboard =
            context.findRenderObject() as RenderBox;
        final keyboardHeight = keyboard.size.height;
        final heightDiff =
            keyboardHeight - (MediaQuery.of(context).viewInsets.bottom);
        final double offsetY =
            heightDiff > 0 ? -(BottomWidgetRenderBox.size.height + heightDiff) : 0;
        if (offsetY != 0) {
          _controller.animateTo(
              _controller.offset + offsetY,
              duration: new Duration(milliseconds: 300),
              curve: Curves.easeOut);
        }
      });
    });
  }
}

二、使用ListView

如果你希望底部?jī)?nèi)容可以滾動(dòng),我們可以使用ListView。ListView將自動(dòng)在鍵盤(pán)彈出時(shí)滾動(dòng)到底部,并且可以讓用戶滾動(dòng)以查看所有內(nèi)容。

class MyWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Expanded(
            child: ListView(
              children: [
                // other widgets
                // bottom widget
              ],
            ),
          ),
          // input widget
        ],
      ),
      appBar: AppBar(
        title: Text("ListView"),
      ),
    );
  }
}

三、使用Stack和AnimatedPositioned

使用Stack和AnimatedPositioned可以在鍵盤(pán)彈出時(shí)自動(dòng)調(diào)整底部?jī)?nèi)容的位置,使其不被鍵盤(pán)遮擋。我們可以將輸入框作為Stack的子元素,然后將底部?jī)?nèi)容作為Stack的第二個(gè)子元素。在鍵盤(pán)彈出時(shí),我們可以使用AnimatedPositioned調(diào)整第二個(gè)子元素的位置。

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State {
  GlobalKey _globalKey = GlobalKey();

  double _bottom = 0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: Text("Stack and AnimatedPositioned"),
      ),
      body: Stack(
        children: [
          Positioned(
            top: 0,
            bottom: 0,
            left: 0,
            right: 0,
            child: GestureDetector(
              onTap: () => FocusScope.of(context).requestFocus(FocusNode()),
              child: Container(
                color: Colors.white,
                child: SingleChildScrollView(
                  child: Column(
                    key: _globalKey,
                    children: [
                      // other widgets
                      Container(
                        height: 800,
                      ),
                    ],
                  ),
                ),
              ),
            ),
          ),
          AnimatedPositioned(
            duration: Duration(milliseconds: 300),
            bottom: _bottom,
            left: 0,
            right: 0,
            child: Container(
              color: Colors.lightBlue,
              height: 140,
              child: Center(
                child: GestureDetector(
                  onTap: () {
                    FocusScope.of(context).requestFocus(FocusNode());
                  },
                  child: Text(
                    "Input",
                    style: TextStyle(
                      fontSize: 30,
                      color: Colors.white,
                    ),
                  ),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    final RenderBox renderBoxRed = _globalKey.currentContext.findRenderObject() as RenderBox;
    WidgetsBinding.instance!.addPostFrameCallback((_) {
      double height = renderBoxRed.size.height;
      double screenHeight = MediaQuery.of(context).size.height;
      double diff = screenHeight - height;
      setState(() {
        _bottom = diff;
      });
    });
  }
}

四、結(jié)合SingleChildScrollView和Stack

我們也可以結(jié)合ScrollView和Stack來(lái)實(shí)現(xiàn)鍵盤(pán)頂起底部的效果。具體操作是將輸入框與底部?jī)?nèi)容放置在Stack中,并將Stack放置在SingleChildScrollView中。當(dāng)鍵盤(pán)彈出時(shí),可以與第一種方法類似地通過(guò)AnimationController將底部?jī)?nèi)容滑動(dòng)到屏幕中央。

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State
    with SingleTickerProviderStateMixin {
  double _offset = 0.0;

  bool _isKeyboardShowing = false;

  late final AnimationController _controller = AnimationController(
      duration: const Duration(milliseconds: 200), vsync: this);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: Text("Stack and SingleChildScrollView"),
      ),
      body: SingleChildScrollView(
        child: Stack(
          children: [
            Column(
              children: [
                Container(
                  height: 800,
                ),
              ],
            ),
            Positioned(
              bottom: _offset,
              left: 0,
              right: 0,
              child: Container(
                color: Colors.lightBlue,
                height: 140,
                child: Center(
                  child: GestureDetector(
                    onTap: () {
                      FocusScope.of(context).requestFocus(FocusNode());
                    },
                    child: Text(
                      "Input",
                      style: TextStyle(
                        fontSize: 30,
                        color: Colors.white,
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  void initState() {
    super.initState();
    _controller.addListener(() {
      setState(() {
        _offset =
            MediaQuery.of(context).viewInsets.bottom * _controller.value;
      });
    });
    _controller.addStatusListener((status) {
      if (status == AnimationStatus.completed) {
        setState(() {
          _isKeyboardShowing = true;
        });
      } else if (status == AnimationStatus.dismissed) {
        setState(() {
          _isKeyboardShowing = false;
        });
      }
    });
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        title: Text("Stack and SingleChildScrollView"),
      ),
      body: SingleChildScrollView(
        child: Stack(
          children: [
            Column(
              children: [
                Container(
                  height: 800,
                ),
                GestureDetector(
                  onTap: () {
                    FocusScope.of(context).requestFocus(FocusNode());
                  }
                  child: // input widget
                ),
              ],
            ),
            Positioned(
              bottom: _offset,
              left: 0,
              right: 0,
              child: Container(
                color: Colors.lightBlue,
                height: 140,
                child: Center(
                  child: GestureDetector(
                    onTap: () {
                      FocusScope.of(context).requestFocus(FocusNode());
                    },
                    child: Text(
                      "Input",
                      style: TextStyle(
                        fontSize: 30,
                        color: Colors.white,
                      ),
                    ),
                  ),
                ),
              ),
            )
          ],
        ),
      ),
    );
  }

  void _handleFocusChange() {
    if (FocusScope.of(context).hasFocus != _isKeyboardShowing) {
      _isKeyboardShowing = FocusScope.of(context).hasFocus;
      _controller.animateTo(
          _isKeyboardShowing ? 1.0 : 0.0,
          duration: const Duration(milliseconds: 150),
          curve: Curves.linear);
    }
  }
}

五、小結(jié)

本文介紹了Flutter中實(shí)現(xiàn)鍵盤(pán)頂起底部的幾種方法,包括使用SingleChildScrollView、ListView、Stack以及結(jié)合方法。在使用這些方法時(shí),我們需要考慮底部?jī)?nèi)容的特殊結(jié)構(gòu),確保鍵盤(pán)彈出時(shí),底部?jī)?nèi)容不會(huì)被遮擋。希望本文能對(duì)您在Flutter開(kāi)發(fā)中實(shí)現(xiàn)鍵盤(pán)頂起底部的需求提供幫助。

聲明:本站稿件版權(quán)均屬千鋒教育所有,未經(jīng)許可不得擅自轉(zhuǎn)載。
10年以上業(yè)內(nèi)強(qiáng)師集結(jié),手把手帶你蛻變精英
請(qǐng)您保持通訊暢通,專屬學(xué)習(xí)老師24小時(shí)內(nèi)將與您1V1溝通
免費(fèi)領(lǐng)取
今日已有369人領(lǐng)取成功
劉同學(xué) 138****2860 剛剛成功領(lǐng)取
王同學(xué) 131****2015 剛剛成功領(lǐng)取
張同學(xué) 133****4652 剛剛成功領(lǐng)取
李同學(xué) 135****8607 剛剛成功領(lǐng)取
楊同學(xué) 132****5667 剛剛成功領(lǐng)取
岳同學(xué) 134****6652 剛剛成功領(lǐng)取
梁同學(xué) 157****2950 剛剛成功領(lǐng)取
劉同學(xué) 189****1015 剛剛成功領(lǐng)取
張同學(xué) 155****4678 剛剛成功領(lǐng)取
鄒同學(xué) 139****2907 剛剛成功領(lǐng)取
董同學(xué) 138****2867 剛剛成功領(lǐng)取
周同學(xué) 136****3602 剛剛成功領(lǐng)取
相關(guān)推薦HOT
Pingfangsc字體詳解

一、字體描述Pingfangsc字體是一種被廣泛用于中文設(shè)計(jì)領(lǐng)域的字體,其正式名稱為蘋(píng)方-簡(jiǎn),是由蘋(píng)果公司與微軟公司共同開(kāi)發(fā)的,用于替代傳統(tǒng)的中...詳情>>

2023-11-23 02:38:00
linux gbd調(diào)試,linuxadb調(diào)試

adb工具linux好不好1、LinuxADB更穩(wěn)定。Linux是Android開(kāi)發(fā)的主要平臺(tái)之一,ADB的開(kāi)發(fā)和測(cè)試也更多地針對(duì)Linux環(huán)境,Linux上的ADB在穩(wěn)定性方面...詳情>>

2023-11-23 02:32:09
npm設(shè)置代理的方法用法介紹

一、什么是npm代理npm代理指的是npm包管理器在使用時(shí)通過(guò)代理訪問(wèn)npm服務(wù)器獲取依賴包的過(guò)程。在某些情況下,我們需要npm走代理才能訪問(wèn)到npm服...詳情>>

2023-11-23 02:23:36
在Ubuntu上安裝中文字體

在Ubuntu系統(tǒng)中安裝中文字體是很必要的,因?yàn)橹形沫h(huán)境下如果沒(méi)有合適的字體,會(huì)導(dǎo)致顯示效果非常差。下面我們將從以下幾個(gè)方面來(lái)闡述在Ubuntu上...詳情>>

2023-11-23 02:12:48
interval1day詳解

一、interval1day的概念和用途interval1day是一個(gè)時(shí)間間隔,表示每天的時(shí)間段。在編程中,我們可以使用interval1day來(lái)表示每天的某些觸發(fā)事件,...詳情>>

2023-11-23 01:29:36
主站蜘蛛池模板: 尾野真知子日韩专区在线| 欧美xxxx做受性欧美88| 国产欧美精品一区二区三区-老狼| 全彩口工彩漫画无遮漫画| 精品国产日韩亚洲一区| 性欧美18-19sex性高清播放| 又粗又大又爽又长又紧又水| 国产三区视频| aaa一级黄色片| 国产色a在线观看| 欧美激情一区二区三区| 国产激情久久久久影院小草| 日b片| 午夜爽爽爽视频| 嗯啊公交车上被群j| 日本一道在线日本一道高清不卡免费| 亚洲欧美另类日韩| 久久九色综合九色99伊人| 无翼乌漫画全彩| 被女同桌调教成鞋袜奴脚奴| 欧美性猛交xxxx乱大交蜜桃| 国内一级纶理片免费| 欧美特黄视频在线观看| 国产三级免费电影| 男女无遮挡高清性视频直播| 日韩成人午夜| 999国产精品999久久久久久| 亚洲欧美一区二区三区电影| 最近中文字幕国语免费完整| 第一福利官方导航| 在线免费观看你懂的| 高清视频一区二区三区| 波多野结衣女教师在线观看| 天天av天天翘天天综合网| 奇米视频7777| 日本三级hd| 巨粗黑吊| 兽皇videos极品另类| 欧美xxxx三人交性视频| 天天舔天天操天天干| 1卡二卡三卡四卡精品|