目前流行的通过 MediaQueryData.fromView(View.of(context))获取屏幕宽高的适配方案,当app从后台唤醒的时候,在安卓机型上会出现适配丢失的场景。
通过MediaQuery.sizeOf(context)获取屏幕宽高的适配方案,横屏竖屏切换的时候,会引起整个app重构。
这里给出结合原生层面的方案,解决上面的问题。
那如何解决适配丢失的问题?
从原生层面获取屏幕信息(屏幕宽高、dpr以及状态栏高度)。
代码如下
安卓+channel代码
class MainActivity: FlutterActivity() {
private val CHANNEL = "app.channel.notification"
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
// This method is invoked on the main thread.
call, result ->
if (call.method == "getScreenSize") {
// get statusBarHeight
val resourceId = resources.getIdentifier("status_bar_height", "dimen", "android")
statusBarHeight = if (resourceId > 0) {
resources.getDimensionPixelSize(resourceId)
} else {
0
}
// Get the screen width and height
val displayMetrics = resources.displayMetrics
screenWidth = displayMetrics.widthPixels
screenHeight = displayMetrics.heightPixels
// Get the device pixel ratio (DPR)
dpr = displayMetrics.density
// Return the screen width and height to Flutter
val resultMap = mapOf(
"width" to screenWidth/dpr,
"height" to screenHeight/dpr,
"statusBarHeight" to statusBarHeight/dpr
)
result.success(resultMap)
} else{
result.notImplemented()
}
}
}
}
苹果+channel代码
import UIKit
import Flutter
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
let appChannel = FlutterMethodChannel(name: "app.channel.notification",
binaryMessenger: controller.binaryMessenger)
appChannel.setMethodCallHandler({
(call: FlutterMethodCall, result: @escaping FlutterResult) -> Void in
// This method is invoked on the UI thread.
if call.method == "getScreenSize" {
let statusBarHeight = UIApplication.shared.statusBarFrame.size.height
let screenSize = UIScreen.main.bounds.size
let screenWidth = screenSize.width
let screenHeight = screenSize.height
let dpr = UIScreen.main.scale
let resultMap: [String: Any] = [
"width": screenWidth,
"height": screenHeight,
"statusBarHeight": statusBarHeight
]
result(resultMap)
}else {
result(FlutterMethodNotImplemented)
}
})
GeneratedPluginRegistrant.register(with: self)
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
}
flutter main.dart
Future<void> main() async{
WidgetsBinding widgetsBinding = WidgetsFlutterBinding.ensureInitialized();
//获取屏幕尺寸信息
const platform = MethodChannel('app.channel.notification');
var screenSize = await platform.invokeMethod('getScreenSize');
Constants.initializeScreenConstants(screenSize);
HYSizeFit.initialize(screenSize:screenSize);
runApp(const MyApp());
}
constants.dart
import 'package:flutter/material.dart';
class Constants {
static late double stateHeight;
static late double screenHeight;
static late double screenWidth;
static void initializeScreenConstants(Map screenSize){
stateHeight = screenSize["statusBarHeight"];
screenWidth = screenSize["width"];
screenHeight = screenSize["height"];
}
}
size_fit.dart
import 'package:flutter/material.dart';
class HYSizeFit {
static late double screenWidth;
static late double screenHeight;
static late double rpx;
static late double px;
static void initialize({required Map screenSize,double standardWidth = 750}) {
screenWidth = screenSize["width"];
screenHeight = screenSize["height"];
// 计算rpx 和px大小
rpx = screenWidth / standardWidth;
px = screenWidth / standardWidth * 2; // 必须是乘以2,因为是以iphone6(750)为标准
}
// 按照像素来设置
static double setPx(double size) {
return px * size ;
}
// 按照rpx来设置(如果给的设计稿是物理像素用rpx)
static double setRpx(double size) {
return rpx * size;
}
}
int_extension.dart
import './size_fit.dart';
extension IntFit on int {
double get px {
// 因为我的工具size_fit自己规定了rpx与px都必须是double类型,所以这里也必须要转换一下
return HYSizeFit.setPx(toDouble());
}
double get rpx {
// 因为我的工具size_fit自己规定了rpx与px都必须是double类型,所以这里也必须要转换一下
return HYSizeFit.setRpx(toDouble());
}
}
double_extension.dart
import './size_fit.dart';
extension DoubleFit on double {
double get px {
//这里的this是数字200.0, 相当于使用时 width: 200.0.px 里面的200.0 ,相当于是它调用方法
return HYSizeFit.setPx(this);
}
double get rpx {
//这里和上面都是用的get ,所以外面使用的时候是:width:200.5.rpx
return HYSizeFit.setRpx(this);
}
}
总结
本适配方案从根源解决适配问题。