Flutter:创建时间轴UI

时间:2018-04-03 16:53:58

标签: dart flutter

我正在尝试制作如下所示的时间轴用户界面:

enter image description here

但我最终会做以下事情:

enter image description here

当我的Description文本的行没有增加时,我想增加垂直分隔符的高度。我该怎么做?

以下是link for the code

6 个答案:

答案 0 :(得分:9)

对于那些正在滚动此处以找到实现时间表的简便方法的人来说,现在您可以使用timeline_tile轻松做到这一点。

查看此特定的交付布局:

或者这个天气时间表:

此外,beautiful_timelines存储库包含一些使用此软件包构建的示例。

Web demo

答案 1 :(得分:4)

 new ListView.builder(
                  itemBuilder: (BuildContext context, int index) {
                    return new Stack(
                      children: <Widget>[
                        new Padding(
                          padding: const EdgeInsets.only(left: 50.0),
                          child: new Card(
                            margin: new EdgeInsets.all(20.0),
                            child: new Container(
                              width: double.INFINITY,
                              height: 200.0,
                              color: Colors.green,
                            ),
                          ),
                        ),
                        new Positioned(
                          top: 0.0,
                          bottom: 0.0,
                          left: 35.0,
                          child: new Container(
                            height: double.INFINITY,
                            width: 1.0,
                            color: Colors.blue,
                          ),
                        ),
                        new Positioned(
                          top: 100.0,
                          left: 15.0,
                          child: new Container(
                            height: 40.0,
                            width: 40.0,
                            decoration: new BoxDecoration(
                              shape: BoxShape.circle,
                              color: Colors.white,
                            ),
                            child: new Container(
                              margin: new EdgeInsets.all(5.0),
                              height: 30.0,
                              width: 30.0,
                              decoration: new BoxDecoration(
                                  shape: BoxShape.circle,
                                  color: Colors.red),
                            ),
                          ),
                        )
                      ],
                    );
                  },
                  itemCount: 5,
                )

输出将如下图timeline image example

答案 2 :(得分:3)

我也喜欢Osama的回答,但这是我的快速自定义实现。它使用CustomPainter画线。

import 'package:flutter/material.dart';

class Timeline extends StatelessWidget {
  const Timeline({
    @required this.children,
    this.indicators,
    this.isLeftAligned = true,
    this.itemGap = 12.0,
    this.gutterSpacing = 4.0,
    this.padding = const EdgeInsets.all(8),
    this.controller,
    this.lineColor = Colors.grey,
    this.physics,
    this.shrinkWrap = true,
    this.primary = false,
    this.reverse = false,
    this.indicatorSize = 30.0,
    this.lineGap = 4.0,
    this.indicatorColor = Colors.blue,
    this.indicatorStyle = PaintingStyle.fill,
    this.strokeCap = StrokeCap.butt,
    this.strokeWidth = 2.0,
    this.style = PaintingStyle.stroke,
  })  : itemCount = children.length,
        assert(itemGap >= 0),
        assert(lineGap >= 0),
        assert(indicators == null || children.length == indicators.length);

  final List<Widget> children;
  final double itemGap;
  final double gutterSpacing;
  final List<Widget> indicators;
  final bool isLeftAligned;
  final EdgeInsets padding;
  final ScrollController controller;
  final int itemCount;
  final ScrollPhysics physics;
  final bool shrinkWrap;
  final bool primary;
  final bool reverse;

  final Color lineColor;
  final double lineGap;
  final double indicatorSize;
  final Color indicatorColor;
  final PaintingStyle indicatorStyle;
  final StrokeCap strokeCap;
  final double strokeWidth;
  final PaintingStyle style;

