시리얼라이저블 스타일 시스템을 사용하여 사용자 정의가 가능하고 애니메이션 효과를 가진 위젯을 생성할 수 있는 플러터 패키지입니다. 개발자는 색상, 크기, 투명도와 같은 시각적 속성을 구조화되고 재사용 가능한 형식으로 정의할 수 있으며, 시간에 따라 애니메이션 처리할 수 있습니다. 이 접근 방식은 스타일과 위젯 로직을 분리함으로써 UI 개발을 단순화하며, 복잡한 애니메이션과 동적 테마를 관리하기 쉽게 만듭니다. 이 패키지는 일관된 디자인 패턴을 갖춘 반응형이고 상호작용 가능한 사용자 인터페이스를 구축하는 데 특히 유용합니다.
사용 사례
애니메이션된 UI 컴포넌트 만들기
테마 전환 구현
재사용 가능한 스타일링 위젯 만들기
인터랙티브 대시보드 설계
레이아웃 변경 애니메이션
동적 시각 상태 관리
주요 기능
시리얼라이저 가능한 스타일 정의
내장 애니메이션 지원
재사용 가능하고 조합 가능한 스타일
여러 시각적 속성 지원
기존 위젯과의 간편한 통합
경량이고 성능이 뛰어남
적합한 대상
Flutter를 사용하는 UI 디자이너
애니메이션 인터페이스를 구축하는 개발자
앱 간에 일관된 스타일링이 필요한 팀
동적 테마 전환을 필요로 하는 앱
원활한 사용자 상호작용에 중점을 둔 프로젝트
고려 사항
제한된 플랫폼별 사용자 지정
시리얼라이제이션에 대한 이해 필요
간단한 정적 위젯에 오버헤드를 추가할 수 있습니다
복잡하고 애니메이션 처리된 UI에 가장 적합
매우 플랫폼 네이티브한 디자인에는 적합하지 않음
원본 README
연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.
animated_styled_widget
Powerful styling, serialization, animation, and custom components all in one place.
Current features of this package:
Let you use a serializable style to design highly customizable StyledContainer widget.
Implicit animations with the AnimatedStyledContainer widget.
Explicit animations (local/global, timed/scroll based) with the ExplicitAnimatedStyledContainer widget.
Styled Components: StyledButton, StyledToggleButtons, StyledSwitch, StyledRadio, StyledCheckbox, StyledSlider. Your app don't need to look like Material.
Many features of this package is inspired by CSS or follows CSS specifications. If you are familiar with CSS, this package should be even easier to use.
What is the Style class?
The style class is a collection of UI data classes.
It currently supports the following properties:
The Dimension type is from the dimension package. It supports both absolute and relative units. You can also combine/nest min/max/clamp functions on Dimension. You can think of this as a supercharged combination of SizedBox and FractionallySizedBox.
ShapeShadow and MorphableShapeBorder are from the morphable_shape package. ShapeShadow supports inset shadows and gradient filling, in addition to what BoxShadow supports. MorpableShapeBorder supports many commonly used shapes, shape morphing, and many more. Check out fluttershape.com for an interactive demo.
DynamicTextStyle lets you define font size, letter spacing etc using absolute/relative values. 300% font size means 3 times the default font size.
SmoothMatrix4 is similar to Matrix4 but ensures that all the transformations can be smoothly animated. It also allows you to use Dimension as translation distances to adapt to different screen sizes.
After you have defined a style, use the StyledContainer widget:
var widget=StyledContainer(
style: style,
child: ...
);
Implicit Animation
Almost every property in the Style class can be animated. See the
following GIF for a demonstration:
Just replace the StyledContainer with AnimatedStyledContainer and provide a duration and a curve. Notice the animation can not only be triggered by providing a new style/style map, but also by window resizing/screen rotation as long as you provide the appropriate styles.
Styled Components
Styled components is a selection of UI components with simple logic like button, radio button, toggle button, switch, etc. The Material implementation of those components is great, but the customization ability is quited limited. There are many other packages out there for even more customization, but the customizability is typically limited to color, border radius, sizing, etc. This package gives you much more.
The Material components animates according to its internal MaterialState like hovered, pressed, selected, etc. So does the styled components. Lets look at the StyleButton's constructor as an example:
A button can be in one of the four states: idle, hovered, pressed, disabled. You need to provide the four corresponding styles. Notice only the idle(default) style is required, and the other three will be set to this style if not provided. You can also specify the duration and animation curve for transitioning between different states. The child parameter is the child widget of this button. But you can also provide a builder which can access the internal state of the button:
Above are six different styled buttons that works great with/without a cursor.
StyledCheckbox is very similar to StyledButton except for that the pressedStyle parameter is replaced by selectedStyle, as checkbox (and other toggleable components) cares about whether itself is selected (not pressed).
And then there's the StyledRadio:
And StyledToggleButtons:
Notice all those components follow the exact parameter naming schemes as the built-in ones except for the styling part.
The StyledSwitch and StyledSlider are a little tricker, as now the styling involves two components. For StyledSwitch, you need to provide styling for both the track and the thumb. And the thumb will be aligned to either the left ot right side of the track (if the switch is horizontal).
The StyledSlider need styling for the track and thumb as well, but you can also provide styling for the active track and tooltip.
The interface for the slider is not final, I may add more styling paramters in the future.
I have also implemented the StyledNavigationBar and StylePopupMenuButton. You can find demos of all those components in the example app.
The next step may be adding themeing capabilities to the styled components so that people.
Explicit Animation
Implicit animations are easy to use but can not achieve every effect we want. That's when the ExplicitAnimatedStyledContainer comes in:
You still provide an initial style to the widget, but then you use local/global animations to animate the widget’s style. Let’s first talk about the localAnimations:
When a trigger event happens(e.g. you tapped this widget), the corresponding MultiAnimationSequence is fired. A MultiAnimationSequence contains a sequences map:
where AnimationProperty is an enum class corresponding to every animatable property the Style class supports, and AnimationSequence is a list of generic values, durations, delays, and curves that tells us how a certain animation property is evolved. For example:
will delay 1 second, then animate the width from its current value to 100 px in 200ms, then to 50% screen width in 200ms. You can animate other properties using the same syntax.
The above mouse hover effect is achieved by writing:
You can have different durations and curves for mouse entering and exiting, and also for different style properties.
Now let's talk about other animation triggers. The AnimationTrigger.tap is easy to understand. The AnimationTrigger.visible is triggered when the widget becomes visible in the viewport (by using the visibility_detector package). The AnimationTrigger.scroll is triggered when the widget is inside a Scrollable (like a ListView). Then the widget will animate according to its position along the scroll direction:
The animation progress by default is calculated as shown in the figure above (if scrolled horizontally). But you can also make the animation start/end earlier or later using two percentage offsets.
Preset Animation
Now those MultiAnimationSequence stuff looks powerful, but also complicated to code. I’ve prepared some predefined animations for general usages. They are categorized into entrance, attention seeker, and exit. For example, one common entrance animation called SlideInAnimation is defined as:
You can configure the slide distance and direction, as well as duration, delay, curve, and control (whether the animation should play once or infinitely). Other predefined animations are:
Then every time the widget moves into the screen it will fade in (opacity from 0 to 1). Another feature of MultiAnimationSequence is the ability to merge or extend other MultiAnimationSequence. So you can do something like this:
Then the widget will both fade and slide in once it shows up in the viewport. If you use extend, the animation will play one after another. Preset animations make animations much easier to use while still offer you great flexibility.
Global Explicit Animations
If we want to stagger animations across different widgets, we can do that by providing global animations. A global animation contains a map between String and MultiAnimationSequence where the String is the identifier of a widget. You provide all the global animations you want to use in an animation pool. Then you can trigger a global animation like this:
The id does not need to be unique. You can have multiple widgets with the same id so they will all animate under the same global animation. Notice if a widget does not use global animations at all, there is no need for an id.
You can programmatically change the state of the animation by calling something like the following inside the child of a ExplicitAnimatedStyledContainer:
Classes involved in explicit animations also support serialization. You can basically create and store complex animated components in plain text and load them everywhere.