Zero, preface,
FlutterUnit is an open source App for Flutter compilation and guidance that has been maintained for a long time. If you haven’t eaten Flutter yet, please refer to the Total Compilation: FlutterUnit Guide to Eating Flutter Open Source
Welcome to Star. Open source address: click me
FlutterUnit. Apk download | Download FlutterUnit for MAC | Github repository address |
---|---|---|
The solution to the Flutter Unit chapter will examine some of the implementation points of the project.
A lot of friends ask me, how do you do code folding panel? “ExpansionTile”? Do ExpansionTile will up and down the cable, very ugly, so I did not use ExpansionTile folding effect of core code in the source code: the components/project/widget_node_panel dart
. | . | . |
---|---|---|
I. Implementation scheme of AnimatedCrossFade
The core component is AnimatedCrossFade, which may not be used by many people, but is a very powerful component
You can search through the FlutterUnit app.
. | . | . | . |
---|---|---|---|
1. Basic usage of AnimatedCrossFade
AnimatedCrossFade
It can contain two componentsfirstChild
andsecondChild
- Enumeration state quantities can be specified
crossFadeState
, has two valuesshowFirst
andshowSecond
- When the state quantity changes, either the first or the second is displayed depending on the state. Fades in and out when switching.
- You can specify the animation duration. The following are
200ms,400ms,600ms
The effect of:
200ms | 400ms | 600ms |
---|---|---|
class TolyExpandTile extends StatefulWidget {
@override
_TolyExpandTileState createState() => _TolyExpandTileState();
}
class _TolyExpandTileState extends State<TolyExpandTile>
with SingleTickerProviderStateMixin {
var _crossFadeState = CrossFadeState.showFirst;
bool get isFirst => _crossFadeState == CrossFadeState.showFirst;
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(20),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Expanded(
child: Container(),
),
GestureDetector(
onTap: _togglePanel,
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Icon(Icons.code),
))
],
),
_buildPanel()
],
),
);
}
void_togglePanel() { setState(() { _crossFadeState = ! isFirst ? CrossFadeState.showFirst : CrossFadeState.showSecond; }); } Widget _buildPanel() => AnimatedCrossFade( firstCurve: Curves.easeInCirc, secondCurve: Curves.easeInToLinear, firstChild: Container(), secondChild: Container( height:150,
color: Colors.blue,
),
duration: Duration(milliseconds: 300),
crossFadeState: _crossFadeState,
);
}
Copy the code
And 2.ToggleRotate
combination
ToggleRotate is a very small component package I wrote, toGGle_rotate: ^0.0.5
For automatic rotation and rotation of components when clicked. See article: Toggle_rotate
45 degrees | 90 degrees |
---|---|
The Flutter Unit is basically code panel folding based on this approach.
– | – |
---|---|
Second, the magic changeExpansionTile
Implementation scheme
ExpansionTile’s source code was broadcast live on “B” last Saturday at 8:30 p.m.
As long as you understand the source code, in fact, magic change is so easy. You can also modify the _kExpand constant in the border to control the animation length.
Note: all magic changes to the source code, need to copy out, new file, do not directly change the source code.
The following code is processed and can be used directly.
Before going to edge | After go to edge |
---|---|
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
const Duration _kExpand = Duration(milliseconds: 200);
class NoBorderExpansionTile extends StatefulWidget {
const ExpansionTile({
Key key,
this.leading,
@required this.title,
this.subtitle,
this.backgroundColor,
this.onExpansionChanged,
this.children = const <Widget>[],
this.trailing,
this.initiallyExpanded = false,}) :assert(initiallyExpanded ! =null),
super(key: key);
final Widget leading;
final Widget title;
final Widget subtitle;
final ValueChanged<bool> onExpansionChanged;
final List<Widget> children;
final Color backgroundColor;
final Widget trailing;
final bool initiallyExpanded;
@override
_ExpansionTileState createState() => _ExpansionTileState();
}
class _ExpansionTileState extends State<ExpansionTile> with SingleTickerProviderStateMixin {
static final Animatable<double> _easeOutTween = CurveTween(curve: Curves.easeOut);
static final Animatable<double> _easeInTween = CurveTween(curve: Curves.easeIn);
static final Animatable<double> _halfTween = Tween<double>(begin: 0.0, end: 0.5);
final ColorTween _borderColorTween = ColorTween();
final ColorTween _headerColorTween = ColorTween();
final ColorTween _iconColorTween = ColorTween();
final ColorTween _backgroundColorTween = ColorTween();
AnimationController _controller;
Animation<double> _iconTurns;
Animation<double> _heightFactor;
Animation<Color> _borderColor;
Animation<Color> _headerColor;
Animation<Color> _iconColor;
Animation<Color> _backgroundColor;
bool _isExpanded = false;
@override
void initState() {
super.initState();
_controller = AnimationController(duration: _kExpand, vsync: this); _heightFactor = _controller.drive(_easeInTween); _iconTurns = _controller.drive(_halfTween.chain(_easeInTween)); _borderColor = _controller.drive(_borderColorTween.chain(_easeOutTween)); _headerColor = _controller.drive(_headerColorTween.chain(_easeInTween)); _iconColor = _controller.drive(_iconColorTween.chain(_easeInTween)); _backgroundColor = _controller.drive(_backgroundColorTween.chain(_easeOutTween)); _isExpanded = PageStorage.of(context)? .readState(context) ?? widget.initiallyExpanded;if (_isExpanded)
_controller.value = 1.0;
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
void_handleTap() { setState(() { _isExpanded = ! _isExpanded;if (_isExpanded) {
_controller.forward();
} else {
_controller.reverse().then<void> ((void value) {
if(! mounted)return;
setState(() {
// Rebuild without widget.children.}); }); } PageStorage.of(context)? .writeState(context, _isExpanded); });if(widget.onExpansionChanged ! =null)
widget.onExpansionChanged(_isExpanded);
}
Widget _buildChildren(BuildContext context, Widget child) {
return Container(
color: _backgroundColor.value ?? Colors.transparent,
child: Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
ListTileTheme.merge(
iconColor: _iconColor.value,
textColor: _headerColor.value,
child: ListTile(
onTap: _handleTap,
leading: widget.leading,
title: widget.title,
subtitle: widget.subtitle,
trailing: widget.trailing ?? RotationTransition(
turns: _iconTurns,
child: const Icon(Icons.expand_more),
),
),
),
ClipRect(
child: Align(
heightFactor: _heightFactor.value,
child: child,
),
),
],
),
);
}
@override
void didChangeDependencies() {
finalThemeData theme = Theme.of(context); _borderColorTween .. end = theme.dividerColor; _headerColorTween .. begin = theme.textTheme.subhead.color .. end = theme.accentColor; _iconColorTween .. begin = theme.unselectedWidgetColor .. end = theme.accentColor; _backgroundColorTween .. end = widget.backgroundColor;super.didChangeDependencies();
}
@override
Widget build(BuildContext context) {
final boolclosed = ! _isExpanded && _controller.isDismissed;return AnimatedBuilder(
animation: _controller.view,
builder: _buildChildren,
child: closed ? null: Column(children: widget.children), ); }}Copy the code
On the livestream, ExpansionTile’s core implementation will be through ClipRect and Align
That’s right, the magical Align again, whose heightFactor controls the score of heights.
ClipRect(
child: Align(
alignment: Alignment.topCenter,
heightFactor: _heightFactor.value,
child: child,
),
),
Copy the code
The default is to start in the middle | Alignment: alignment. TopCenter |
---|---|
So you can control where it comes from. Or that sentence: source code in hand, the world I have. Nothing to see the implementation of the source code, is very helpful to yourself. This is also the original intention between live source code, do not ask what learning method, learn debug, and then force yourself to see the source code is the fastest way to grow.
The cable | wireless |
---|---|
The end of the
Welcome to Star and pay attention to the development of FlutterUnit. Let’s join hands and become a member of Unit.
In addition, I have a Flutter wechat communication group. You are welcome to join and discuss Flutter issues together. I look forward to exchanging ideas with you.
@ZhangFengjietele 2020.04.21 not allowed transfer
My official number: King of programming contact me – email :[email protected] – wechat :zdl1994328 ~ END ~