  @override
  Widget build(BuildContext context) {
    return ListView.separated(
      padding: padding,
      separatorBuilder: (_, __) => SizedBox(height: itemGap),
      physics: physics,
      shrinkWrap: shrinkWrap,
      itemCount: itemCount,
      controller: controller,
      reverse: reverse,
      primary: primary,
      itemBuilder: (context, index) {
        final child = children[index];

        Widget indicator;
        if (indicators != null) {
          indicator = indicators[index];
        }

        final isFirst = index == 0;
        final isLast = index == itemCount - 1;

        final timelineTile = <Widget>[
          CustomPaint(
            foregroundPainter: _TimelinePainter(
              hideDefaultIndicator: indicator != null,
              lineColor: lineColor,
              indicatorColor: indicatorColor,
              indicatorSize: indicatorSize,
              indicatorStyle: indicatorStyle,
              isFirst: isFirst,
              isLast: isLast,
              lineGap: lineGap,
              strokeCap: strokeCap,
              strokeWidth: strokeWidth,
              style: style,
              itemGap: itemGap,
            ),
            child: SizedBox(
              height: double.infinity,
              width: indicatorSize,
              child: indicator,
            ),
          ),
          SizedBox(width: gutterSpacing),
          Expanded(child: child),
        ];

        return IntrinsicHeight(
          child: Row(
            mainAxisAlignment: MainAxisAlignment.start,
            children:
                isLeftAligned ? timelineTile : timelineTile.reversed.toList(),
          ),
        );
      },
    );
  }
}

class _TimelinePainter extends CustomPainter {
  _TimelinePainter({
    @required this.hideDefaultIndicator,
    @required this.indicatorColor,
    @required this.indicatorStyle,
    @required this.indicatorSize,
    @required this.lineGap,
    @required this.strokeCap,
    @required this.strokeWidth,
    @required this.style,
    @required this.lineColor,
    @required this.isFirst,
    @required this.isLast,
    @required this.itemGap,
  })  : linePaint = Paint()
          ..color = lineColor
          ..strokeCap = strokeCap
          ..strokeWidth = strokeWidth
          ..style = style,
        circlePaint = Paint()
          ..color = indicatorColor
          ..style = indicatorStyle;

  final bool hideDefaultIndicator;
  final Color indicatorColor;
  final PaintingStyle indicatorStyle;
  final double indicatorSize;
  final double lineGap;
  final StrokeCap strokeCap;
  final double strokeWidth;
  final PaintingStyle style;
  final Color lineColor;
  final Paint linePaint;
  final Paint circlePaint;
  final bool isFirst;
  final bool isLast;
  final double itemGap;

  @override
  void paint(Canvas canvas, Size size) {
    final indicatorRadius = indicatorSize / 2;
    final halfItemGap = itemGap / 2;
    final indicatorMargin = indicatorRadius + lineGap;

    final top = size.topLeft(Offset(indicatorRadius, 0.0 - halfItemGap));
    final centerTop = size.centerLeft(
      Offset(indicatorRadius, -indicatorMargin),
    );

    final bottom = size.bottomLeft(Offset(indicatorRadius, 0.0 + halfItemGap));
    final centerBottom = size.centerLeft(
      Offset(indicatorRadius, indicatorMargin),
    );

    if (!isFirst) canvas.drawLine(top, centerTop, linePaint);
    if (!isLast) canvas.drawLine(centerBottom, bottom, linePaint);

    if (!hideDefaultIndicator) {
      final Offset offsetCenter = size.centerLeft(Offset(indicatorRadius, 0));

      canvas.drawCircle(offsetCenter, indicatorRadius, circlePaint);
    }
  }

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

您会这样称呼它:

Timeline(
  children: <Widget>[
    Container(height: 100, color: color),
    Container(height: 50, color: color),
    Container(height: 200, color: color),
    Container(height: 100, color: color),
  ],
  indicators: <Widget>[
    Icon(Icons.access_alarm),
    Icon(Icons.backup),
    Icon(Icons.accessibility_new),
    Icon(Icons.access_alarm),
  ],
),

An Image of a timeline mobile ui

答案 3 :(得分:0)

class MyTimeLine extends StatefulWidget {
 @override
 _TimeLineState createState() => _TimeLineState();
 }

class _TimeLineState extends State<MyTimeLine> {
@override
Widget build(BuildContext context) {
return new Padding(
  padding: new EdgeInsets.symmetric(horizontal: 10.0),
  child: new Column(
    children: <Widget>[
         IntrinsicHeight(
        child: new Row(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: <Widget>[
            Wrap(
              direction: Axis.vertical,
              children: <Widget>[
                new Container(
                  width: 30.0,
                  child: new Center(
                    child: new Stack(
                      children: <Widget>[
                        new Padding(
                          padding: new EdgeInsets.only(left: 12.0),
                          child: new Container(
                              margin:
                                  new EdgeInsets.symmetric(vertical: 4.0),
                              height: double.infinity,
                              width: 1.0,
                              color: Colors.deepOrange),
                        ),
                        new Container(
                          padding: new EdgeInsets.only(),
                          child: new Icon(Icons.star, color: Colors.white),
                          decoration: new BoxDecoration(
                              color: new Color(0xff00c6ff),
                              shape: BoxShape.circle),
                        )
                      ],
                    ),
                  ),
                ),
              ],
            ),
            new Expanded(
              child: new Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: <Widget>[
                  new Padding(
                    padding: new EdgeInsets.only(left: 20.0, top: 5.0),
                    child: new Text(
                      'Header Text',
                      style: new TextStyle(
                          fontWeight: FontWeight.w500,
                          color: Colors.deepOrange,
                          fontSize: 16.0),
                    ),
                  ),
                  new Padding(
                    padding: new EdgeInsets.only(left: 20.0, top: 5.0),
                    child: new Text(
                        'Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here Lorem ipsum description here description here '),
                  )
                ],
              ),
            )
          ],
        ),
      )
    ],
  ),
);
} 
}

