Files
moodiary/lib/components/base/button.dart
住京华 b8ce69011c feat(video): use ffmpeg as video backend (#241)
* chore(deps): update dependencies

* chore(deps): update dependencies

* fix: update ios and macos platform version

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* feat: add argon2 support

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* chore(deps): update deps

* feat(video): use ffmpeg as video backend

* fix(video): simplify video view invocation and improve button interaction

* feat(button): add customizable color option to PageBackButton

[skip ci]
2025-05-19 00:18:51 +08:00

124 lines
3.2 KiB
Dart

import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:moodiary/l10n/l10n.dart';
class FrostedGlassButton extends StatelessWidget {
final Widget child;
final double size;
final Function()? onPressed;
const FrostedGlassButton({
super.key,
required this.child,
required this.size,
this.onPressed,
});
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: onPressed,
child: Container(
width: size,
height: size,
clipBehavior: Clip.hardEdge,
decoration: const ShapeDecoration(shape: CircleBorder()),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10),
child: Center(child: child),
),
),
);
}
}
class MultiFabLayoutDelegate extends MultiChildLayoutDelegate {
MultiFabLayoutDelegate({required this.controller, required this.layoutIds})
: super(relayout: controller);
final Animation<double> controller;
final List<int> layoutIds;
static const double mainButtonHeight = 56.0;
static const double childButtonHeight = 46.0;
static const double buttonSpacing = 8.0;
@override
void performLayout(Size size) {
final animationValue = controller.value;
// 布局主按钮
if (hasChild(0)) {
final mainButtonSize = layoutChild(
0,
BoxConstraints.loose(const Size(mainButtonHeight, mainButtonHeight)),
);
positionChild(
0,
Offset(
size.width - mainButtonSize.width,
size.height - mainButtonSize.height,
),
);
}
// 布局子按钮
for (int i = 1; i < layoutIds.length; i++) {
final layoutId = layoutIds[i];
if (hasChild(layoutId)) {
final childButtonSize = layoutChild(
layoutId,
BoxConstraints(maxWidth: size.width, maxHeight: childButtonHeight),
);
// 动态计算子按钮的垂直偏移量
final dyOffset =
(mainButtonHeight + buttonSpacing) +
(i - 1) * (childButtonSize.height + buttonSpacing) * animationValue;
// 动态计算水平偏移量,使子按钮完全隐藏在主按钮底部时的水平位置对齐
final dxOffset =
(mainButtonHeight - childButtonSize.width) /
2 *
(1 - animationValue);
positionChild(
layoutId,
Offset(
size.width - mainButtonHeight + dxOffset,
size.height - mainButtonHeight - dyOffset,
),
);
}
}
}
@override
bool shouldRelayout(MultiFabLayoutDelegate oldDelegate) {
return oldDelegate.controller != controller ||
oldDelegate.layoutIds != layoutIds;
}
}
class PageBackButton extends StatelessWidget {
final Function()? onBack;
final Color? color;
const PageBackButton({super.key, this.onBack, this.color});
@override
Widget build(BuildContext context) {
return Center(
child: IconButton(
onPressed: onBack ?? Get.back,
icon: const Icon(Icons.arrow_back_rounded),
color: color ?? context.theme.colorScheme.onSurface,
tooltip: context.l10n.back,
),
);
}
}