forked from lxm_flutter/FlutterUnit
curve 查看器
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
#storePassword=toly1994
|
||||
#keyPassword=toly1994328
|
||||
#keyAlias= king
|
||||
#storeFile=/Users/mac/Coder/files/key/toly1994.jks
|
||||
@@ -73,7 +73,7 @@ class AnimPainter extends CustomPainter {
|
||||
|
||||
if(points.values.length>0){
|
||||
canvas.drawLine(Offset(0, -points.values.last*step*10), Offset(280, -points.values.last*step*10), Paint()..color=Colors.purple);
|
||||
canvas.drawCircle(Offset(240, -points.values.last*step*10), 10, Paint()..color=Colors.orange);
|
||||
canvas.drawCircle(Offset(230, -points.values.last*step*10), 10, Paint()..color=Colors.orange);
|
||||
}
|
||||
|
||||
Path scalePath = Path();
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'dart:ui';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_unit/views/components/drop_selectable_widget.dart';
|
||||
|
||||
import 'anim_painter.dart';
|
||||
import 'point_data.dart';
|
||||
@@ -22,6 +23,50 @@ class _CurveAnimShowerState extends State<CurveAnimShower>
|
||||
|
||||
Animation<double> curveAnim;
|
||||
|
||||
Map<String, Curve> maps = {
|
||||
'bounceOut': Curves.bounceOut,
|
||||
'linear': Curves.linear,
|
||||
'decelerate': Curves.decelerate,
|
||||
'fastLinearToSlowEaseIn': Curves.fastLinearToSlowEaseIn,
|
||||
'ease': Curves.ease,
|
||||
'easeIn': Curves.easeIn,
|
||||
'easeInToLinear': Curves.easeInToLinear,
|
||||
'easeInSine': Curves.easeInSine,
|
||||
'easeInQuad': Curves.easeInQuad,
|
||||
'easeInCubic': Curves.easeInCubic,
|
||||
'easeInQuart': Curves.easeInQuart,
|
||||
'easeInQuint': Curves.easeInQuint,
|
||||
'easeInExpo': Curves.easeInExpo,
|
||||
'easeInCirc': Curves.easeInCirc,
|
||||
'easeInBack': Curves.easeInBack,
|
||||
'easeOut': Curves.easeOut,
|
||||
'linearToEaseOut': Curves.linearToEaseOut,
|
||||
'easeOutSine': Curves.easeOutSine,
|
||||
'easeOutQuad': Curves.easeOutQuad,
|
||||
'easeOutCubic': Curves.easeOutCubic,
|
||||
'easeOutQuart': Curves.easeOutQuart,
|
||||
'easeOutQuint': Curves.easeOutQuint,
|
||||
'easeOutExpo': Curves.easeOutExpo,
|
||||
'easeOutCirc': Curves.easeOutCirc,
|
||||
'easeOutBack': Curves.easeOutBack,
|
||||
'easeInOut': Curves.easeInOut,
|
||||
'easeInOutSine': Curves.easeInOutSine,
|
||||
'easeInOutQuad': Curves.easeInOutQuad,
|
||||
'easeInOutCubic': Curves.easeInOutCubic,
|
||||
'easeInOutQuart': Curves.easeInOutQuart,
|
||||
'easeInOutExpo': Curves.easeInOutExpo,
|
||||
'easeInOutQuint': Curves.easeInOutQuint,
|
||||
'easeInOutCirc': Curves.easeInOutCirc,
|
||||
'easeInOutBack': Curves.easeInOutBack,
|
||||
'fastOutSlowIn': Curves.fastOutSlowIn,
|
||||
'slowMiddle': Curves.slowMiddle,
|
||||
'bounceIn': Curves.bounceIn,
|
||||
'bounceInOut': Curves.bounceInOut,
|
||||
'elasticIn': Curves.elasticIn,
|
||||
'elasticOut': Curves.elasticOut,
|
||||
'elasticInOut': Curves.elasticInOut,
|
||||
};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
@@ -52,15 +97,35 @@ class _CurveAnimShowerState extends State<CurveAnimShower>
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: _startAnim,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(30.0),
|
||||
child: CustomPaint(
|
||||
painter: AnimPainter(points),
|
||||
size: const Size(
|
||||
200,
|
||||
200,
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: [
|
||||
Positioned(
|
||||
right: 5,
|
||||
top: 5,
|
||||
child: DropSelectableWidget(
|
||||
fontSize: 12,
|
||||
data: maps.keys.toList(),
|
||||
iconSize: 20,
|
||||
height: 25,
|
||||
width: 180,
|
||||
disableColor: Color(0xff1F425F),
|
||||
onDropSelected: (int index) async {
|
||||
curveAnim = CurvedAnimation(
|
||||
parent: _ctrl, curve: maps.values.toList()[index]);
|
||||
_startAnim();
|
||||
},
|
||||
)),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(30.0),
|
||||
child: CustomPaint(
|
||||
painter: AnimPainter(points),
|
||||
size: const Size(
|
||||
200,
|
||||
200,
|
||||
),
|
||||
)),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ class _DrawPathState extends State<DrawPath> with SingleTickerProviderStateMixin
|
||||
_controller = AnimationController(
|
||||
duration: const Duration(seconds: 15),
|
||||
vsync: this,
|
||||
)..repeat()
|
||||
;
|
||||
)..repeat();
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
199
lib/views/components/drop_selectable_widget.dart
Normal file
199
lib/views/components/drop_selectable_widget.dart
Normal file
@@ -0,0 +1,199 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
typedef OnDropSelected = void Function(int index);
|
||||
|
||||
class DropSelectableWidget extends StatefulWidget {
|
||||
final List<String> data;
|
||||
final OnDropSelected onDropSelected;
|
||||
final Color disableColor;
|
||||
final double iconSize;
|
||||
final double height;
|
||||
final double width;
|
||||
final double fontSize;
|
||||
|
||||
const DropSelectableWidget(
|
||||
{Key key,
|
||||
this.data = const [],
|
||||
this.onDropSelected,
|
||||
this.disableColor = Colors.black,
|
||||
this.iconSize = 24,
|
||||
this.height = 30,
|
||||
this.width = 200,
|
||||
this.fontSize = 14,
|
||||
})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
_DropSelectableWidgetState createState() => _DropSelectableWidgetState();
|
||||
}
|
||||
|
||||
class _DropSelectableWidgetState extends State<DropSelectableWidget>
|
||||
with SingleTickerProviderStateMixin {
|
||||
FocusNode _node;
|
||||
bool _focused = false;
|
||||
FocusAttachment _nodeAttachment;
|
||||
Color _color = Colors.white;
|
||||
OverlayEntry _overlayEntry;
|
||||
AnimationController _ctrl;
|
||||
Animation<double> animation;
|
||||
final LayerLink layerLink = LayerLink();
|
||||
|
||||
int _selectedIndex = 0;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
|
||||
_ctrl = AnimationController(
|
||||
vsync: this,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
);
|
||||
|
||||
animation = Tween<double>(begin: 0, end: pi).animate(_ctrl);
|
||||
_node = FocusNode()
|
||||
..addListener(() {
|
||||
if (_node.hasFocus != _focused) {
|
||||
if (!_focused) {
|
||||
_ctrl.forward();
|
||||
_showOverlay();
|
||||
} else {
|
||||
_hideOverlay();
|
||||
_ctrl.reverse();
|
||||
}
|
||||
setState(() {
|
||||
_focused = _node.hasFocus;
|
||||
});
|
||||
}
|
||||
});
|
||||
_nodeAttachment = _node.attach(context);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_node.dispose();
|
||||
_ctrl.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
_nodeAttachment.reparent();
|
||||
return GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTap: () {
|
||||
if (_focused) {
|
||||
_node.unfocus();
|
||||
} else {
|
||||
_node.requestFocus();
|
||||
}
|
||||
},
|
||||
child: CompositedTransformTarget(
|
||||
link: layerLink,
|
||||
child: buildTarget(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showOverlay() {
|
||||
_overlayEntry = _createOverlayEntry();
|
||||
Overlay.of(context).insert(_overlayEntry);
|
||||
}
|
||||
|
||||
void _hideOverlay() {
|
||||
_overlayEntry?.remove();
|
||||
}
|
||||
|
||||
Widget buildTarget() {
|
||||
return Container(
|
||||
width: widget.width,
|
||||
height: widget.height,
|
||||
padding: EdgeInsets.only(left: 10, right: 10),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: _focused ? Colors.blue : widget.disableColor,
|
||||
)),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
'${widget.data.isNotEmpty ? widget.data[_selectedIndex] : "暂无数据"}',style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: widget.fontSize
|
||||
),),
|
||||
AnimatedBuilder(
|
||||
animation: animation,
|
||||
builder: (_, child) => Transform.rotate(
|
||||
angle: animation.value,
|
||||
child: child,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.keyboard_arrow_down,
|
||||
size: widget.iconSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
OverlayEntry _createOverlayEntry() => OverlayEntry(
|
||||
builder: (BuildContext context) => UnconstrainedBox(
|
||||
child: CompositedTransformFollower(
|
||||
link: layerLink,
|
||||
targetAnchor: Alignment.bottomCenter,
|
||||
followerAnchor: Alignment.topCenter,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(top: 4.0),
|
||||
child: Material(
|
||||
shape: RoundedRectangleBorder(
|
||||
side: BorderSide.none,
|
||||
borderRadius: BorderRadius.all(Radius.circular(5))),
|
||||
elevation: 1,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(5),
|
||||
child: Container(
|
||||
height: 200,
|
||||
// alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xffDAE3FF),
|
||||
),
|
||||
// padding: const EdgeInsets.only(top: 5),
|
||||
width: widget.width,
|
||||
child: CupertinoScrollbar(
|
||||
child: ListView.builder(
|
||||
padding: EdgeInsets.zero,
|
||||
// shrinkWrap: true,
|
||||
itemCount: widget.data.length,
|
||||
itemBuilder: _buildItem),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _buildItem(BuildContext context, int index) {
|
||||
return Material(
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
if (_selectedIndex != index) widget.onDropSelected?.call(index);
|
||||
_selectedIndex = index;
|
||||
_overlayEntry.markNeedsBuild();
|
||||
_node.unfocus();
|
||||
},
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(8),
|
||||
color: index == _selectedIndex
|
||||
? Colors.blue.withOpacity(0.2)
|
||||
: Colors.transparent,
|
||||
child: Text('${widget.data[index]}',style: TextStyle(fontSize: widget.fontSize),)),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user