timebar_widget 0.0.2 copy "timebar_widget: ^0.0.2" to clipboard
timebar_widget: ^0.0.2 copied to clipboard

A highly customizable timeline/timebar widget for Flutter. Ideal for video surveillance, CCTV, and live stream playback navigation with zoom and multi-segment support.

example/main.dart

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:timebar_widget/timebar_widget.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: TimeBarDemoPage(),
    );
  }
}

class TimeBarDemoPage extends StatefulWidget {
  const TimeBarDemoPage({super.key});

  @override
  State<TimeBarDemoPage> createState() => _TimeBarDemoPageState();
}

class _TimeBarDemoPageState extends State<TimeBarDemoPage> {
  late int _currentTimeMs;
  late List<RecordSegment> _segments;
  bool _isPlaying = false;
  Timer? _playbackTimer;
  final bool _isLandscape = false;

  @override
  void initState() {
    super.initState();
    // 设置当前时间为今天中午
    final now = DateTime.now();
    _currentTimeMs =
        DateTime(now.year, now.month, now.day, 12, 0, 0).millisecondsSinceEpoch;
    _generateMockSegments();
  }

  @override
  void dispose() {
    _playbackTimer?.cancel();
    super.dispose();
  }

  /// 生成模拟数据
  void _generateMockSegments() {
    final now = DateTime.now();
    final startOfDay =
        DateTime(now.year, now.month, now.day, 0, 0, 0).millisecondsSinceEpoch;

    _segments = [
      // 早上 08:00 - 10:00 普通录像
      RecordSegment(
        startTimeMs: startOfDay + 8 * 3600000,
        endTimeMs: startOfDay + 10 * 3600000,
        type: SegmentType.normal,
      ),
      // 10:00 - 10:30 移动侦测
      RecordSegment(
        startTimeMs: startOfDay + 10 * 3600000,
        endTimeMs: startOfDay + 10 * 3600000 + 1800000,
        type: SegmentType.motion,
      ),
      // 11:00 - 12:00 报警录制
      RecordSegment(
        startTimeMs: startOfDay + 11 * 3600000,
        endTimeMs: startOfDay + 12 * 3600000,
        type: SegmentType.alert,
      ),
      // 13:00 - 15:00 普通录像
      RecordSegment(
        startTimeMs: startOfDay + 13 * 3600000,
        endTimeMs: startOfDay + 15 * 3600000,
        type: SegmentType.normal,
      ),
      // 16:00 - 16:15 自定义
      RecordSegment(
        startTimeMs: startOfDay + 16 * 3600000,
        endTimeMs: startOfDay + 16 * 3600000 + 900000,
        type: SegmentType.custom,
      ),
      // 20:00 - 22:00 普通录像
      RecordSegment(
        startTimeMs: startOfDay + 20 * 3600000,
        endTimeMs: startOfDay + 22 * 3600000,
        type: SegmentType.normal,
      ),
    ];
  }

  void _togglePlayback() {
    setState(() {
      _isPlaying = !_isPlaying;
      if (_isPlaying) {
        _playbackTimer =
            Timer.periodic(const Duration(milliseconds: 100), (timer) {
          setState(() {
            _currentTimeMs += 100;
          });
        });
      } else {
        _playbackTimer?.cancel();
      }
    });
  }

  void _jumpToTime(int hour, int minute) {
    final now = DateTime.now();
    setState(() {
      _currentTimeMs = DateTime(now.year, now.month, now.day, hour, minute, 0)
          .millisecondsSinceEpoch;
    });
  }

  String _formatTime(int timeMs) {
    final dt = DateTime.fromMillisecondsSinceEpoch(timeMs);
    return "${dt.hour.toString().padLeft(2, '0')}:${dt.minute.toString().padLeft(2, '0')}:${dt.second.toString().padLeft(2, '0')}";
  }