答案 4 :(得分:0)

A glance of the pub

查看此酒吧。 https://pub.dev/packages/timeline_widget

它可以帮助您创建具有自定义内容的精美时间轴ui。也可以在左右对齐和居中对齐选项中使用。这是一个如何使用它的示例!

TimelineView(
  align: TimelineAlign.rightAlign,
  lineWidth: 4,
  lineColor: Colors.deepOrange,
  imageBorderColor: Colors.deepOrange,
  image: [
    Container(
        padding: EdgeInsets.all(15),
        child: Image.asset("assets/pre-breakfast-image.png")),
    Container(
        padding: EdgeInsets.all(15),
        child: Image.asset("assets/breakfast-image.png")),
    Container(
        padding: EdgeInsets.all(15),
        child: Image.asset("assets/pre-lunch-image.png")),
    Container(
        padding: EdgeInsets.all(15),
        child: Image.asset("assets/lunch-image.png")),
    Container(
        padding: EdgeInsets.all(15),
        child: Image.asset("assets/evening-snack-image.png")),
    Container(
        padding: EdgeInsets.all(20),
        child: Image.asset("assets/dinner-image.png")),
  ],
  height: 150,
  width: MediaQuery.of(context).size.width,
  imageHeight: 50,
  children: [
    Container(
        margin: EdgeInsets.fromLTRB(20, 0, 0, 0),
        child: _widgetWeather(20, 71, 31)),
    Container(
        margin: EdgeInsets.fromLTRB(20, 0, 0, 0),
        child: _widgetWeather(15, 75, 55)),
    Container(
        margin: EdgeInsets.fromLTRB(20, 0, 0, 0),
        child: _widgetWeather(25, 73, 30)),
    Container(
        margin: EdgeInsets.fromLTRB(20, 0, 0, 0),
        child: _widgetWeather(22, 65, 35)),
    Container(
        margin: EdgeInsets.fromLTRB(20, 0, 0, 0),
        child: _widgetWeather(21, 55, 32)),
    Container(
        margin: EdgeInsets.fromLTRB(20, 0, 0, 0),
        child: _widgetWeather(20, 65, 35)),
  ],
),

答案 5 :(得分:0)

您可以使用flutter_timeline,主体和指示器都可以自定义。

https://github.com/softmarshmallow/flutter-timeline

这是最新的受支持的软件包。 enter image description here