Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to achieve scrollable canvas in Flutter?

I'm a experienced iOS developer, but completely new to the Flutter. Right now I'm facing a problem with ScrollView in Flutter.

What I want to achieve is building a large scrollable canvas. I did it on iOS before, you can see the screenshot here.

iOS UI

The canvas is a big UIScrollView, and each subview on the canvas is draggable, so I can place them at will. Even if the text is very long, I can scroll the canvas to see the full content. Now I need to do the same thing using Flutter.

Currently, I can only drag the text widgets in Flutter. But the parent widget is not scrollable. I know I need to use a scrollable widget in Flutter to achieve the same result, but I just can't make it work. Here's the code I currently have.

void main() {
  //debugPaintLayerBordersEnabled = true;
  //debugPaintSizeEnabled = true;
  runApp(new MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new MaterialApp(
        title: 'Flutter Demo',
        theme: new ThemeData(
        primarySwatch: Colors.indigo,
      ),
      home: new MyHomePage(title: 'Flutter Demo Drag Box'),
    );
  }
}

class MyHomePage extends StatelessWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
      title: new Text(title),
    ),
    body: DragBox(Offset(0.0, 0.0)));
  }
}

class DragBox extends StatefulWidget {
  final Offset position; // widget's position
  DragBox(this.position);

  @override
  _DragBoxState createState() => new _DragBoxState();
}

class _DragBoxState extends State<DragBox> {
  Offset _previousOffset;
  Offset _offset;
  Offset _position;

  @override
  void initState() {
    _offset = Offset.zero;
    _previousOffset = Offset.zero;
    _position = widget.position;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return new Container(
      constraints: BoxConstraints.expand(),
      color: Colors.white24,
      child: Stack(
        children: <Widget>[
        buildDraggableBox(1, Colors.red, _offset)
      ],
    )
  );
}

Widget buildDraggableBox(int boxNumber, Color color, Offset offset) {
  print('buildDraggableBox $boxNumber !');
  return new Stack(
    children: <Widget>[
      new Positioned(
        left: _position.dx,
        top: _position.dy,
        child: Draggable(
          child: _buildBox(color, offset),
          feedback: _buildBox(color, offset),
          //childWhenDragging: _buildBox(color, offset, onlyBorder: true),
          onDragStarted: () {
            print('Drag started !');
            setState(() {
              _previousOffset = _offset;
            });
            print('Start position: $_position}');
          },
          onDragCompleted: () {
            print('Drag complete !');
          },
          onDraggableCanceled: (Velocity velocity, Offset offset) {
            // update position here
            setState(() {
              Offset _offset = Offset(offset.dx, offset.dy - 80);
              _position = _offset;
              print('Drag canceled position: $_position');
            });
          },
        ),
      )
    ],
  );
}

Widget _buildBox(Color color, Offset offset, {bool onlyBorder: false}) {
  return new Container(
    child: new Text('Flutter widget',
      textAlign: TextAlign.center,
      style: new TextStyle(fontWeight: FontWeight.bold, fontSize: 25.0)),
    );
  }
}

Any suggestions or code samples would be really helpful to me.

PS: Please forget about the rulers on the screenshot, it's not the most important thing to me right now. I just need a big scrollable canvas now.

like image 909
colin Avatar asked Aug 17 '18 04:08

colin


People also ask

How do I make my canvas scrollable?

Specify the total width of the canvas then wrap it in a div. Set the div to overflow: scroll and give that the 500px width. You should then have scrollbars allowing you to scroll and see the hidden parts of the canvas. Repeat this for all of the canvases.

How do you add a scrollable in flutter?

By default, scrollable widgets in Flutter don't show a scrollbar. To add a scrollbar to a ScrollView, wrap the scroll view widget in a Scrollbar widget. Using this widget we can scroll a widget. The scrollbar allows the user to jump into the particular points and also shows how far the user reaches.


1 Answers

The below Code may help to resolve your problem it scroll the custom canvas in horizontal direction as you have shown in example image.

     import 'package:flutter/material.dart';

      class MyScroll extends StatelessWidget {
        @override
        Widget build(BuildContext context) {
          return new MaterialApp(
            title: 'Flutter Demo',
            theme: new ThemeData(
              primarySwatch: Colors.blue,
            ),
            home: new MyHomePage(title: 'Canvas Scroller'),
          );
        }
      }
      class MyHomePage extends StatefulWidget {
        MyHomePage({Key key, this.title}) : super(key: key);
        final String title;

        @override
        _MyHomePageState createState() => new _MyHomePageState();
      }
      class _MyHomePageState extends State<MyHomePage> {
        @override
        Widget build(BuildContext context) {
          final width = MediaQuery.of(context).size.width;
          final height = MediaQuery.of(context).size.height;
          return new Scaffold(
            appBar: new AppBar(
              title: new Text(widget.title),
            ),
            body: new Center(
              child: new SingleChildScrollView(
                scrollDirection: Axis.horizontal,
                child: new CustomPaint(
                  painter: new MyCanvasView(),
                  size: new Size(width*2, height/2),
                ),
              ),
            ),
          );
        }
      }

      class MyCanvasView extends CustomPainter{
        @override
        void paint(Canvas canvas, Size size) {
          var paint = new Paint();
          paint..shader = new LinearGradient(colors: [Colors.yellow[700], Colors.redAccent],
             begin: Alignment.centerRight, end: Alignment.centerLeft).createShader(new Offset(0.0, 0.0)&size);
          canvas.drawRect(new Offset(0.0, 0.0)&size, paint);
          var path = new Path();
          path.moveTo(0.0, size.height);
          path.lineTo(1*size.width/4, 0*size.height/4);
          path.lineTo(2*size.width/4, 2*size.height/4);
          path.lineTo(3*size.width/4, 0*size.height/4);
          path.lineTo(4*size.width/4, 4*size.height/4);
          canvas.drawPath(path, new Paint()..color = Colors.yellow ..strokeWidth = 4.0 .. style = PaintingStyle.stroke);
        }

        @override
        bool shouldRepaint(CustomPainter oldDelegate) {
          return false;
        }

      }
like image 144
Zulfiqar Avatar answered Oct 20 '22 00:10

Zulfiqar