2

Here solved question about design this layout.

enter image description here

I have a problem to using that, because of this curve on right of screen is not widget and when I want to have some other widgets in green side, I can't, because designed curve is not widget its clipped from green layout.

Suppose I want to have this curve on right of screen and some widget in below of that.

Source code

import 'package:flutter/material.dart';

void main() {
    runApp(MaterialApp(home: Scaffold(body: Test())));
}

class Test extends StatefulWidget {
    @override
    _TestState createState() => _TestState();
}

class _TestState extends State<Test> {
    double _height = 0.0;
    double _width = 0.0;
    double _rightPadding = 2.0;
    double _btnSize = 25.0;
    double _btnY = 0.0;

    @override
    Widget build(BuildContext context) {
    if (_height == 0.0)
        setState(() {
        _height = MediaQuery.of(context).size.height;
        _width = MediaQuery.of(context).size.width;
        _btnY = _height / 3 * 2;
        });
    return _height == 0.0
        ? Container()
        : Stack(
            children: <Widget>[
                Container(
                color: Colors.white,
                ),
                CustomPaint(
                size: Size(_width - _rightPadding, _height),
                painter: CurvedPainter(_btnSize, _btnY),
                ),
            ],
            );
    }
}

class CurvedPainter extends CustomPainter {
    CurvedPainter(this.btnSize, this.btnY);

    final double btnSize;
    final double btnY;

    @override
    void paint(Canvas canvas, Size size) {
    Path path = Path();
    path.moveTo(0.0, 0.0);
    path.lineTo(size.width, 0.0);
    path.lineTo(size.width, btnY - btnSize * 2);

    path.cubicTo(size.width, btnY - btnSize * 0.3, size.width - btnSize * 0.95, btnY - btnSize * 0.9, size.width - btnSize, btnY);
    path.cubicTo(size.width - btnSize * 0.95, btnY + btnSize * 0.9, size.width, btnY + btnSize * 0.3, size.width, btnY + btnSize * 2);

    path.lineTo(size.width, size.height);
    path.lineTo(0.0, size.height);
    path.lineTo(0.0, 0.0);
    canvas.drawPath(
        path,
        Paint()
            ..color = Colors.transparent
            ..style = PaintingStyle.fill);
    }

    @override
    bool shouldRepaint(CurvedPainter oldDelegate) => oldDelegate.btnY != btnY;
}

I want to use right curve as an widget on top of all widgets, without having green side, you suppose green side is as ListView.

Kherel
  • 14,882
  • 5
  • 50
  • 80
DolDurma
  • 15,753
  • 51
  • 198
  • 377
  • simply implement `_getPath` method, something like this: https://pastebin.com/raw/Q8KvmvkF – pskink Aug 14 '19 at 06:23
  • @Andrey Turkovsky could you help me on this issue? – DolDurma Aug 20 '19 at 07:56
  • @pskink in that green should be transparent and i want to have only right half circle. like with this design witch that is widget.https://stackoverflow.com/a/56988726/1830228 in this design and your implementation that cause of clip part of container, but i want to have widget.screen shot http://s6.uplod.ir/i/00958/ysbszbx5dy6d.png – DolDurma Aug 21 '19 at 16:47
  • @pskink could you got it with this graphic and is that understandable? http://s6.uplod.ir/i/00958/pezhjuaio39m.png – DolDurma Aug 22 '19 at 04:48
  • @pskink my mean is designed curve is under `listview`, its not top of `listview`. i want to have a simple single widget on top of all widgets and layout, widget like with customizable `container` – DolDurma Aug 22 '19 at 06:31
  • @pskink please check this link. i want to design like with this implementation https://stackoverflow.com/a/56988726/1830228 – DolDurma Aug 22 '19 at 06:33
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/198284/discussion-between-doldurma-and-pskink). – DolDurma Aug 22 '19 at 06:35
  • @pskink yes, i see that and i upvote your answer, thanks in advance – DolDurma Aug 25 '19 at 08:33
  • @pskink why you deleted your post? i'll try to use that for another design of application – DolDurma Aug 25 '19 at 09:48

1 Answers1

6

It seems that you need something like this given in the image below.

Update: Dragging control added

enter image description here

import 'dart:math' as math;
import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      debugShowCheckedModeBanner: false,
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        body: Test(),
      ),
    );
  }
}

class Test extends StatefulWidget {
  @override
  _TestState createState() => _TestState();
}

enum dragType { vertical, horizontal }

class _TestState extends State<Test> {
  final double _btnSize = 48.0;
  final double _rightPadding = 0;

  double _extraOffcet = 0;
  double _btnY;
  double _currentX;
  double _currentY;
  double _height;
  double _width;

  bool _isHorizontalActive = true;
  bool _isVerticalActive = true;

  @override
  void initState() {
    WidgetsBinding.instance.addPostFrameCallback(_afterLayout);

    super.initState();
  }

  _afterLayout(_) {
    _height = MediaQuery.of(context).size.height;
    _width = MediaQuery.of(context).size.width;
    _btnY = _height / 2;
    setState(() {});
  }

  _onDrag(details) {
    _updateCoordinates(
      details.globalPosition.dx,
      details.globalPosition.dy,
    );
  }

  _updateCoordinates(double x, double y) {
    setState(() {
      if (_isHorizontalActive) {
        _updateX(x);
      }
      if (_isVerticalActive) {
        _updateY(y);
      }
    });
  }

