diff --git a/examples/api/lib/widgets/magnifier/cupertino_magnifier.0.dart b/examples/api/lib/widgets/magnifier/cupertino_magnifier.0.dart new file mode 100644 index 0000000000..56a2ec5c3e --- /dev/null +++ b/examples/api/lib/widgets/magnifier/cupertino_magnifier.0.dart @@ -0,0 +1,78 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; + +/// Flutter code sample for [CupertinoMagnifier]. + +void main() => runApp(const CupertinoMagnifierApp()); + +class CupertinoMagnifierApp extends StatelessWidget { + const CupertinoMagnifierApp({super.key}); + + @override + Widget build(BuildContext context) { + return const CupertinoApp( + theme: CupertinoThemeData(brightness: Brightness.light), + home: CupertinoMagnifierExample(), + ); + } +} + +class CupertinoMagnifierExample extends StatefulWidget { + const CupertinoMagnifierExample({super.key}); + + @override + State createState() => _CupertinoMagnifierExampleState(); +} + +class _CupertinoMagnifierExampleState extends State { + static const double magnifierRadius = 50.0; + Offset dragGesturePosition = Offset.zero; + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: const CupertinoNavigationBar( + middle: Text('CupertinoMagnifier Sample'), + ), + child: Center( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('Drag on the logo!'), + RepaintBoundary( + child: Stack( + children: [ + GestureDetector( + onPanUpdate: (DragUpdateDetails details) { + setState(() { + dragGesturePosition = details.localPosition; + }); + }, + onPanDown: (DragDownDetails details) { + setState(() { + dragGesturePosition = details.localPosition; + }); + }, + child: const FlutterLogo(size: 200), + ), + Positioned( + left: dragGesturePosition.dx - magnifierRadius, + top: dragGesturePosition.dy - magnifierRadius, + child: const CupertinoMagnifier( + magnificationScale: 1.5, + borderRadius: BorderRadius.all(Radius.circular(magnifierRadius)), + additionalFocalPointOffset: Offset(0, -magnifierRadius), + ), + ) + ], + ), + ), + ], + ), + ), + ); + } +} diff --git a/examples/api/lib/widgets/magnifier/cupertino_text_magnifier.0.dart b/examples/api/lib/widgets/magnifier/cupertino_text_magnifier.0.dart new file mode 100644 index 0000000000..5f44cf9d40 --- /dev/null +++ b/examples/api/lib/widgets/magnifier/cupertino_text_magnifier.0.dart @@ -0,0 +1,60 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; + +/// Flutter code sample for [CupertinoTextMagnifier]. + +void main() => runApp(const CupertinoTextMagnifierApp()); + +class CupertinoTextMagnifierApp extends StatelessWidget { + const CupertinoTextMagnifierApp({super.key}); + + @override + Widget build(BuildContext context) { + return const CupertinoApp( + theme: CupertinoThemeData(brightness: Brightness.light), + home: CupertinoTextMagnifierExampleApp(), + ); + } +} + +class CupertinoTextMagnifierExampleApp extends StatefulWidget { + const CupertinoTextMagnifierExampleApp({ + super.key, + }); + + @override + State createState() => + _CupertinoTextMagnifierExampleAppState(); +} + +class _CupertinoTextMagnifierExampleAppState extends State { + final MagnifierController _controller = MagnifierController(); + + @override + Widget build(BuildContext context) { + return CupertinoPageScaffold( + navigationBar: const CupertinoNavigationBar( + middle: Text('CupertinoTextMagnifier Sample'), + ), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 48.0), + child: Center( + child: CupertinoTextField( + magnifierConfiguration: TextMagnifierConfiguration( + magnifierBuilder: (_, __, ValueNotifier magnifierInfo) { + return CupertinoTextMagnifier( + controller: _controller, + magnifierInfo: magnifierInfo, + ); + }, + ), + controller: TextEditingController(text: 'Hello world!'), + ), + ), + ), + ); + } +} diff --git a/examples/api/test/widgets/magnifier/cupertino_magnifier.0_test.dart b/examples/api/test/widgets/magnifier/cupertino_magnifier.0_test.dart new file mode 100644 index 0000000000..bbf0ee4312 --- /dev/null +++ b/examples/api/test/widgets/magnifier/cupertino_magnifier.0_test.dart @@ -0,0 +1,62 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_api_samples/widgets/magnifier/cupertino_magnifier.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + + testWidgets('CupertinoMagnifier must be visible', (WidgetTester tester) async { + await tester.pumpWidget(const example.CupertinoMagnifierApp()); + + final Finder cupertinoMagnifierWidget = find.byType(CupertinoMagnifier); + expect(cupertinoMagnifierWidget, findsOneWidget); + }); + + testWidgets('CupertinoMagnifier is not using the default value', (WidgetTester tester) async { + await tester.pumpWidget(const example.CupertinoMagnifierApp()); + expect( + tester.widget(find.byType(CupertinoMagnifier)), + isA().having( + (CupertinoMagnifier t) => t.magnificationScale, + 'magnificationScale', + 1.5, + ), + ); + }); + + testWidgets('should update CupertinoMagnifier position on drag', (WidgetTester tester) async { + await tester.pumpWidget(const example.CupertinoMagnifierApp()); + + Matcher isPositionedAt(Offset at) { + return isA().having( + (Positioned positioned) => Offset(positioned.left!, positioned.top!), + 'magnifier position', + at, + ); + } + + // Make sure magnifier is present. + final Finder positionedWidget = find.byType(Positioned); + final Widget positionedWidgetInTree = tester.widget(positionedWidget.first); + final Positioned oldConcretePositioned = positionedWidgetInTree as Positioned; + final Offset centerOfPositioned = tester.getCenter(positionedWidget.first); + + // Drag the magnifier and confirm its new position is expected. + const Offset dragDistance = Offset(10, 10); + final Offset updatedPositioned = Offset( + oldConcretePositioned.left ?? 0.0 + 10.0, + oldConcretePositioned.top ?? 0.0 + 10.0, + ); + + await tester.dragFrom(centerOfPositioned, dragDistance); + await tester.pump(); + expect( + positionedWidgetInTree, + isPositionedAt(updatedPositioned), + ); + }); +} diff --git a/examples/api/test/widgets/magnifier/cupertino_text_magnifier.0_test.dart b/examples/api/test/widgets/magnifier/cupertino_text_magnifier.0_test.dart new file mode 100644 index 0000000000..cd849684db --- /dev/null +++ b/examples/api/test/widgets/magnifier/cupertino_text_magnifier.0_test.dart @@ -0,0 +1,20 @@ +// Copyright 2014 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:flutter/cupertino.dart'; +import 'package:flutter_api_samples/widgets/magnifier/cupertino_text_magnifier.0.dart' + as example; +import 'package:flutter_test/flutter_test.dart'; + +void main() { + testWidgets('CupertinoTextMagnifier must be visible after longPress', (WidgetTester tester) async { + await tester.pumpWidget(const example.CupertinoTextMagnifierApp()); + + final Finder cupertinoTextFieldWidget = find.byType(CupertinoTextField); + await tester.longPress(cupertinoTextFieldWidget); + + final Finder cupertinoTextMagnifierWidget = find.byType(CupertinoTextMagnifier); + expect(cupertinoTextMagnifierWidget, findsOneWidget); + }); +} diff --git a/packages/flutter/lib/src/cupertino/magnifier.dart b/packages/flutter/lib/src/cupertino/magnifier.dart index 2227595276..cf749f5ca6 100644 --- a/packages/flutter/lib/src/cupertino/magnifier.dart +++ b/packages/flutter/lib/src/cupertino/magnifier.dart @@ -11,6 +11,12 @@ import 'package:flutter/widgets.dart'; /// A [CupertinoMagnifier] used for magnifying text in cases where a user's /// finger may be blocking the point of interest, like a selection handle. /// +/// {@tool dartpad} +/// This sample demonstrates how to use [CupertinoTextMagnifier]. +/// +/// ** See code in examples/api/lib/widgets/magnifier/cupertino_text_magnifier.0.dart ** +/// {@end-tool} +/// /// Delegates styling to [CupertinoMagnifier] with its position depending on /// [magnifierInfo]. /// @@ -225,6 +231,12 @@ class _CupertinoTextMagnifierState extends State /// A [RawMagnifier] used for magnifying text in cases where a user's /// finger may be blocking the point of interest, like a selection handle. /// +/// {@tool dartpad} +/// This sample demonstrates how to use [CupertinoMagnifier]. +/// +/// ** See code in examples/api/lib/widgets/magnifier/cupertino_magnifier.0.dart ** +/// {@end-tool} +/// /// [CupertinoMagnifier] is a wrapper around [RawMagnifier] that handles styling /// and transitions. ///