flutter_keyframe_timeline 0.0.2-pre1 copy "flutter_keyframe_timeline: ^0.0.2-pre1" to clipboard
flutter_keyframe_timeline: ^0.0.2-pre1 copied to clipboard

A Flutter package for creating keyframe-based timelines for 2D/3D animations, video editing, etc.

example/lib/main.dart

import 'package:flutter_keyframe_timeline/flutter_keyframe_timeline.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_keyframe_timeline_example/object/objects.dart';
import 'package:flutter_keyframe_timeline_example/object_display_widget.dart';
import 'package:flutter_keyframe_timeline_example/track_visibility_widget.dart';
import 'package:flutter_keyframe_timeline_example/timeline_skip_control.dart';
import 'package:logging/logging.dart';
import 'package:mix/mix.dart';

void main() {
  Logger.root.level = Level.ALL; // defaults to Level.INFO
  Logger.root.onRecord.listen((record) {
    print('${record.loggerName} ${record.level.name}  ${record.message}');
  });
  runApp(const MyApp());
}

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
      ),
      home: const MyHomePage(),
    );
  }
}

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

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  late final ObjectHolder _objectHolder;

  late final TimelineController _controller;

  final _numObjects = 5;

  @override
  void initState() {
    super.initState();
    _objectHolder = ObjectHolder(_numObjects, () {
      setState(() {});
    });
    _controller = TimelineController.create(
      _objectHolder.animatableObjects,
    );
    _objectHolder.setTimelineController(_controller);
    final map = TimelineSerializer.toMap(_objectHolder.animatableObjects.first);
    final foo = TimelineSerializer.fromMap(map);
    print(foo);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Expanded(
            child: ObjectDisplayWidget(
              objectHolder: _objectHolder,
              timelineController: _controller,
            ),
          ),
          Expanded(
            child: Stack(
              children: [
                Positioned.fill(
                  child: TimelineWidget(
                    controller: _controller,

                    trackObjectExtraWidgetBuilder:
                        (
                          BuildContext context,
                          AnimatableObject animatableObject,
                          bool trackObjectIsActive,
                          bool trackObjectIsExpanded,
                        ) {
                          final object = _objectHolder.get(animatableObject);
                          return TrackObjectVisibilityWidget(
                            object: object!,
                            isActive: trackObjectIsActive,
                            isExpanded: trackObjectIsExpanded,
                            onRemove: () {
                              _controller.deleteObject(animatableObject);
                              _objectHolder.removeObject(animatableObject);
                            },
                          );
                        },

                    keyframeIconBuilder:
                        (context, isSelected, isHovered, frameNumber) {
                          return Transform.translate(
                            offset: const Offset(
                              -11,
                              0.0,
                            ), // Center the 16px icon
                            child: Container(
                              padding: EdgeInsets.all(4),
                              child: Container(
                                width: 15,
                                height: 15,
                                decoration: BoxDecoration(
                                  boxShadow: isSelected || isHovered
                                      ? [
                                          BoxShadow(
                                            color: Colors.blue.withValues(
                                              alpha: 0.6,
                                            ),
                                            spreadRadius: isSelected ? 3 : 2,
                                            blurRadius: isSelected ? 6 : 4,
                                          ),
                                        ]
                                      : null,
                                ),
                                child: Transform.rotate(
                                  angle:
                                      0.785398, // 45 degrees in radians (pi/4)
                                  child: Container(
                                    decoration: BoxDecoration(
                                      color: Colors.blue,
                                      border: Border.all(
                                        color: Colors.black,
                                        width: 1,
                                      ),
                                    ),
                                  ),
                                ),
                              ),
                            ),
                          );
                        },
                    // keyframeToggleIconBuilder: (context, hasKeyframeAtCurrentFrame, onPressed) {
                    //   return IconButton(
                    //     onPressed: onPressed,
                    //     icon: Container(
                    //       width: 18,
                    //       height: 18,
                    //       decoration: BoxDecoration(
                    //         shape: BoxShape.circle,
                    //         color: hasKeyframeAtCurrentFrame ? Colors.green : Colors.red.withValues(alpha: 0.3),
                    //         border: Border.all(
                    //           color: hasKeyframeAtCurrentFrame ? Colors.green.shade800 : Colors.red,
                    //           width: 2,
                    //         ),
                    //       ),
                    //       child: Icon(
                    //         hasKeyframeAtCurrentFrame ? Icons.check : Icons.add,
                    //         color: hasKeyframeAtCurrentFrame ? Colors.white : Colors.red,
                    //         size: 12,
                    //       ),
                    //     ),
                    //     padding: EdgeInsets.zero,
                    //     constraints: const BoxConstraints(minWidth: 20, minHeight: 20),
                    //   );
                    // },
                    frameDragHandleStyle: FrameDragHandleStyle(
                      backgroundColor: Color(0xFF333333),
                      width: 50.0,
                      height: 30.0,
                      textBuilder: (context, text) => Text(
                        text,
                        style: TextStyle(
                          color: Color(0xFFEEEEEE),
                          fontSize: 14,
                        ),
                        textAlign: TextAlign.center,
                      ),
                    ),
                    backgroundStyle: TimelineBackgroundStyle(
                      majorTickColor: Colors.grey.shade500,
                      minorTickColor: Colors.grey.shade300,
                      textColor: Colors.grey.shade700,
                      majorTickInterval: 10,
                      minorTickInterval: 1,
                    ),
                    trackObjectNameStyle: TrackObjectNameStyle(
                      iconData: Icons.folder,
                      textColor: Colors.blue.shade800,
                      iconColor: Colors.blue.shade600,
                      borderColor: Colors.blue.shade200,
                    ),
                    channelValueEditorStyle: ChannelValueEditorStyle(
                      textFieldFontColor: Colors.green.shade700,
                      textFieldFontSize: 12.0,
                      labelBuilder: (label) {
                        return StyledText(
                          label,
                          style: Style($text.fontSize(10.0)),
                        );
                      },
                      width: 65.0,
                      backgroundColor: Colors.green.shade50,
                      borderColor: Colors.green.shade400,
                      enabledBorderColor: Colors.green.shade300,
                      focusedBorderColor: Colors.green.shade600,
                      errorBorderColor: Colors.red.shade400,
                    ),
                    channelValueEditorContainerBuilder:
                        (
                          context,
                          textField,
                          controller,
                          dimensionLabel,
                          dimensionIndex,
                        ) {
                          return Container(
                            width: 60,
                            padding: const EdgeInsets.all(2),
                            decoration: BoxDecoration(
                              border: Border.all(color: Colors.blue.shade300),
                              borderRadius: BorderRadius.circular(4),
                            ),
                            child: Column(
                              mainAxisSize: MainAxisSize.min,
                              children: [
                                Text(
                                  dimensionLabel,
                                  style: TextStyle(
                                    fontSize: 10,
                                    color: Colors.blue.shade600,
                                  ),
                                ),
                                textField,
                              ],
                            ),
                          );
                        },
                  ),
                ),

                Positioned(
                  top: 8,
                  left: 8,
                  child: Row(
                    children: [
                      TimelineZoomControl(timelineController: _controller),
                      SizedBox(width: 8),
                      TimelineSkipControl(timelineController: _controller),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
12
likes
115
points
280
downloads

Publisher

verified publishernick-fisher.com

Weekly Downloads

A Flutter package for creating keyframe-based timelines for 2D/3D animations, video editing, etc.

Repository (GitHub)

Documentation

API reference

License

unknown (license)

Dependencies

flutter, logging, mix, phosphor_flutter, uuid, vector_math

More

Packages that depend on flutter_keyframe_timeline