  @override
  Widget build(BuildContext context) {
    // 查找当前时间所属的段
    RecordSegment? currentSegment;
    try {
      currentSegment = _segments.firstWhere((s) => s.contains(_currentTimeMs));
    } catch (_) {}

    return Scaffold(
      appBar: AppBar(
        title: const Text('录像时间轴演示'),
        backgroundColor: Colors.blueAccent,
      ),
      body: Column(
        children: [
          // 视频预览占位
          Expanded(
            child: Container(
              color: Colors.black,
              child: Center(
                child: Column(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    const Icon(Icons.videocam, color: Colors.white, size: 64),
                    const SizedBox(height: 16),
                    Text(
                      _formatTime(_currentTimeMs),
                      style: const TextStyle(
                          color: Colors.white,
                          fontSize: 24,
                          fontWeight: FontWeight.bold),
                    ),
                    if (currentSegment != null)
                      Padding(
                        padding: const EdgeInsets.only(top: 8.0),
                        child: Text(
                          "正在播放: ${currentSegment.type.name.toUpperCase()} 录像",
                          style: TextStyle(
                              color: currentSegment.type.getDefaultColor(),
                              fontSize: 16),
                        ),
                      ),
                  ],
                ),
              ),
            ),
          ),

          // 控制栏
          Padding(
            padding: const EdgeInsets.all(16.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.spaceEvenly,
              children: [
                IconButton(
                  icon: Icon(_isPlaying ? Icons.pause : Icons.play_arrow,
                      size: 36),
                  onPressed: _togglePlayback,
                ),
                ElevatedButton(
                  onPressed: () => _jumpToTime(8, 0),
                  child: const Text('08:00'),
                ),
                ElevatedButton(
                  onPressed: () => _jumpToTime(12, 0),
                  child: const Text('12:00'),
                ),
                ElevatedButton(
                  onPressed: () => _jumpToTime(20, 0),
                  child: const Text('20:00'),
                ),
              ],
            ),
          ),

          // 时间轴组件
          TimeBarWidget(
            segments: _segments,
            currentTimeMs: _currentTimeMs,
            onTimeChanged: (timeMs) {
              setState(() {
                _currentTimeMs = timeMs;
              });
            },
            // 自定义配置示例
            maxScale: 100.0,
            timeBarOption: TimeBarOption(
              height: _isLandscape ? 64 : 80,
              backgroundColor: Colors.transparent,
            ),
            videoAreaOption: VideoAreaOption(
              height: _isLandscape ? 12.0 : 14.0,
              topOffset: _isLandscape ? 26.0 : 28.0,
              backgroundColor: Colors.black12,
            ),
            middleIndicatorOption: MiddleIndicatorOption(
              fillColor: const Color(0xFF0A59F7),
              timeTextStyle: TextStyle(
                color: const Color(0xFF0A59F7),
                fontSize: 12.0,
                fontWeight: FontWeight.bold,
              ),
            ),
            timeScaleOption: TimeScaleOption(
              scaleTextColor: Colors.blue,
              scaleLineColor: Colors.blue,
            ),
          ),

          // 图例
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8.0),
            child: Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                _buildLegend(SegmentType.normal, '普通'),
                const SizedBox(width: 16),
                _buildLegend(SegmentType.motion, '移动'),
                const SizedBox(width: 16),
                _buildLegend(SegmentType.alert, '报警'),
                const SizedBox(width: 16),
                _buildLegend(SegmentType.custom, '自定义'),
              ],
            ),
          ),
          const SizedBox(height: 16),
        ],
      ),
    );
  }

  Widget _buildLegend(SegmentType type, String label) {
    return Row(
      children: [
        Container(
            width: 12,
            height: 12,
            decoration: BoxDecoration(
                color: type.getDefaultColor(),
                borderRadius: BorderRadius.circular(2))),
        const SizedBox(width: 4),
        Text(label, style: const TextStyle(fontSize: 12)),
      ],
    );
  }
}
1
likes
155
points
4
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A highly customizable timeline/timebar widget for Flutter. Ideal for video surveillance, CCTV, and live stream playback navigation with zoom and multi-segment support.

Repository (GitHub)
View/report issues

License

MIT (license)

Dependencies

flutter

More

Packages that depend on timebar_widget