Add Ink.image clip examples (#93799)

This commit is contained in:
Markus Aksli 2021-12-17 12:54:14 +02:00 committed by GitHub
parent 25b37bab1e
commit 75e2470302
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 214 additions and 0 deletions

View 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,
),
),
),
),
),
),
);
}
}

View 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,
),
),
),
),
),
),
),
);
}
}

View 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);
});
}

View 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);
});
}

View file

@ -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,

View file

@ -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

View file

@ -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