详情里的对话框切换动画ok
This commit is contained in:
@@ -41,8 +41,8 @@ class _AvatarNameState extends State<AvatarName> {
|
||||
setState(() {
|
||||
_isEdit = false;
|
||||
});
|
||||
var res = await updateUserInfoApi(name: value);
|
||||
widget.onUpdate(res);
|
||||
widget.onUpdate(UserInfo(name: value));
|
||||
await updateUserInfoApi(name: value);
|
||||
}
|
||||
|
||||
///选择图片
|
||||
|
||||
@@ -8,9 +8,8 @@ import 'package:remixicon/remixicon.dart';
|
||||
|
||||
import '../widgets/edit_desc_dialog.dart';
|
||||
import 'widgets/avatar_card.dart';
|
||||
import 'widgets/plan_item.dart';
|
||||
import 'widgets/coach_message.dart';
|
||||
import 'widgets/scroll_box.dart';
|
||||
import 'widgets/suggested.dart';
|
||||
|
||||
class PlanDetailPage extends StatefulWidget {
|
||||
final String? id;
|
||||
@@ -55,7 +54,11 @@ class _PlanDetailPageState extends State<PlanDetailPage> {
|
||||
Widget build(BuildContext context) {
|
||||
return ChangeNotifierProvider<PlanDetailStore>(
|
||||
create: (_) {
|
||||
return PlanDetailStore();
|
||||
return PlanDetailStore(
|
||||
planId: widget.id.toString(),
|
||||
planContent: widget.planName ?? "",
|
||||
showRoleTalk: widget.planName == null,
|
||||
);
|
||||
},
|
||||
child: CupertinoPageScaffold(
|
||||
backgroundColor: Colors.white,
|
||||
@@ -108,31 +111,32 @@ class _PlanDetailPageState extends State<PlanDetailPage> {
|
||||
decoration: shadowDecoration,
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(height: 20),
|
||||
),
|
||||
SliverList.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return PlanItem(
|
||||
showEdit: _isEdit,
|
||||
title: "测试 ${index + 1}",
|
||||
desc: "测测 ${index + 1}",
|
||||
onDelete: (id) {},
|
||||
);
|
||||
},
|
||||
itemCount: 10,
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SuggestedTitle(),
|
||||
),
|
||||
SliverList.builder(
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return SuggestedItem(
|
||||
title: "测试",
|
||||
);
|
||||
},
|
||||
itemCount: 5,
|
||||
),
|
||||
CoachMessage(),
|
||||
// SliverToBoxAdapter(
|
||||
// child: SizedBox(height: 20),
|
||||
// ),
|
||||
// SliverList.builder(
|
||||
// itemBuilder: (BuildContext context, int index) {
|
||||
// return PlanItem(
|
||||
// showEdit: _isEdit,
|
||||
// title: "测试 ${index + 1}",
|
||||
// desc: "测测 ${index + 1}",
|
||||
// onDelete: (id) {},
|
||||
// );
|
||||
// },
|
||||
// itemCount: 10,
|
||||
// ),
|
||||
// SliverToBoxAdapter(
|
||||
// child: SuggestedTitle(),
|
||||
// ),
|
||||
// SliverList.builder(
|
||||
// itemBuilder: (BuildContext context, int index) {
|
||||
// return SuggestedItem(
|
||||
// title: "测试",
|
||||
// );
|
||||
// },
|
||||
// itemCount: 5,
|
||||
// ),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
@@ -1,6 +1,15 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:plan/api/dto/plan_detail_dto.dart';
|
||||
import 'package:plan/api/endpoints/plan_api.dart';
|
||||
|
||||
class PlanDetailStore extends ChangeNotifier {
|
||||
///构造函数
|
||||
PlanDetailStore({
|
||||
this.planContent = "",
|
||||
this.planId = "",
|
||||
bool showRoleTalk = true,
|
||||
}) : _showRoleTalk = showRoleTalk;
|
||||
|
||||
///角色话语是否显示
|
||||
bool _showRoleTalk = true;
|
||||
|
||||
@@ -10,4 +19,19 @@ class PlanDetailStore extends ChangeNotifier {
|
||||
_showRoleTalk = value;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
///计划的内容,只有新增时才会有
|
||||
String planContent = "";
|
||||
|
||||
///计划id
|
||||
String planId = "";
|
||||
|
||||
///计划详情
|
||||
PlanDetailDto planDetail = PlanDetailDto();
|
||||
|
||||
///创建计划
|
||||
void createPlan() async {
|
||||
var id = await initPlanApi(planContent, 1);
|
||||
planId = id.toString();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
import '../viewmodel/plan_detail_store.dart';
|
||||
|
||||
class AvatarCard extends StatefulWidget {
|
||||
const AvatarCard({super.key});
|
||||
|
||||
@@ -9,23 +12,35 @@ class AvatarCard extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _AvatarCardState extends State<AvatarCard> with SingleTickerProviderStateMixin {
|
||||
bool _isShow = false;
|
||||
|
||||
late AnimationController _controller;
|
||||
late Animation<double> _animation;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_controller = AnimationController(
|
||||
vsync: this,
|
||||
duration: Duration(milliseconds: 400),
|
||||
duration: Duration(milliseconds: 300),
|
||||
);
|
||||
_animation = Tween<double>(begin: 0, end: 1).animate(
|
||||
CurvedAnimation(
|
||||
parent: _controller,
|
||||
curve: Curves.easeInOut,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
super.dispose();
|
||||
_controller.dispose();
|
||||
}
|
||||
|
||||
void _toggleShow() {
|
||||
var store = context.read<PlanDetailStore>();
|
||||
setState(() {
|
||||
_isShow = !_isShow;
|
||||
if (_isShow) {
|
||||
store.showRoleTalk = !store.showRoleTalk;
|
||||
if (store.showRoleTalk) {
|
||||
_controller.forward();
|
||||
} else {
|
||||
_controller.reverse();
|
||||
@@ -41,11 +56,10 @@ class _AvatarCardState extends State<AvatarCard> with SingleTickerProviderStateM
|
||||
offset: Offset(0, 50),
|
||||
child: Column(
|
||||
children: [
|
||||
Transform(
|
||||
alignment: Alignment.center,
|
||||
transform: Matrix4.identity()..translate(40.0, 40.0)..scale(0.2),
|
||||
BothSizeTransition(
|
||||
animation: _animation,
|
||||
offset: Offset(50, 50),
|
||||
child: Container(
|
||||
color: Colors.red,
|
||||
padding: EdgeInsets.only(bottom: 10),
|
||||
child: InkWell(
|
||||
onTap: _toggleShow,
|
||||
@@ -84,10 +98,14 @@ class _AvatarCardState extends State<AvatarCard> with SingleTickerProviderStateM
|
||||
Positioned(
|
||||
top: 20,
|
||||
child: Transform.translate(
|
||||
offset: Offset(50, -10),
|
||||
offset: Offset(40, -10),
|
||||
child: GestureDetector(
|
||||
onTap: _toggleShow,
|
||||
child: Icon(RemixIcons.message_2_line, size: 26),
|
||||
child: BothSizeTransition(
|
||||
animation: ReverseAnimation(_animation),
|
||||
offset: Offset(-50, -50),
|
||||
child: Icon(RemixIcons.message_2_line),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -101,6 +119,7 @@ class _AvatarCardState extends State<AvatarCard> with SingleTickerProviderStateM
|
||||
}
|
||||
}
|
||||
|
||||
///聊天气泡三角
|
||||
class BubblePainter extends CustomPainter {
|
||||
@override
|
||||
void paint(Canvas canvas, Size size) {
|
||||
@@ -135,3 +154,47 @@ class BubblePainter extends CustomPainter {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
///缩放动画
|
||||
class BothSizeTransition extends StatelessWidget {
|
||||
final Animation<double> animation;
|
||||
final Widget child;
|
||||
final Offset offset;
|
||||
|
||||
const BothSizeTransition({
|
||||
super.key,
|
||||
required this.animation,
|
||||
this.offset = Offset.zero,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return AnimatedBuilder(
|
||||
animation: animation,
|
||||
builder: (_, child) {
|
||||
return Align(
|
||||
alignment: Alignment(0.7, 1),
|
||||
child: Opacity(
|
||||
opacity: animation.value,
|
||||
child: Transform(
|
||||
alignment: Alignment(0.5, 1),
|
||||
transform: Matrix4.identity()
|
||||
..translate(
|
||||
offset.dx * (1 - animation.value),
|
||||
offset.dy * (1 - animation.value),
|
||||
)
|
||||
..scale(animation.value, 1.0),
|
||||
child: SizeTransition(
|
||||
sizeFactor: animation,
|
||||
axis: Axis.vertical,
|
||||
child: child,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
37
lib/page/plan/detail/widgets/coach_message.dart
Normal file
37
lib/page/plan/detail/widgets/coach_message.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:plan/page/plan/detail/viewmodel/plan_detail_store.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
class CoachMessage extends StatefulWidget {
|
||||
const CoachMessage({super.key});
|
||||
|
||||
@override
|
||||
State<CoachMessage> createState() => _CoachMessageState();
|
||||
}
|
||||
|
||||
class _CoachMessageState extends State<CoachMessage> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
var store = context.read<PlanDetailStore>();
|
||||
if (store.planContent.isEmpty) {
|
||||
return SliverToBoxAdapter();
|
||||
}
|
||||
return SliverToBoxAdapter(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"你的教练正在拆分",
|
||||
style: Theme.of(context).textTheme.bodyMedium,
|
||||
),
|
||||
Text(
|
||||
'"${store.planContent}"',
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user