黄视频网站在线免费观看-黄视频网站在线看-黄视频网站在线观看-黄视频网站免费看-黄视频网站免费观看-黄视频网站免费

千鋒教育-做有情懷、有良心、有品質(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í),可以與第一種方法類(lèi)似地通過(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)您保持通訊暢通,專(zhuān)屬學(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
欧美夜夜骑 青草视频在线观看完整版 久久精品99无色码中文字幕 欧美日韩一区二区在线观看视频 欧美中文字幕在线视频 www.99精品 香蕉视频久久 | 色综合久久天天综合绕观看| 国产麻豆精品高清在线播放| 中文字幕一区二区三区精彩视频| 可以免费看污视频的网站| 欧美激情一区二区三区在线| 精品久久久久久综合网| a级黄色毛片免费播放视频| 99久久精品国产片| 国产一区二区精品久| 午夜在线影院| 欧美激情一区二区三区在线播放| 国产成人精品综合| 国产美女在线观看| 国产视频一区二区在线观看| 九九干| 久久精品欧美一区二区| 国产视频一区二区在线播放| 成人高清免费| 九九干| 四虎影视库| 国产精品免费久久| 午夜欧美成人久久久久久| 欧美国产日韩精品| 亚洲精品中文一区不卡| 国产视频一区二区在线观看| 亚洲 欧美 成人日韩| 超级乱淫伦动漫| 日本伦理黄色大片在线观看网站| 美女免费精品高清毛片在线视| 日韩女人做爰大片| 国产激情一区二区三区| 精品视频免费观看| 国产成人精品综合在线| 一本伊大人香蕉高清在线观看| 青青久久精品| 国产精品1024在线永久免费| 久草免费在线色站| 亚洲 欧美 成人日韩| 欧美激情一区二区三区视频 | 日韩在线观看网站| 中文字幕97| 黄色短视屏| 国产视频久久久| 韩国三级一区| 午夜在线亚洲| 欧美一级视| 亚洲第一页乱| 国产国语在线播放视频| 四虎影视久久久| 美女被草网站| 国产a免费观看| 亚洲精品影院一区二区| 久久精品免视看国产成人2021| 欧美1区| 精品视频在线看| 国产亚洲精品aaa大片| 欧美大片aaaa一级毛片| 亚欧视频在线| 国产91精品系列在线观看| 国产精品自拍在线| 国产一区二区精品在线观看| 美女免费精品高清毛片在线视| 国产a视频| 精品视频免费观看| 国产成人精品综合久久久| 国产不卡在线观看视频| 国产精品12| 免费国产在线视频| 日日日夜夜操| 91麻豆精品国产片在线观看| 黄色免费三级| 午夜在线影院| 国产a一级| 久久精品欧美一区二区| 国产一区免费观看| 久久成人综合网| 精品毛片视频| 国产成人欧美一区二区三区的| 国产精品自拍在线| 国产极品精频在线观看| 四虎久久精品国产| 国产网站免费| 欧美激情一区二区三区视频| 国产成人啪精品| 欧美日本免费| 久草免费在线色站| 九九干| 国产伦精品一区二区三区无广告| 欧美激情一区二区三区在线| 亚洲天堂在线播放| 欧美激情一区二区三区视频 | 二级片在线观看| 国产成人精品综合久久久| 欧美爱爱动态| 日韩中文字幕在线观看视频| 你懂的日韩| 91麻豆国产| 91麻豆精品国产综合久久久| 精品久久久久久免费影院| 国产成a人片在线观看视频| 韩国三级视频网站| 成人免费福利片在线观看| 久草免费在线观看| 尤物视频网站在线| 毛片高清| 午夜精品国产自在现线拍| 日本免费看视频| 久久99中文字幕| 日韩在线观看视频网站| 午夜欧美成人久久久久久| 成人a级高清视频在线观看| 国产麻豆精品免费密入口| 日韩男人天堂| 国产网站免费| 国产精品1024在线永久免费| 欧美a免费| 韩国三级一区| a级毛片免费观看网站| 天天色成人| 日韩在线观看视频网站| 国产一区二区精品久| 精品视频一区二区三区免费| 沈樵在线观看福利| 韩国毛片| 国产网站免费视频| 高清一级做a爱过程不卡视频| 日韩女人做爰大片| 国产91精品系列在线观看| 久久精品店| 精品国产一区二区三区国产馆| 欧美激情一区二区三区在线播放| 亚洲 激情| 美女免费精品视频在线观看| 四虎久久影院| 国产伦久视频免费观看视频| 精品国产一区二区三区免费| 亚洲第一页乱| a级毛片免费观看网站| 97视频免费在线观看| 亚洲精品中文一区不卡| 亚洲精品中文字幕久久久久久| 成人高清免费| 国产不卡精品一区二区三区| 久草免费在线色站| 青青久久精品| 国产精品免费久久| 欧美电影免费| 精品在线观看一区| 国产原创视频在线| 色综合久久天天综合观看| 九九精品久久久久久久久| 国产欧美精品午夜在线播放| 日日爽天天| 香蕉视频亚洲一级| 韩国三级一区| 午夜激情视频在线播放| 午夜欧美成人香蕉剧场| 精品国产一区二区三区久| 天堂网中文在线| 四虎影视库| 一级片片| 九九九国产| 成人在激情在线视频| 午夜在线观看视频免费 成人| 国产亚洲免费观看| 久久99中文字幕| 亚洲 激情| 精品久久久久久中文字幕2017| 99久久精品国产免费| 国产伦理精品| 精品在线观看国产| 一级女性全黄久久生活片| 欧美另类videosbestsex高清| 欧美α片无限看在线观看免费| 久久久成人网| 国产伦久视频免费观看 视频| 欧美另类videosbestsex高清| 欧美一级视频高清片| 天天做日日爱| 午夜欧美成人久久久久久| 999精品在线| 精品视频在线观看免费| 久久成人综合网| 国产激情一区二区三区| 欧美a级v片不卡在线观看| 可以免费看毛片的网站| 亚洲精品影院一区二区| 日本免费区| 午夜激情视频在线播放| 欧美另类videosbestsex久久 | 欧美激情一区二区三区在线播放 | 欧美α片无限看在线观看免费| 黄色免费三级| 韩国毛片免费| 国产伦久视频免费观看视频| 成人影院久久久久久影院| 国产一区二区福利久久| 韩国三级视频网站| 国产视频一区二区在线播放|