  _updateX(x) {
    var dx = _currentX - x;
    _currentX = x;
    _extraOffcet = _extraOffcet + dx;
    _extraOffcet = math.max(_extraOffcet, _rightPadding);
    _extraOffcet = math.min(_extraOffcet, _width - _btnSize);
  }

  _updateY(y) {
    var dy = _currentY - y;
    _currentY = y;
    _btnY = _btnY - dy;
    _btnY = math.max(_btnY, _btnSize);
    _btnY = math.min(_btnY, _height - _btnSize);
  }

  _listItem(String text, double height) {
    return Container(
      height: height,
      child: Text(text, style: TextStyle(fontSize: 20.0)),
    );
  }

  @override
  Widget build(BuildContext context) {
    return _height == null
        ? Container()
        : Stack(
            children: <Widget>[
              Container(
                padding: EdgeInsets.only(right: 30),
                color: Colors.blue,
                height: double.infinity,
                width: double.infinity,
                child: Column(mainAxisAlignment: MainAxisAlignment.center, children: [
                  _buildSwitch(type: dragType.vertical),
                  _buildSwitch(type: dragType.horizontal),
                  ...List.generate(
                    4,
                    (index) => _listItem('inside', 80),
                  ),
                ]),
              ),
              Positioned(
                right: _extraOffcet + _rightPadding,
                child: CustomPaint(
                  size: Size(_btnSize, _height),
                  painter: CurvedPainter(_btnSize, _btnY),
                ),
              ),
              Positioned(
                top: _btnY - _btnSize / 2 + 5,
                right: _extraOffcet + _rightPadding + 5,
                child: GestureDetector(
                  onPanDown: (details) {
                    _currentX = details.globalPosition.dx;
                    _currentY = details.globalPosition.dy;
                  },
                  onPanStart: _onDrag,
                  onPanUpdate: _onDrag,
                  child: Material(
                    type: MaterialType.circle,
                    color: Colors.white,
                    elevation: 8.0,
                    child: Container(
                      width: _btnSize - 10,
                      height: _btnSize - 10,
                      child: Icon(Icons.add),
                    ),
                  ),
                ),
              ),
              Positioned(
                top: 0,
                left: _width - _extraOffcet,
                child: Container(
                  color: Colors.white,
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: List.generate(8, (index) => _listItem('from right', 20)),
                  ),
                  height: _height,
                  width: _width,
                ),
              ),
            ],
          );
  }

  SwitchListTile _buildSwitch({dragType type}) {
    Function onChange;
    String titleText, sutitleText;
    bool value;

    if (type == dragType.horizontal) {
      value = _isHorizontalActive;
      titleText = 'Horizontal dragging';
      onChange = (newValue) => setState(() => _isHorizontalActive = newValue);
    } else {
      value = _isVerticalActive;
      titleText = 'Vertical dragging';
      onChange = (newValue) => setState(() => _isVerticalActive = newValue);
    }
    sutitleText = value ? 'active' : 'disabled';

    return SwitchListTile(
      value: value,
      onChanged: onChange,
      title: Text(titleText),
      subtitle: Text(sutitleText),
    );
  }
}

class CurvedPainter extends CustomPainter {
  CurvedPainter(this.btnSize, this.btnY);

  final double btnSize;
  final double btnY;

  @override
  void paint(Canvas canvas, Size size) {
    var halfBtnSize = btnSize / 2;
    var xMax = size.width;
    var yMax = size.height;

    var path = Path()
      ..moveTo(halfBtnSize, yMax)
      ..lineTo(halfBtnSize, btnY + halfBtnSize * 2)
      ..cubicTo(halfBtnSize, btnY + halfBtnSize, 0, btnY + halfBtnSize, 0, btnY)
      ..cubicTo(0, btnY - halfBtnSize, halfBtnSize, btnY - halfBtnSize, halfBtnSize,
          btnY - halfBtnSize * 2)
      ..lineTo(halfBtnSize, 0)
      ..lineTo(xMax, 0)
      ..lineTo(xMax, yMax);

    canvas.drawPath(
        path,
        Paint()
          ..color = Colors.white
          ..style = PaintingStyle.fill);
  }

  @override
  bool shouldRepaint(CurvedPainter oldDelegate) => oldDelegate.btnY != btnY;
}
Kherel
  • 14,882
  • 5
  • 50
  • 80
  • dragging button to top or bottom and left or right are the same, how can i disable that? for example dragging only in left or right side. or top or bottom, that means linear dragging – DolDurma Aug 25 '19 at 05:03
  • By changing the _updateCoordinates method. When you change the _btnY parameter you change button position on axis Y, and when you change the _extraOffcet value you change button position on axis x + position of other moving elements. – Kherel Aug 25 '19 at 06:04
  • Sure give few minutes – Kherel Aug 25 '19 at 07:58
  • can we limited dragging on width of screen? for example with this code we can open slider to left of screen, my mean is like with Drawer to have limited width, for example 50% of width – DolDurma Aug 25 '19 at 09:50
  • 1
    The _width value is the width of the screen. The _extraOffcet is the value of how big is the drawer slide. The _onDrag method is receving a dragging position. change _updateX method: _updateX(x) { var dx = _currentX - x; _currentX = x; _extraOffcet = _extraOffcet + dx < _width / 2 ? _extraOffcet + dx : _extraOffcet; _extraOffcet = math.max(_extraOffcet, _rightPadding); _extraOffcet = math.min(_extraOffcet, _width - _btnSize); } – Kherel Aug 25 '19 at 10:34