【问题标题】:Draggable Scrollable Sheet from both top and bottom从顶部和底部可拖动的可滚动工作表
【发布时间】:2021-09-16 08:24:47
【问题描述】:

我想知道有没有办法实现从顶部和底部展开的可拖动工作表。预期的行为是,当我将工作表从底部拖动到总高度的 75% 左右时,另一张工作表将从顶部开始展开,而我仍在向上拖动并停止,直到两张工作表相互接触。

DraggableScrollableSheet(
    builder: (BuildContext context, ScrollController scrollController) {
        return Container(
            color: Colors.blue[100],
            child: ListView.builder(
                controller: scrollController,
                itemCount: 25,
                itemBuilder: (BuildContext context, int index) {
                    return ListTile(title: Text('Item $index'));
                },
            ),
        );
    },

我注意到滚动控制器具有 ScrollPosition 的属性,我猜它可以用于触发从上到下的可拖动工作表。我目前的想法是创建一个侦听器,通过滚动控制器类中的 notifyListeners 方法将其添加到滚动控制器,并在满足要求后将顶部的另一个可拖动工作表推送到堆栈。有没有类似想法或说法的例子,关于是否有可能有这样一个奇特的想法?

【问题讨论】:

    标签: flutter dart listener draggable


    【解决方案1】:

    是的,非常有可能,就像 Bolt 应用欢呼一样工作

    import 'package:flutter/material.dart';
    
    class AnimationSheet extends StatefulWidget {
      const AnimationSheet({Key? key}) : super(key: key);
    
      @override
      State<AnimationSheet> createState() => _AnimationSheetState();
    }
    
    class _AnimationSheetState extends State<AnimationSheet> {
      double _percent = 0.0;
      bool isDragged = false;
      double initialHeight = 0.0;
    
      checkStateDragged() {
        if (_percent > 0.5) {
          setState(() {
            isDragged = true;
          });
        } else {
          setState(() {
            isDragged = false;
          });
        }
      }
    
      @override
      Widget build(BuildContext context) {
        // handle hiding disabled search field
        checkStateDragged();
        return Scaffold(
          drawer: Drawer(
            elevation: 0,
            child: SafeArea(
              child: Column(
                children: const [
                  Text("Hello world"),
                ],
              ),
            ),
          ),
          body: SafeArea(
            child: Stack(
              children: [
                Positioned.fill(
                  bottom: MediaQuery.of(context).size.height * 0.2,
                  child: Image.asset(
                    'assets/images/background.jpg',
                    fit: BoxFit.cover,
                  ),
                ),
                Positioned(
                  top: 10.0,
                  left: 10.0,
                  child: FloatingActionButton(
                    backgroundColor: Colors.white,
                    onPressed: () {},
                    child: const Icon(
                      Icons.menu,
                      color: Colors.black,
                    ),
                  ),
                ),
    
                /* draggable scrollable sheet*/
                Positioned.fill(
                  child: NotificationListener<DraggableScrollableNotification>(
                    onNotification: (notification) {
                      setState(() {
                        _percent = 2 * notification.extent - 0.8;
                      });
                      return true;
                    },
                    child: DraggableScrollableSheet(
                      maxChildSize: 0.9,
                      minChildSize: 0.4,
                      builder: (BuildContext context, ScrollController scrollController) {
                        return Material(
                          elevation: 10.0,
                          borderRadius: const BorderRadius.vertical(
                            top: Radius.circular(20.0),
                          ),
                          color: Colors.white,
                          child: Padding(
                            padding: const EdgeInsets.only(
                              left: 10.0,
                              right: 10.0,
                            ),
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.start,
                              children: [
                                const SizedBox(height: 15.0),
                                Container(
                                  height: 10.0,
                                  margin: const EdgeInsets.symmetric(horizontal: 120.0),
                                  decoration: BoxDecoration(
                                    color: Colors.grey[200],
                                    borderRadius: BorderRadius.circular(50.0),
                                  ),
                                ),
                                const SizedBox(height: 15.0),
                                Container(
                                  margin: const EdgeInsets.symmetric(horizontal: 5.0),
                                  child: const Text(
                                    "Akwaaba !",
                                    style: TextStyle(
                                      color: Colors.black54,
                                    ),
                                  ),
                                ),
                                Container(
                                  margin: const EdgeInsets.symmetric(
                                    horizontal: 5.0,
                                    vertical: 5.0,
                                  ),
                                  decoration: const BoxDecoration(
                                    color: Colors.white,
                                  ),
                                  child: const Text(
                                    "Where are you going?",
                                    style: TextStyle(
                                      color: Colors.black,
                                      fontWeight: FontWeight.w900,
                                      fontSize: 22.0,
                                    ),
                                  ),
                                ),
                                !isDragged
                                    ? GestureDetector(
                                        onTap: () {
                                          setState(() {
                                            _percent = 1.0;
                                          });
                                        },
                                        child: TextFormField(
                                          decoration: InputDecoration(
                                            enabled: false,
                                            hintText: "Search Destination",
                                            filled: true,
                                            fillColor: Colors.white,
                                            border: const OutlineInputBorder(
                                              borderRadius: BorderRadius.all(
                                                Radius.circular(15.0),
                                              ),
                                              gapPadding: 2.0,
                                            ),
                                            prefixIcon: Icon(
                                              Icons.search,
                                              color: Colors.purple[300],
                                            ),
                                          ),
                                        ),
                                      )
                                    : Container(),
                                Expanded(
                                  child: ListView.builder(
                                    controller: scrollController,
                                    padding: const EdgeInsets.only(bottom: 40.0),
                                    itemCount: 20,
                                    itemBuilder: (context, index) {
                                      return const ListTile(
                                        contentPadding: EdgeInsets.zero,
                                        leading: Icon(
                                          Icons.location_on,
                                          color: Colors.black,
                                        ),
                                        title: Text(
                                          "Street No 12345 NY Street",
                                          style: TextStyle(
                                            color: Colors.black87,
                                            fontWeight: FontWeight.w700,
                                          ),
                                        ),
                                        subtitle: Text(
                                          "New York City",
                                          style: TextStyle(
                                            color: Colors.black54,
                                          ),
                                        ),
                                      );
                                    },
                                  ),
                                ),
                              ],
                            ),
                          ),
                        );
                      },
                    ),
                  ),
                ),
    
                /* search destination */
                Positioned(
                  left: 0.0,
                  right: 0.0,
                  top: -180 * (1 - _percent),
                  child: Opacity(
                    opacity: _percent,
                    child: const SearchDestination(),
                  ),
                ),
    
                /* select destination on map */
                Positioned(
                  left: 0.0,
                  right: 0.0,
                  bottom: -50 * (1 - _percent),
                  child: Opacity(
                    opacity: _percent,
                    child: const PickOnMap(),
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    // search destination sheet
    class SearchDestination extends StatelessWidget {
      const SearchDestination({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Material(
          elevation: 2.0,
          child: Padding(
            padding: const EdgeInsets.only(
              left: 10.0,
              right: 10.0,
              top: 10.0,
              bottom: 10.0,
            ),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceBetween,
                  children: [
                    const Icon(
                      Icons.arrow_back_ios,
                      color: Colors.black87,
                    ),
                    Expanded(
                      child: Center(
                        child: Text(
                          "Choose Destination".toUpperCase(),
                          style: const TextStyle(
                            color: Colors.black87,
                            fontWeight: FontWeight.w900,
                            fontSize: 22.0,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 25.0),
                  child: Column(
                    children: [
                      const SizedBox(height: 10.0),
                      //  pick up location
                      TextFormField(
                        decoration: InputDecoration(
                          hintText: "Avenue 34 St 34 NY",
                          filled: true,
                          fillColor: Colors.grey[200],
                          border: InputBorder.none,
                        ),
                      ),
                      const SizedBox(height: 10.0),
                      //  destination
                      TextFormField(
                        decoration: InputDecoration(
                          hintText: "Where are you going",
                          filled: true,
                          fillColor: Colors.grey[200],
                          border: InputBorder.none,
                        ),
                      ),
                      const SizedBox(height: 10.0),
                    ],
                  ),
                ),
              ],
            ),
          ),
        );
      }
    }
    
    /// select destination on map
    class PickOnMap extends StatelessWidget {
      const PickOnMap({Key? key}) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Material(
          elevation: 5.0,
          color: Colors.amber,
          child: Padding(
            padding: const EdgeInsets.symmetric(
              horizontal: 20.0,
              vertical: 10.0,
            ),
            child: Center(
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: const [
                  Icon(
                    Icons.place_sharp,
                    color: Colors.purple,
                  ),
                  SizedBox(width: 30.0),
                  Text(
                    "Select on Map",
                    style: TextStyle(
                      color: Colors.black87,
                      fontSize: 22.0,
                      fontWeight: FontWeight.w700,
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-10-10
      • 2021-10-18
      • 1970-01-01
      • 2017-04-13
      • 2013-01-25
      • 1970-01-01
      相关资源
      最近更新 更多