Help please, I have a WebView screen on which I display the site. This site adapts to the width of the mobile phone and reduces the font. Can I somehow increase the font?
body: Container(
child: WebView(
initialUrl: url,
javascriptMode: JavascriptMode.unrestricted,
),
),
Android is smart enough to identify html code without with viewport, but IOS does not. You have to explicitly set viewport to mobile device, like you make webapp responsive to mobile devices.
It's better to wrap annotation to render correctly.
This is what you need exactly to your code:
<!DOCTYPE html><html><head><meta name="viewport" content="width=device-width, initial-scale=1.0"></head><!--rest of your html-->
You can use the flutter_inappwebview plugin (I'm the author) to set custom text size/zoom to the whole web page.
On Android, we can use InAppWebViewSettings.textZoom property.
On iOS, we need to use JavaScript and set the text-size-adjust CSS property.
Here is a code example using the current latest version 6 available (6.0.0-beta.18):
import 'dart:collection';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
const kInitialTextSize = 100;
const kTextSizePlaceholder = 'TEXT_SIZE_PLACEHOLDER';
const kTextSizeSourceJS = """
window.addEventListener('DOMContentLoaded', function(event) {
document.body.style.textSizeAdjust = '$kTextSizePlaceholder%';
document.body.style.webkitTextSizeAdjust = '$kTextSizePlaceholder%';
});
""";
final textSizeUserScript = UserScript(
source: kTextSizeSourceJS.replaceAll(kTextSizePlaceholder, '$kInitialTextSize'),
injectionTime: UserScriptInjectionTime.AT_DOCUMENT_START);
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb &&
kDebugMode &&
defaultTargetPlatform == TargetPlatform.android) {
await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);
}
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
int textSize = kInitialTextSize;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Custom Text Size"),
actions: [
IconButton(
onPressed: () async {
textSize++;
await updateTextSize(textSize);
},
icon: const Icon(Icons.add)),
IconButton(
onPressed: () async {
textSize--;
await updateTextSize(textSize);
},
icon: const Icon(Icons.remove)),
TextButton(
onPressed: () async {
textSize = kInitialTextSize;
await updateTextSize(textSize);
},
child: const Text(
'Reset',
style: TextStyle(color: Colors.white),
),
),
],
),
body: Column(children: <Widget>[
Expanded(
child: InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri("https://github.com/flutter")),
initialUserScripts: UnmodifiableListView(
!kIsWeb && defaultTargetPlatform == TargetPlatform.android
? []
: [textSizeUserScript]),
initialSettings: InAppWebViewSettings(textZoom: textSize),
onWebViewCreated: (controller) async {
webViewController = controller;
},
),
),
]));
}
updateTextSize(int textSize) async {
if (!kIsWeb && defaultTargetPlatform == TargetPlatform.android) {
await webViewController?.setSettings(
settings: InAppWebViewSettings(textZoom: textSize));
} else {
// update current text size
await webViewController?.evaluateJavascript(source: """
document.body.style.textSizeAdjust = '$textSize%';
document.body.style.webkitTextSizeAdjust = '$textSize%';
""");
// update the User Script for the next page load
await webViewController?.removeUserScript(userScript: textSizeUserScript);
textSizeUserScript.source =
kTextSizeSourceJS.replaceAll(kTextSizePlaceholder, '$textSize');
await webViewController?.addUserScript(userScript: textSizeUserScript);
}
}
}
Full project code example is available at https://github.com/pichillilorenzo/flutter_inappwebview_examples/tree/main/custom_text_size
Related
Hello I am new to flutter but I am somehow created a webview app. Now I want some additional features like show custom page when url not loaded, or when web page not found. I have searched google a lot but not able to find any solution.
My code:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../main.dart';
class Outlook extends StatefulWidget {
const Outlook({Key? key}) : super(key: key);
#override
State<Outlook> createState() => _OutlookState();
}
class _OutlookState extends State<Outlook> {
bool isLoading=true;
late WebViewController _controller;
final _key = UniqueKey();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Outlook"),
backgroundColor: const Color(0xff6200EE),
centerTitle: true,
),
body: Stack(
children: <Widget>[
WebView(
key: _key,
initialUrl: "https://outlook.office.com/",
javascriptMode: JavascriptMode.unrestricted,
onWebResourceError: (WebResourceError error) {
_controller.loadUrl("http://connectivitycheck.gstatic.com/generate_204");
},
onPageFinished: (finish) {
setState(() {
isLoading = false;
});
},
),
isLoading ? const Center( child: CircularProgressIndicator(),)
: Stack(),
],
),
drawer: const Navigation(),
);
}
}
To manage and display a custom error page, you can try my plugin flutter_inappwebview.
Use the InAppWebView.onReceivedError event to handle web page loading errors and the InAppWebView.onReceivedHttpError event to handle HTTP errors.
Also, on Android, you should set the InAppWebViewSettings.disableDefaultErrorPage property to true.
Here is an example using the current latest version 6 (6.0.0-beta.18):
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
if (!kIsWeb &&
kDebugMode &&
defaultTargetPlatform == TargetPlatform.android) {
await InAppWebViewController.setWebContentsDebuggingEnabled(kDebugMode);
}
runApp(const MaterialApp(home: MyApp()));
}
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final GlobalKey webViewKey = GlobalKey();
InAppWebViewController? webViewController;
handleClick(int item) {
switch (item) {
case 0:
webViewController?.loadUrl(
urlRequest:
URLRequest(url: WebUri('https://www.notawebsite..com/')));
break;
case 1:
webViewController?.loadUrl(
urlRequest: URLRequest(url: WebUri('https://google.com/404')));
break;
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Custom Error Page"),
actions: [
PopupMenuButton<int>(
onSelected: (item) => handleClick(item),
itemBuilder: (context) => [
const PopupMenuItem<int>(
value: 0, child: Text('Test web page loading error')),
const PopupMenuItem<int>(
value: 1, child: Text('Test 404 error')),
],
),
],
),
body: Column(children: <Widget>[
Expanded(
child: InAppWebView(
key: webViewKey,
initialUrlRequest:
URLRequest(url: WebUri('https://github.com/flutter')),
initialSettings:
InAppWebViewSettings(disableDefaultErrorPage: true),
onWebViewCreated: (controller) {
webViewController = controller;
},
onReceivedHttpError: (controller, request, errorResponse) async {
// Handle HTTP errors here
var isForMainFrame = request.isForMainFrame ?? false;
if (!isForMainFrame) {
return;
}
final snackBar = SnackBar(
content: Text(
'HTTP error for URL: ${request.url} with Status: ${errorResponse.statusCode} ${errorResponse.reasonPhrase ?? ''}'),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
},
onReceivedError: (controller, request, error) async {
// Handle web page loading errors here
var isForMainFrame = request.isForMainFrame ?? false;
if (!isForMainFrame ||
(!kIsWeb &&
defaultTargetPlatform == TargetPlatform.iOS &&
error.type == WebResourceErrorType.CANCELLED)) {
return;
}
var errorUrl = request.url;
controller.loadData(data: """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<style>
${await InAppWebViewController.tRexRunnerCss}
</style>
<style>
.interstitial-wrapper {
box-sizing: border-box;
font-size: 1em;
line-height: 1.6em;
margin: 0 auto 0;
max-width: 600px;
width: 100%;
}
</style>
</head>
<body>
${await InAppWebViewController.tRexRunnerHtml}
<div class="interstitial-wrapper">
<h1>Website not available</h1>
<p>Could not load web pages at <strong>$errorUrl</strong> because:</p>
<p>${error.description}</p>
</div>
</body>
""", baseUrl: errorUrl, historyUrl: errorUrl);
},
),
),
]));
}
}
Full project code example available at https://github.com/pichillilorenzo/flutter_inappwebview_examples/tree/main/custom_error_page
I tried share package and it works but I want to add a Widget that only appears on the shared image, not on the app. So please help me this is the code so far:
import 'dart:ui';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:share/share.dart';
void main() {
runApp(MaterialApp(home: HomePage()));
}
class HomePage extends StatelessWidget {
final _contentKey = GlobalKey();
final bool forSharing;
HomePage({
Key key,
this.forSharing = false,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: const Icon(Icons.share),
onPressed: () => onTakeScreenShotAndSharing(
'Image',
_contentKey.currentContext,
),
),
],
),
body: RepaintBoundary(
key: _contentKey,
child: Column(
children: [
if (forSharing) Text('Text appear only for Sharing'), // This is the widget that I want it appear only on the shared image
Text('Content'),
],
),
),
);
}
void onTakeScreenShotAndSharing(String fileName, BuildContext context) async {
try {
RenderRepaintBoundary boundary = context.findRenderObject();
final image = await boundary?.toImage();
final bytes = await image?.toByteData(format: ImageByteFormat.png);
if (bytes == null || bytes.buffer == null) return;
final dir = (await getApplicationDocumentsDirectory()).path;
final file = File('$dir/$fileName${DateTime.now().toString()}.png');
final newFile = await file.writeAsBytes(bytes.buffer.asUint8List());
await Share.shareFiles([newFile.path]);
} catch (error) {
print(error);
}
}
}
how to get html content form flutterWebViewPlugin ( webview ) in flutter
I am going to edit and use one of the answers on that link page.
It was an old sauce, so I barely removed the red line and even ran it, but because I was a beginner, I hit a wall.
Find the <meta name = " " ......> part of the page loaded in the webview and save the text in " " to the 'catchtext' list,
How can I make it print when the FloatingActionButton is pressed?
Sorry for the basic question. I'm learning from the beginning, but I'm so curious, so I ask in advance.
The source code is attached below.
import 'dart:async';
import 'dart:developer';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
runApp(new MyApp());
}
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => new _MyAppState();
}
class _MyAppState extends State<MyApp> {
late InAppWebViewController webView;
String myurl = "https://github.com/flutter";
static var catchtext = [];
#override
void initState() {
super.initState();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('InAppWebView Example'),
),
body: Container(
child: Column(children: <Widget>[
Expanded(
child: InAppWebView(
initialUrlRequest: URLRequest(
url: Uri.parse("https://flutter.dev/")
),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
// debuggingEnabled: true,
// userAgent: "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.13; rv:61.0) Gecko/20100101 Firefox/61.0"
),
),
onWebViewCreated: (InAppWebViewController controller) {
webView = controller;
},
onLoadStart: (controller, url) {
},
onLoadStop: (controller, url) async {
var html = await controller.evaluateJavascript(
source: "window.document.getElementsByTagName('head')[0].outerHTML;");
// source: "window.document.body.innerText;");
print("==========start================");
catchtext = html;
log(html);
},
))
])),
floatingActionButton: FloatingActionButton(
onPressed: ()
{
print(catchtext);
},
// tooltip: 'Increment',
child: const Icon(Icons.add),
),
),
);
}
}
Why does the image update only when I save file?
image_picker version
image_picker: ^0.8.4+3
My Code related to ImagePicker
// image_picker_controller.dart
// controller
import 'dart:io';
import 'package:get/get.dart';
import 'package:image_picker/image_picker.dart';
class ImagePickerController extends GetxController {
File? pickedImageFile;
var seletedImagePath = ''.obs;
void _pickImage() async {
final picker = ImagePicker();
// final pickedImage = await picker.pickImage(source: ImageSource.gallery);
final pickedImage = await picker.pickImage(source: ImageSource.camera);
if (pickImage != null) {
pickedImageFile = File(pickedImage!.path);
}
update();
}
void Function() get pickImage => _pickImage;
}
view page
// user_image_picker.dart
// page screen
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_chatting_app/src/controllers/image_picker_controller.dart';
import 'package:get/get.dart';
class UserImagePicker extends GetView<ImagePickerController> {
UserImagePicker({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return Column(
children: [
CircleAvatar(
radius: 40,
backgroundColor: Colors.grey,
backgroundImage: controller.pickedImageFile != null
? FileImage(controller.pickedImageFile as File)
: null,
),
TextButton.icon(
onPressed: controller.pickImage,
icon: Icon(Icons.image),
label: Text('Add Image'),
),
],
);
}
}
You can have a look at what happens in this gif link
When I add image with ImagePicker, DEBUG CONSOLE shows below, and image isn't updated.
// DEBUG CONSOLE
D/MediaScannerConnection( 7062): Scanned /data/user/0/com.example.flutter_chatting_app/cache/bc149d80-91bb-487d-b2b7-3597357c4d182105624148556557573.jpg to null
but, after I save codes, the image appear. I think the state doens't update, but I have no idea why it happens.
I've googled about this problem, but I couldn't figure it out.
Please, somebody help me.
I used the default Stateless and GetBuilder combination and it worked:
class ImagePickerController extends GetxController {
File? pickedImageFile;
void _pickImage() async {
final picker = ImagePicker();
final pickedImage = await picker.pickImage(source: ImageSource.camera);
pickedImageFile = File(pickedImage!.path);
update();
}
void Function() get pickImage => _pickImage;
}
and the view:
class UserImagePicker extends StatelessWidget {
const UserImagePicker({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return GetBuilder<ImagePickerController>(builder: (logic) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
CircleAvatar(
radius: 40,
backgroundColor: Colors.grey,
backgroundImage: logic.pickedImageFile != null
? FileImage(logic.pickedImageFile as File)
: null,
),
TextButton.icon(
onPressed: logic.pickImage,
icon: const Icon(Icons.image),
label: const Text('Add Image'),
),
],
);
});
}
}
I'm working on an app for scanning barcode, and i want to scanning multiple barcodes and still see what i'm scanning at the same time. please there a way this can be achieved in flutter?
This would only be achievable by using an inline QR scan widget.
This is available, but uses embedded native widgets, which is an experimental feature.
Have a look at this library: https://pub.dev/packages/qr_code_scanner
The example included should be able to help you. It divides the screen in 4/5 for the camera widget and 1/5 for the rest. You can change this by changing the flex value in the example below.
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:qr_code_scanner/qr_code_scanner.dart';
void main() => runApp(MaterialApp(home: QRViewExample()));
class QRViewExample extends StatefulWidget {
const QRViewExample({
Key key,
}) : super(key: key);
#override
State<StatefulWidget> createState() => _QRViewExampleState();
}
class _QRViewExampleState extends State<QRViewExample> {
final GlobalKey qrKey = GlobalKey(debugLabel: 'QR');
var qrText = "";
QRViewController controller;
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
Expanded(
child: QRView(
key: qrKey,
onQRViewCreated: _onQRViewCreated,
),
flex: 4,
),
Expanded(
child: Column(children:
<Widget>[
Text("This is the result of scan: $qrText"),
RaisedButton(
onPressed: (){
if(controller != null){
controller.flipCamera();
}
},
child: Text(
'Flip',
style: TextStyle(fontSize: 20)
),
)
],
),
flex: 1,
)
],
),
);
}
void _onQRViewCreated(QRViewController controller) {
final channel = controller.channel;
controller.init(qrKey);
this.controller = controller;
channel.setMethodCallHandler((MethodCall call) async {
switch (call.method) {
case "onRecognizeQR":
dynamic arguments = call.arguments;
setState(() {
qrText = arguments.toString();
});
}
});
}
}