mirror of https://github.com/flutter/samples.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
149 lines
3.7 KiB
149 lines
3.7 KiB
6 years ago
|
// Copyright 2018 The Flutter team. All rights reserved.
|
||
|
// Use of this source code is governed by a BSD-style license that can be
|
||
|
// found in the LICENSE file.
|
||
|
|
||
1 year ago
|
import 'dart:ui' as ui;
|
||
6 years ago
|
|
||
|
import 'package:flutter/cupertino.dart';
|
||
3 months ago
|
import '../styles.dart';
|
||
6 years ago
|
|
||
6 years ago
|
/// Partially overlays and then blurs its child's background.
|
||
6 years ago
|
class FrostedBox extends StatelessWidget {
|
||
|
const FrostedBox({
|
||
|
this.child,
|
||
3 years ago
|
super.key,
|
||
|
});
|
||
6 years ago
|
|
||
3 years ago
|
final Widget? child;
|
||
6 years ago
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return BackdropFilter(
|
||
1 year ago
|
filter: ui.ImageFilter.blur(sigmaX: 10, sigmaY: 10),
|
||
6 years ago
|
child: DecoratedBox(
|
||
4 years ago
|
decoration: const BoxDecoration(
|
||
6 years ago
|
color: Styles.frostedBackground,
|
||
|
),
|
||
|
child: child,
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// An Icon that implicitly animates changes to its color.
|
||
|
class ColorChangingIcon extends ImplicitlyAnimatedWidget {
|
||
|
const ColorChangingIcon(
|
||
|
this.icon, {
|
||
|
this.color = CupertinoColors.black,
|
||
|
this.size,
|
||
3 years ago
|
required super.duration,
|
||
|
super.key,
|
||
|
});
|
||
6 years ago
|
|
||
|
final Color color;
|
||
|
|
||
|
final IconData icon;
|
||
|
|
||
3 years ago
|
final double? size;
|
||
6 years ago
|
|
||
|
@override
|
||
3 years ago
|
AnimatedWidgetBaseState<ColorChangingIcon> createState() =>
|
||
|
_ColorChangingIconState();
|
||
6 years ago
|
}
|
||
|
|
||
|
class _ColorChangingIconState
|
||
|
extends AnimatedWidgetBaseState<ColorChangingIcon> {
|
||
3 years ago
|
ColorTween? _colorTween;
|
||
6 years ago
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return Icon(
|
||
|
widget.icon,
|
||
6 years ago
|
semanticLabel: 'Close button',
|
||
6 years ago
|
size: widget.size,
|
||
|
color: _colorTween?.evaluate(animation),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
@override
|
||
5 years ago
|
void forEachTween(TweenVisitor<dynamic> visitor) {
|
||
6 years ago
|
_colorTween = visitor(
|
||
|
_colorTween,
|
||
|
widget.color,
|
||
3 years ago
|
(dynamic value) => ColorTween(begin: value as Color?),
|
||
|
) as ColorTween?;
|
||
6 years ago
|
}
|
||
|
}
|
||
|
|
||
3 months ago
|
/// A close button that invokes a callback when pressed.
|
||
|
class CloseButton extends _DetailPageButton {
|
||
|
const CloseButton(VoidCallback onPressed, {super.key})
|
||
|
: super(onPressed, CupertinoIcons.chevron_back);
|
||
|
}
|
||
|
|
||
|
/// A share button that invokes a callback when pressed.
|
||
|
class ShareButton extends _DetailPageButton {
|
||
|
const ShareButton(VoidCallback onPressed, {super.key})
|
||
|
: super(onPressed, CupertinoIcons.share);
|
||
|
}
|
||
|
|
||
|
/// A favorite button that invokes a callback when pressed.
|
||
|
class FavoriteButton extends _DetailPageButton {
|
||
|
const FavoriteButton(VoidCallback onPressed, bool isFavorite, {super.key})
|
||
|
: super(
|
||
|
onPressed,
|
||
|
isFavorite ? CupertinoIcons.heart_fill : CupertinoIcons.heart,
|
||
|
);
|
||
|
}
|
||
|
|
||
|
class _DetailPageButton extends StatefulWidget {
|
||
|
const _DetailPageButton(this.onPressed, this.icon, {super.key});
|
||
6 years ago
|
|
||
|
final VoidCallback onPressed;
|
||
3 months ago
|
final IconData icon;
|
||
6 years ago
|
|
||
|
@override
|
||
3 months ago
|
State<_DetailPageButton> createState() => _DetailPageButtonState();
|
||
6 years ago
|
}
|
||
|
|
||
3 months ago
|
class _DetailPageButtonState extends State<_DetailPageButton> {
|
||
6 years ago
|
bool tapInProgress = false;
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
return GestureDetector(
|
||
|
onTapDown: (details) {
|
||
|
setState(() => tapInProgress = true);
|
||
|
},
|
||
|
onTapUp: (details) {
|
||
|
setState(() => tapInProgress = false);
|
||
|
widget.onPressed();
|
||
|
},
|
||
|
onTapCancel: () {
|
||
|
setState(() => tapInProgress = false);
|
||
|
},
|
||
|
child: ClipOval(
|
||
|
child: FrostedBox(
|
||
|
child: Container(
|
||
|
width: 30,
|
||
|
height: 30,
|
||
|
decoration: BoxDecoration(
|
||
|
borderRadius: BorderRadius.circular(15),
|
||
|
),
|
||
|
child: Center(
|
||
|
child: ColorChangingIcon(
|
||
3 months ago
|
widget.icon,
|
||
4 years ago
|
duration: const Duration(milliseconds: 300),
|
||
6 years ago
|
color: tapInProgress
|
||
|
? Styles.closeButtonPressed
|
||
|
: Styles.closeButtonUnpressed,
|
||
|
size: 20,
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|