I am trying to implement a dropdown button that let users switch between languages for my app, upon which the corresponding Webview containers will change to match the selected languages. I tried to implement this by creating a _renderWebviewBox1() function that returns the Webview controller that matches the current selected language.
String? _value = "English";
_renderWebviewBox1() {
if (_value == "English") {
return WebViewWidget(controller: _controller);
} else if (_value == "Mi'gmaq") {
return WebViewWidget(controller: _controller1Mig);
} else {
print("No translation yet");
return null;
}
}
Here is my full code:
import 'package:flutter/material.dart';
import 'package:flutter_webview_practice/routes.dart';
import 'package:webview_flutter/webview_flutter.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: MainPage(),
initialRoute: RouteManager.homePage,
onGenerateRoute: RouteManager.generateRoute,
);
}
}
class MainPage extends StatefulWidget {
const MainPage({super.key});
@override
State<MainPage> createState() => _MainPageState();
}
class _MainPageState extends State<MainPage> {
late final WebViewController _controller = WebViewController()
..setBackgroundColor(Colors.transparent)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadFlutterAsset("assets/aligns/hunter-3-align1.html")
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
),
);
late final WebViewController _controller2 = WebViewController()
..setBackgroundColor(Colors.transparent)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadFlutterAsset("assets/aligns/hunter-3-align2.html")
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
),
);
late final WebViewController _controller1Mig = WebViewController()
..setBackgroundColor(Colors.transparent)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadFlutterAsset("assets/aligns/hunter-3-align1-mig.html")
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
),
);
late final WebViewController _controller2Mig = WebViewController()
..setBackgroundColor(Colors.transparent)
..setJavaScriptMode(JavaScriptMode.unrestricted)
..loadFlutterAsset("assets/aligns/hunter-3-align2-mig.html")
..setNavigationDelegate(
NavigationDelegate(
onProgress: (int progress) {
debugPrint('WebView is loading (progress : $progress%)');
},
),
);
String? _value = "English";
_renderWebviewBox1() {
if (_value == "English") {
return WebViewWidget(controller: _controller);
} else if (_value == "Mi'gmaq") {
return WebViewWidget(controller: _controller1Mig);
} else {
print("No translation yet");
return null;
}
}
_renderWebviewBox2() {
if (_value == "English") {
return WebViewWidget(controller: _controller2);
} else if (_value == "Mi'gmaq") {
return WebViewWidget(controller: _controller2Mig);
} else {
print("No translation yet");
return null;
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: FittedBox(
alignment: Alignment.center,
fit: BoxFit.contain,
child: Column(
children: [
DropdownButton<String>(
value: _value,
items: <String>[
"English",
"Mi'gmaq",
"Wolastoqey",
].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (String? newValue) {
if (newValue != _value) {
switch (newValue) {
case "Mi'gmaq":
_value = "Mi'gmaq";
break;
case "English":
_value = "English";
break;
case "Wolastoqey":
_value = "Wolastoqey";
break;
}
}
setState(() {
_value = newValue;
});
},
),
Stack(
children: [
Container(
width: 650,
height: 500,
child: const Image(
image: AssetImage("assets/images/hunterChoice3.jpg"),
),
),
Positioned(
left: 120,
right: 10,
top: 10,
bottom: 10,
child: Container(
width: 325,
height: 500,
child: _renderWebviewBox1(),
),
),
Positioned(
left: 20,
right: 90,
top: 420,
child: Container(
width: 325,
height: 500,
child: _renderWebviewBox2(),
),
),
],
),
],
),
),
),
);
}
}
However, currently, while the dropdown button does update, the page does not rebuild and thus _renderWebviewBox1() and _renderWebviewBox2() are only called once. How should I implement setState() such that the page rebuilds every time the dropdown button is changed?
I have tried placing setState() inside each of the switch statement of the onChanged property in the dropdown button widget, but that also does not rebuild the page.
As Peter Koltai mentioned, you should use the setState
method to let the application know that it must rebuild, but it is not necessary to use the _value
in the build
method directly. When the build
method is executed, it also executes both functions every time.
I assume that if you add a different key to each of your WebViewWidget
, it would rebuild normally.
Also, you don't need that switch
statement completely, it can be removed as it does nothing:
onChanged: (String? newValue) {
if (newValue != _value) {
setState(() {
_value = newValue;
});
}
Moreover, as you use copy-paste code everywhere, consider creating functions or methods to reduce code duplication.