mirror of
https://github.com/flutter/flutter
synced 2024-10-12 11:12:54 +00:00
Add Ink.image clip examples (#93799)
This commit is contained in:
parent
25b37bab1e
commit
75e2470302
55
examples/api/lib/material/ink/ink.image_clip.0.dart
Normal file
55
examples/api/lib/material/ink/ink.image_clip.0.dart
Normal file
|
@ -0,0 +1,55 @@
|
|||
// 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.
|
||||
|
||||
// Flutter code sample for Image.frameBuilder
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MaterialApp(
|
||||
title: 'Flutter Code Sample',
|
||||
home: Scaffold(
|
||||
appBar: AppBar(title: const Text('Flutter Code Sample')),
|
||||
body: const Center(
|
||||
child: MyStatelessWidget(
|
||||
image: NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg'),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
class MyStatelessWidget extends StatelessWidget {
|
||||
const MyStatelessWidget({Key? key, required this.image}) : super(key: key);
|
||||
|
||||
final ImageProvider image;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Ink.image(
|
||||
fit: BoxFit.fill,
|
||||
width: 300,
|
||||
height: 300,
|
||||
image: image,
|
||||
child: InkWell(
|
||||
onTap: () {/* ... */},
|
||||
child: const Align(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text(
|
||||
'PUFFIN',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
57
examples/api/lib/material/ink/ink.image_clip.1.dart
Normal file
57
examples/api/lib/material/ink/ink.image_clip.1.dart
Normal file
|
@ -0,0 +1,57 @@
|
|||
// 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.
|
||||
|
||||
// Flutter code sample for Image.frameBuilder
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
void main() {
|
||||
runApp(MaterialApp(
|
||||
title: 'Flutter Code Sample',
|
||||
home: Scaffold(
|
||||
appBar: AppBar(title: const Text('Flutter Code Sample')),
|
||||
body: const Center(
|
||||
child: MyStatelessWidget(
|
||||
image: NetworkImage('https://flutter.github.io/assets-for-api-docs/assets/widgets/puffin.jpg'),
|
||||
),
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
||||
class MyStatelessWidget extends StatelessWidget {
|
||||
const MyStatelessWidget({Key? key, required this.image}) : super(key: key);
|
||||
|
||||
final ImageProvider image;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ClipRRect(
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Material(
|
||||
child: Ink.image(
|
||||
fit: BoxFit.fill,
|
||||
width: 300,
|
||||
height: 300,
|
||||
image: image,
|
||||
child: InkWell(
|
||||
onTap: () {/* ... */},
|
||||
child: const Align(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(10.0),
|
||||
child: Text(
|
||||
'PUFFIN',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w900,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
34
examples/api/test/material/ink/ink.image_clip.0.test.dart
Normal file
34
examples/api/test/material/ink/ink.image_clip.0.test.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
// 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 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_api_samples/material/ink/ink.image_clip.0.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
const List<int> kTransparentImage = <int>[
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
|
||||
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,
|
||||
0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D,
|
||||
0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
||||
];
|
||||
|
||||
testWidgets('Ink ancestor material is not clipped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: example.MyStatelessWidget(
|
||||
image: MemoryImage(Uint8List.fromList(kTransparentImage)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final Finder inkMaterialFinder = find.ancestor(of: find.byType(Ink), matching: find.byType(Material));
|
||||
expect(find.ancestor(of: inkMaterialFinder, matching: find.byType(ClipRRect)), findsNothing);
|
||||
});
|
||||
}
|
34
examples/api/test/material/ink/ink.image_clip.1.test.dart
Normal file
34
examples/api/test/material/ink/ink.image_clip.1.test.dart
Normal file
|
@ -0,0 +1,34 @@
|
|||
// 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 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_api_samples/material/ink/ink.image_clip.1.dart' as example;
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
|
||||
void main() {
|
||||
const List<int> kTransparentImage = <int>[
|
||||
0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A, 0x00, 0x00, 0x00, 0x0D, 0x49,
|
||||
0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x08, 0x06,
|
||||
0x00, 0x00, 0x00, 0x1F, 0x15, 0xC4, 0x89, 0x00, 0x00, 0x00, 0x0A, 0x49, 0x44,
|
||||
0x41, 0x54, 0x78, 0x9C, 0x63, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00, 0x01, 0x0D,
|
||||
0x0A, 0x2D, 0xB4, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, 0x4E, 0x44, 0xAE,
|
||||
];
|
||||
|
||||
testWidgets('Ink ancestor material is clipped', (WidgetTester tester) async {
|
||||
await tester.pumpWidget(
|
||||
MaterialApp(
|
||||
home: Scaffold(
|
||||
body: example.MyStatelessWidget(
|
||||
image: MemoryImage(Uint8List.fromList(kTransparentImage)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
final Finder inkMaterialFinder = find.ancestor(of: find.byType(Ink), matching: find.byType(Material));
|
||||
expect(find.ancestor(of: inkMaterialFinder, matching: find.byType(ClipRRect)), findsOneWidget);
|
||||
});
|
||||
}
|
|
@ -104,6 +104,27 @@ import 'material.dart';
|
|||
/// ```
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// What to do if you want to clip this [Ink.image]?
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// Wrapping the [Ink] in a clipping widget directly will not work since the
|
||||
/// [Material] it will be printed on is responsible for clipping.
|
||||
///
|
||||
/// In this example the image is not being clipped as expected. This is because
|
||||
/// it is being rendered onto the Scaffold body Material, which isn't wrapped in
|
||||
/// the [ClipRRect].
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/ink/ink.image_clip.0.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// {@tool dartpad}
|
||||
/// One solution would be to deliberately wrap the [Ink.image] in a [Material].
|
||||
/// This makes sure the Material that the image is painted on is also responsible
|
||||
/// for clipping said content.
|
||||
///
|
||||
/// ** See code in examples/api/lib/material/ink/ink.image_clip.1.dart **
|
||||
/// {@end-tool}
|
||||
///
|
||||
/// See also:
|
||||
///
|
||||
/// * [Container], a more generic form of this widget which paints itself,
|
||||
|
|
|
@ -1159,6 +1159,18 @@ class _InkResponseState extends State<_InkResponseStateWidget>
|
|||
/// ancestor to the ink well). The [MaterialType.transparency] material
|
||||
/// kind can be used for this purpose.
|
||||
///
|
||||
/// ### InkWell isn't clipping properly
|
||||
///
|
||||
/// If you want to clip an InkWell or any [Ink] widgets you need to keep in mind
|
||||
/// that the [Material] that the Ink will be printed on is responsible for clipping.
|
||||
/// This means you can't wrap the [Ink] widget in a clipping widget directly,
|
||||
/// since this will leave the [Material] not clipped (and by extension the printed
|
||||
/// [Ink] widgets as well).
|
||||
///
|
||||
/// An easy solution is to deliberately wrap the [Ink] widgets you want to clip
|
||||
/// in a [Material], and wrap that in a clipping widget instead. See [Ink] for
|
||||
/// an example.
|
||||
///
|
||||
/// ### The ink splashes don't track the size of an animated container
|
||||
/// If the size of an InkWell's [Material] ancestor changes while the InkWell's
|
||||
/// splashes are expanding, you may notice that the splashes aren't clipped
|
||||
|
|
|
@ -91,6 +91,7 @@ abstract class MaterialInkController {
|
|||
/// 1. Clipping: If [clipBehavior] is not [Clip.none], Material clips its widget
|
||||
/// sub-tree to the shape specified by [shape], [type], and [borderRadius].
|
||||
/// By default, [clipBehavior] is [Clip.none] for performance considerations.
|
||||
/// See [Ink] for an example of how this affects clipping [Ink] widgets.
|
||||
/// 2. Elevation: Material elevates its widget sub-tree on the Z axis by
|
||||
/// [elevation] pixels, and draws the appropriate shadow.
|
||||
/// 3. Ink effects: Material shows ink effects implemented by [InkFeature]s
|
||||
|
|
Loading…
Reference in a new issue