9 votes

Comment réaliser un canevas défilable dans Flutter ?

Je suis un développeur iOS expérimenté, mais complètement nouveau dans le domaine de Flutter. En ce moment, je suis confronté à un problème avec ScrollView dans Flutter.

Ce que je veux réaliser, c'est construire une grande toile déroulable. Je l'ai déjà fait sur iOS, vous pouvez voir la capture d'écran ici.

iOS UI

Le canevas est un grand UIScrollView, et chaque sous-vue du canevas peut être déplacée, de sorte que je peux les placer à volonté. Même si le texte est très long, je peux faire défiler le canevas pour voir l'intégralité du contenu. J'ai maintenant besoin de faire la même chose en utilisant Flutter.

Actuellement, je ne peux faire glisser que les widgets de texte dans Flutter. Mais le widget parent n'est pas déroulable. Je sais que je dois utiliser un widget défilable dans Flutter pour obtenir le même résultat, mais je n'arrive pas à le faire fonctionner. Voici le code que j'ai actuellement.

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

Toute suggestion ou exemple de code me serait très utile.

PS : oubliez les règles sur la capture d'écran, ce n'est pas la chose la plus importante pour moi en ce moment. J'ai juste besoin d'une grande toile déroulante maintenant.

8voto

Zulfiqar Ali Points 368

Le code ci-dessous peut vous aider à résoudre votre problème. Il fait défiler le canevas personnalisé dans le sens horizontal comme vous l'avez montré dans l'image d'exemple.

     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;
        }

      }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X