Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Making a resizable dropdown widget with touch in flutter

I want to create a drop down menu like the image below, Which is opened by touching and dragging and closing by touching the outside.

before dragging

after dragging

Scaffold(
  appBar: AppBar(
    automaticallyImplyLeading: false
  ),
  body: Stack(
    children: <Widget>[
      Container(
        height: 200,
        decoration: BoxDecoration(
            color: Colors.white,
            borderRadius: BorderRadius.vertical(bottom: Radius.circular(20))
        ),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          children: <Widget>[
            Align(
              alignment: Alignment.bottomCenter,
              child: Column(
                children: <Widget>[
                  Padding(
                    padding: EdgeInsets.symmetric(horizontal: 40),
                    child: Divider(
                      color: Colors.blueGrey[500],
                      height: 10,
                      indent: 5,
                    ),
                  ),
                  Icon(FontAwesomeIcons.angleDoubleDown,size: 15,color: Colors.blueGrey[500],)
                ],
              ),
            )
          ],
        ),
      ),
      Center(child: Text('List View'),)
    ],
  )
)

I want to change the height, but I encounter overflow error! What is the best way to make this widget? Can I do this within the AppBar?

like image 460
saeid gh Avatar asked Mar 04 '23 11:03

saeid gh


1 Answers

You can do this in some ways, but one that came up in mind immediately was to use a CustomPaint widget with your own CustomPainter at the top of a Stack so you can actually keep your other widgets below the scrolled bar.

I've tried to replicate what you've shown on the images but feel free to tweak it to your needs.

example

const kMinScrollBarHeight = 20.0;

class MyScreen extends StatefulWidget {
  _MyScreenState createState() => _MyScreenState();
}

class _MyScreenState extends State<MyScreen> {
  double _scrollBarOffset = 0.0;

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: const Color.fromRGBO(13, 23, 35, 1.0),
      appBar: AppBar(
        backgroundColor: const Color.fromRGBO(255, 72, 18, 1.0),
      ),
      body: Stack(children: <Widget>[
        GestureDetector(
          onVerticalDragUpdate: (tapDetails) => setState(() => _scrollBarOffset = tapDetails.globalPosition.dy),
          child: Stack(
            children: <Widget>[
              Center(
                child: Text(
                  'My screen widgets',
                  style: TextStyle(color: Colors.white),
                ),
              ),
              Stack(
                children: <Widget>[
                  Positioned(
                    bottom: MediaQuery.of(context).size.height -
                        max(_scrollBarOffset,
                            MediaQuery.of(context).padding.top + kToolbarHeight + kMinScrollBarHeight),
                    child: CustomPaint(
                      painter: MyDraggable(),
                      child: Container(
                        height: MediaQuery.of(context).size.height,
                        width: double.infinity,
                        child: Column(
                          mainAxisAlignment: MainAxisAlignment.center,
                          children: <Widget>[
                            FlutterLogo(
                              size: 100.0,
                            ),
                            Text('Flutter is awesome'),
                          ],
                        ),
                      ),
                    ),
                  ),
                ],
              ),
            ],
          ),
        ),
      ]),
    );
  }
}

class MyDraggable extends CustomPainter {
  @override
  void paint(Canvas canvas, Size size) {
    final Paint paint = Paint()..color = Colors.white;
    final Radius cornerRadius = Radius.circular(20.0);
    final double lineMargin = 30.0;

    // Draw slider
    canvas.drawRRect(
        RRect.fromLTRBAndCorners(0.0, 0.0, size.width, size.height,
            bottomLeft: cornerRadius, bottomRight: cornerRadius),
        paint);
    paint.color = Colors.black.withAlpha(64);
    paint.strokeWidth = 1.5;

    // Draw triangle
    canvas.drawPoints(
        PointMode.polygon,
        [
          Offset((size.width / 2) - 5.0, size.height - 10.0),
          Offset((size.width / 2) + 5.0, size.height - 10.0),
          Offset((size.width / 2), size.height - 5.0),
          Offset((size.width / 2) - 5.0, size.height - 10.0),
        ],
        paint);

    // Draw line
    canvas.drawLine(Offset(lineMargin, size.height - kMinScrollBarHeight),
        Offset(size.width - lineMargin, size.height - kMinScrollBarHeight), paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) => true;
}
like image 70
Miguel Ruivo Avatar answered Mar 18 '23 17:03

Miguel Ruivo