flutter_keyframe_timeline 0.0.1-pre2 copy "flutter_keyframe_timeline: ^0.0.1-pre2" to clipboard
flutter_keyframe_timeline: ^0.0.1-pre2 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';

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 = TimelineControllerImpl(
      _objectHolder.animatableObjects,
      _objectHolder,
    );
    _objectHolder.setTimelineController(_controller);
  }

  @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(
                        textColor: Colors.green.shade700,
                        fontSize: 12.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),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ],
      ),
    );
  }
}
15
likes
0
points
13
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)
View/report issues

License

unknown (license)

Dependencies

flutter, logging, mix, phosphor_flutter, uuid, vector_math

More

Packages that depend on flutter_keyframe_timeline