Unverified 提交 5f6bf2eb authored 作者: Rithesh's avatar Rithesh 提交者: GitHub

Merge pull request #61 from SachinGanesh/invisible_image

Support Inheriting App theme for Invisible Widgets, #54
差异被折叠。
...@@ -14,6 +14,11 @@ class MyApp extends StatelessWidget { ...@@ -14,6 +14,11 @@ class MyApp extends StatelessWidget {
return MaterialApp( return MaterialApp(
title: 'Flutter Demo', title: 'Flutter Demo',
theme: ThemeData( theme: ThemeData(
textTheme: TextTheme(
headline6: TextStyle(
color: Colors.yellow,
fontSize: 50,
)),
// This is the theme of your application. // This is the theme of your application.
// //
// Try running your application with "flutter run". You'll see the // Try running your application with "flutter run". You'll see the
...@@ -98,15 +103,21 @@ class _MyHomePageState extends State<MyHomePage> { ...@@ -98,15 +103,21 @@ class _MyHomePageState extends State<MyHomePage> {
'Capture An Invisible Widget', 'Capture An Invisible Widget',
), ),
onPressed: () { onPressed: () {
var container = Container(
padding: const EdgeInsets.all(30.0),
decoration: BoxDecoration(
border: Border.all(color: Colors.blueAccent, width: 5.0),
color: Colors.redAccent,
),
child: Text(
"This is an invisible widget",
style: Theme.of(context).textTheme.headline6,
));
screenshotController screenshotController
.captureFromWidget(Container( .captureFromWidget(
padding: const EdgeInsets.all(30.0), InheritedTheme.captureAll(
decoration: BoxDecoration( context, Material(child: container)),
border: delay: Duration(seconds: 1))
Border.all(color: Colors.blueAccent, width: 5.0),
color: Colors.redAccent,
),
child: Text("This is an invisible widget")))
.then((capturedImage) { .then((capturedImage) {
ShowCapturedWidget(context, capturedImage); ShowCapturedWidget(context, capturedImage);
}); });
......
...@@ -36,8 +36,8 @@ flutter: ...@@ -36,8 +36,8 @@ flutter:
# the material Icons class. # the material Icons class.
uses-material-design: true uses-material-design: true
# To add assets to your application, add an assets section, like this: # To add assets to your application, add an assets section, like this:
# assets: assets:
# - images/a_dot_burr.jpeg - assets/images/
# - images/a_dot_ham.jpeg # - images/a_dot_ham.jpeg
# An image asset can refer to one or more resolution-specific "variants", see # An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware. # https://flutter.io/assets-and-images/#resolution-aware.
......
...@@ -2,6 +2,7 @@ library screenshot; ...@@ -2,6 +2,7 @@ library screenshot;
// import 'dart:io'; // import 'dart:io';
import 'dart:async'; import 'dart:async';
import 'dart:developer';
import 'dart:typed_data'; import 'dart:typed_data';
import 'src/platform_specific/file_manager/file_manager.dart'; import 'src/platform_specific/file_manager/file_manager.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
...@@ -65,14 +66,13 @@ class ScreenshotController { ...@@ -65,14 +66,13 @@ class ScreenshotController {
//Delay is required. See Issue https://github.com/flutter/flutter/issues/22308 //Delay is required. See Issue https://github.com/flutter/flutter/issues/22308
return new Future.delayed(delay, () async { return new Future.delayed(delay, () async {
try { try {
var findRenderObject = this var findRenderObject =
._containerKey this._containerKey.currentContext?.findRenderObject();
.currentContext if (findRenderObject == null) {
?.findRenderObject(); return null;
if(findRenderObject==null){ }
return null; RenderRepaintBoundary boundary =
} findRenderObject as RenderRepaintBoundary;
RenderRepaintBoundary boundary = findRenderObject as RenderRepaintBoundary;
BuildContext? context = _containerKey.currentContext; BuildContext? context = _containerKey.currentContext;
if (pixelRatio == null) { if (pixelRatio == null) {
if (context != null) if (context != null)
...@@ -86,14 +86,45 @@ class ScreenshotController { ...@@ -86,14 +86,45 @@ class ScreenshotController {
}); });
} }
Future<Uint8List> captureFromWidget(Widget widget, ///
{Duration delay: const Duration(milliseconds: 20), double? pixelRatio,}) async { /// Value for [delay] should increase with widget tree size. Prefered value is 1 seconds
///
///[context] parameter is used to Inherit App Theme and MediaQuery data.
///
///
///
Future<Uint8List> captureFromWidget(
Widget widget, {
Duration delay: const Duration(seconds: 1),
double? pixelRatio,
BuildContext? context,
}) async {
///
///Retry counter
///
int retryCounter = 3;
bool isDirty = false;
Widget child = widget;
if (context != null) {
///
///Inherit Theme and MediaQuery of app
///
///
child = InheritedTheme.captureAll(
context,
MediaQuery(data: MediaQuery.of(context), child: child),
);
}
final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary(); final RenderRepaintBoundary repaintBoundary = RenderRepaintBoundary();
Size logicalSize = ui.window.physicalSize / ui.window.devicePixelRatio; Size logicalSize = ui.window.physicalSize / ui.window.devicePixelRatio;
Size imageSize = ui.window.physicalSize; Size imageSize = ui.window.physicalSize;
assert(logicalSize.aspectRatio.toPrecision(5) == imageSize.aspectRatio.toPrecision(5)); assert(logicalSize.aspectRatio.toPrecision(5) ==
imageSize.aspectRatio.toPrecision(5));
final RenderView renderView = RenderView( final RenderView renderView = RenderView(
window: ui.window, window: ui.window,
...@@ -101,38 +132,87 @@ class ScreenshotController { ...@@ -101,38 +132,87 @@ class ScreenshotController {
alignment: Alignment.center, child: repaintBoundary), alignment: Alignment.center, child: repaintBoundary),
configuration: ViewConfiguration( configuration: ViewConfiguration(
size: logicalSize, size: logicalSize,
devicePixelRatio: 1.0, devicePixelRatio: pixelRatio ?? 1.0,
), ),
); );
final PipelineOwner pipelineOwner = PipelineOwner(); final PipelineOwner pipelineOwner = PipelineOwner();
final BuildOwner buildOwner = BuildOwner(focusManager: FocusManager()); final BuildOwner buildOwner = BuildOwner(
focusManager: FocusManager(),
onBuildScheduled: () {
///
///current render is dirty, mark it.
///
isDirty = true;
});
pipelineOwner.rootNode = renderView; pipelineOwner.rootNode = renderView;
renderView.prepareInitialFrame(); renderView.prepareInitialFrame();
final RenderObjectToWidgetElement<RenderBox> rootElement = final RenderObjectToWidgetElement<RenderBox> rootElement =
RenderObjectToWidgetAdapter<RenderBox>( RenderObjectToWidgetAdapter<RenderBox>(
container: repaintBoundary, container: repaintBoundary,
child: Directionality( child: Directionality(
textDirection: TextDirection.ltr, textDirection: TextDirection.ltr,
child: widget, child: child,
), )).attachToRenderTree(
).attachToRenderTree(buildOwner); buildOwner,
);
buildOwner.buildScope(rootElement); ////
///Render Widget
await Future.delayed(delay); ///
///
buildOwner.buildScope(rootElement); buildOwner.buildScope(rootElement,);
buildOwner.finalizeTree(); buildOwner.finalizeTree();
pipelineOwner.flushLayout(); pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits(); pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint(); pipelineOwner.flushPaint();
final ui.Image image = await repaintBoundary.toImage( ui.Image? image;
pixelRatio: pixelRatio ?? (imageSize.width / logicalSize.width));
do {
///
///Reset the dirty flag
///
///
isDirty = false;
image = await repaintBoundary.toImage(
pixelRatio: pixelRatio ?? (imageSize.width / logicalSize.width));
///
///This delay shoud inceases with Widget tree Size
///
await Future.delayed(delay);
///
///Check does this require rebuild
///
///
if (isDirty) {
///
///Previous capture has been updated, re-render again.
///
///
buildOwner.buildScope(
rootElement,
);
buildOwner.finalizeTree();
pipelineOwner.flushLayout();
pipelineOwner.flushCompositingBits();
pipelineOwner.flushPaint();
}
retryCounter--;
///
///retry untill capture is successfull
///
} while (isDirty && retryCounter >= 0);
final ByteData? byteData = final ByteData? byteData =
await image.toByteData(format: ui.ImageByteFormat.png); await image.toByteData(format: ui.ImageByteFormat.png);
...@@ -173,7 +253,6 @@ class ScreenshotState extends State<Screenshot> with TickerProviderStateMixin { ...@@ -173,7 +253,6 @@ class ScreenshotState extends State<Screenshot> with TickerProviderStateMixin {
} }
} }
extension Ex on double { extension Ex on double {
double toPrecision(int n) => double.parse(toStringAsFixed(n)); double toPrecision(int n) => double.parse(toStringAsFixed(n));
} }
\ No newline at end of file
...@@ -7,7 +7,7 @@ packages: ...@@ -7,7 +7,7 @@ packages:
name: async name: async
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "2.6.1" version: "2.5.0"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
...@@ -92,7 +92,7 @@ packages: ...@@ -92,7 +92,7 @@ packages:
name: source_span name: source_span
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "1.8.1" version: "1.8.0"
stack_trace: stack_trace:
dependency: transitive dependency: transitive
description: description:
...@@ -127,7 +127,7 @@ packages: ...@@ -127,7 +127,7 @@ packages:
name: test_api name: test_api
url: "https://pub.dartlang.org" url: "https://pub.dartlang.org"
source: hosted source: hosted
version: "0.3.0" version: "0.2.19"
typed_data: typed_data:
dependency: transitive dependency: transitive
description: description:
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论