Skip to content

Commit e712491

Browse files
committed
💄 Add exposure point widget.
1 parent e40dab6 commit e712491

File tree

3 files changed

+225
-14
lines changed

3 files changed

+225
-14
lines changed
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
///
2+
/// [Author] Alex (https://github.com/AlexV525)
3+
/// [Date] 2021-01-09 18:33
4+
///
5+
import 'package:flutter/material.dart';
6+
7+
class TweenAnimationBuilder2<A, B> extends StatelessWidget {
8+
const TweenAnimationBuilder2({
9+
Key key,
10+
@required this.firstTween,
11+
@required this.secondTween,
12+
@required this.builder,
13+
this.firstTweenDuration = kThemeAnimationDuration,
14+
this.secondTweenDuration = kThemeAnimationDuration,
15+
this.firstTweenCurve = Curves.linear,
16+
this.secondTweenCurve = Curves.linear,
17+
}) : assert(firstTween != null),
18+
assert(secondTween != null),
19+
assert(builder != null),
20+
assert(firstTweenDuration != null),
21+
assert(secondTweenDuration != null),
22+
assert(firstTweenCurve != null),
23+
assert(secondTweenCurve != null),
24+
super(key: key);
25+
26+
final Tween<A> firstTween;
27+
final Tween<B> secondTween;
28+
final Duration firstTweenDuration;
29+
final Duration secondTweenDuration;
30+
final Curve firstTweenCurve;
31+
final Curve secondTweenCurve;
32+
final Widget Function(BuildContext, A, B) builder;
33+
34+
@override
35+
Widget build(BuildContext context) {
36+
return TweenAnimationBuilder<A>(
37+
tween: firstTween,
38+
curve: firstTweenCurve,
39+
duration: firstTweenDuration,
40+
builder: (__, A first, _) => TweenAnimationBuilder<B>(
41+
tween: secondTween,
42+
curve: secondTweenCurve,
43+
duration: secondTweenDuration,
44+
builder: (_, B second, __) => builder(context, first, second),
45+
),
46+
);
47+
}
48+
}

lib/src/widget/camera_picker.dart

Lines changed: 18 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import '../widget/circular_progress_bar.dart';
1616

1717
import 'builder/slide_page_transition_builder.dart';
1818
import 'camera_picker_viewer.dart';
19+
import 'exposure_point_widget.dart';
1920

2021
const Duration _kRouteDuration = Duration(milliseconds: 300);
2122

@@ -759,7 +760,8 @@ class CameraPickerState extends State<CameraPicker>
759760
/// 用户手动设置的曝光点的区域显示
760761
Widget get _focusingAreaWidget {
761762
Widget _buildFromPoint(Offset point) {
762-
const double _width = 100;
763+
final double _width = Screens.width / 5;
764+
763765
final double _effectiveLeft = math.min(
764766
Screens.width - _width,
765767
math.max(0, point.dx - _width / 2),
@@ -768,23 +770,13 @@ class CameraPickerState extends State<CameraPicker>
768770
Screens.height - _width,
769771
math.max(0, point.dy - _width / 2),
770772
);
773+
771774
return Positioned(
772775
left: _effectiveLeft,
773776
top: _effectiveTop,
774777
width: _width,
775778
height: _width,
776-
child: TweenAnimationBuilder<double>(
777-
tween: Tween<double>(begin: 0, end: 1),
778-
duration: kThemeAnimationDuration,
779-
builder: (__, double v, _) => Opacity(
780-
opacity: v,
781-
child: DecoratedBox(
782-
decoration: BoxDecoration(
783-
border: Border.all(color: theme.iconTheme.color, width: 2),
784-
),
785-
),
786-
),
787-
),
779+
child: ExposurePointWidget(key: ValueKey<int>(currentTimeStamp)),
788780
);
789781
}
790782

@@ -799,6 +791,18 @@ class CameraPickerState extends State<CameraPicker>
799791
);
800792
}
801793

