flutter 可从顶部和底部拖动的可滚动工作表

kadbb459  于 2022-12-24  发布在  Flutter
关注(0)|答案(1)|浏览(148)

我想知道是否有可能创建一个可以从顶部和底部同时拉伸的可拖动工作表。当我从底部将工作表拉到其完整高度的大约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函数将其添加到滚动控制器,然后在满足条件时将另一个可拖动的工作表放到堆栈的顶部。

**编辑1:**这可以很容易地完成,你只需要3个小部件,animatedContainer,gestureDetector和transform。

vwkv1x7d

vwkv1x7d1#

是的,这是非常有可能的,工程完全一样的螺栓应用程序欢呼

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,
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

相关问题