794+
/// The [GestureDetector] widget for setting exposure poing manually.
795+
/// 用于手动设置曝光点的 [GestureDetector]
796+
Widget _exposureDetectorWidget(BuildContext context) {
797+
return Positioned.fill(
798+
child: GestureDetector(
799+
onTapDown: setExposurePoint,
800+
behavior: HitTestBehavior.translucent,
801+
child: const SizedBox.expand(),
802+
),
803+
);
804+
}
805+
802806
Widget _cameraPreview(BuildContext context) {
803807
assert(controller != null);
804808

@@ -808,7 +812,6 @@ class CameraPickerState extends State<CameraPicker>
808812
child: GestureDetector(
809813
onScaleStart: _handleScaleStart,
810814
onScaleUpdate: _handleScaleUpdate,
811-
onTapDown: setExposurePoint,
812815
onDoubleTap: switchCameras,
813816
child: CameraPreview(controller),
814817
),
@@ -886,6 +889,7 @@ class CameraPickerState extends State<CameraPicker>
886889
),
887890
),
888891
),
892+
_exposureDetectorWidget(context),
889893
SafeArea(
890894
child: Padding(
891895
padding: const EdgeInsets.only(bottom: 20.0),
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
///
2+
/// [Author] Alex (https://github.com/AlexV525)
3+
/// [Date] 2021-01-09 18:43
4+
///
5+
import 'dart:math' as math;
6+
7+
import 'package:flutter/material.dart';
8+
9+
import 'builder/tween_animation_builder_2.dart';
10+
11+
class ExposurePointWidget extends StatelessWidget {
12+
const ExposurePointWidget({
13+
Key key,
14+
this.size = 90,
15+
}) : super(key: key);
16+
17+
final double size;
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
return TweenAnimationBuilder2<double, double>(
22+
firstTween: Tween<double>(begin: 0, end: 1),
23+
secondTween: Tween<double>(begin: 1.5, end: 1),
24+
secondTweenCurve: Curves.easeOutBack,
25+
secondTweenDuration: const Duration(milliseconds: 400),
26+
builder: (_, double opacity, double scale) => Opacity(
27+
opacity: opacity,
28+
child: Transform.scale(
29+
scale: scale,
30+
child: SizedBox.fromSize(
31+
size: Size.square(size),
32+
child: CustomPaint(
33+
painter: ExposurePointPainter(size: size),
34+
),
35+
),
36+
),
37+
),
38+
);
39+
}
40+
}
41+
42+
/// A [CustomPaint] that draws the exposure point with four arcs and one circle.
43+
/// 包含了四条弧及一个圆的曝光点绘制
44+
class ExposurePointPainter extends CustomPainter {
45+
const ExposurePointPainter({
46+
@required this.size,
47+
this.radius = 2,
48+
this.strokeWidth = 2,
49+
this.color = Colors.white,
50+
}) : assert(size != null),
51+
assert(size > 0);
52+
53+
final double size;
54+
final double radius;
55+
final double strokeWidth;
56+
final Color color;
57+
58+
@override
59+
void paint(Canvas canvas, Size size) {
60+
final Size _dividedSize = size / 3;
61+
final Paint _paint = Paint()
62+
..style = PaintingStyle.stroke
63+
..color = color
64+
..strokeWidth = strokeWidth;
65+
66+
canvas
67+
// 左上角组弧
68+
..drawLine(Offset(radius, 0), Offset(_dividedSize.width, 0), _paint)
69+
..drawArc(
70+
Rect.fromCenter(
71+
center: Offset(radius, radius),
72+
width: radius * 2,
73+
height: radius * 2,
74+
),
75+
-math.pi,
76+
math.pi / 2,
77+
false,
78+
_paint,
79+
)
80+
..drawLine(Offset(0, _dividedSize.height), Offset(0, radius), _paint)
81+
// 右上角组弧
82+
..drawLine(
83+
Offset(_dividedSize.width * 2, 0),
84+
Offset(size.width - radius, 0),
85+
_paint,
86+
)
87+
..drawArc(
88+
Rect.fromCenter(
89+
center: Offset(size.width - radius, radius),
90+
width: radius * 2,
91+
height: radius * 2,
92+
),
93+
-math.pi / 2,
94+
math.pi / 2,
95+
false,
96+
_paint,
97+
)
98+
..drawLine(
99+
Offset(size.width, radius),
100+
Offset(size.width, _dividedSize.height),
101+
_paint,
102+
)
103+
// 右下角组弧
104+
..drawLine(
105+
Offset(size.width, _dividedSize.height * 2),
106+
Offset(size.width, size.height - radius),
107+
_paint,
108+
)
109+
..drawArc(
110+
Rect.fromCenter(
111+
center: Offset(size.width - radius, size.height - radius),
112+
width: radius * 2,
113+
height: radius * 2,
114+
),
115+
0,
116+
math.pi / 2,
117+
false,
118+
_paint,
119+
)
120+
..drawLine(
121+
Offset(size.height - radius, size.height),
122+
Offset(size.height - _dividedSize.width, size.height),
123+
_paint,
124+
)
125+
// 左下角组弧
126+
..drawLine(
127+
Offset(_dividedSize.width, size.height),
128+
Offset(radius, size.height),
129+
_paint,
130+
)
131+
..drawArc(
132+
Rect.fromCenter(
133+
center: Offset(radius, size.height - radius),
134+
width: radius * 2,
135+
height: radius * 2,
136+
),
137+
math.pi / 2,
138+
math.pi / 2,
139+
false,
140+
_paint,
141+
)
142+
..drawLine(
143+
Offset(0, size.height - radius),
144+
Offset(0, size.height - _dividedSize.height),
145+
_paint,
146+
)
147+
// 中心圆
148+
..drawCircle(
149+
Offset(size.width / 2, size.height / 2),
150+
_dividedSize.width / 2,
151+
_paint,
152+
);
153+
}
154+
155+
@override
156+
bool shouldRepaint(ExposurePointPainter oldDelegate) {
157+
return oldDelegate.size != size || oldDelegate.radius != radius;
158+
}
159+
}

0 commit comments

Comments
 (0)