NosuchMethodError: The getter 'pasterButtonLabel' was called on null.
Receiver: null
Tried calling: pasteButtonLabel
在最近 app store 提交审核时被拒了,然后得到了一个这样的截图
在 flutter 中可能会会出现各种问题,因为之前遇到过这个问题,但是那是我另一个应用,这个忘了设置了
我快速搞了一下,重新提交了审核
import 'package:flutter/cupertino.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_localizations/flutter_localizations.dart';
class ChineseCupertinoLocalizations implements CupertinoLocalizations {
final materialDelegate = GlobalMaterialLocalizations.delegate;
final widgetsDelegate = GlobalWidgetsLocalizations.delegate;
final local = const Locale('zh');
MaterialLocalizations ml;
Future init() async {
ml = await materialDelegate.load(local);
print(ml.pasteButtonLabel);
}
@override
String get alertDialogLabel => ml.alertDialogLabel;
@override
String get anteMeridiemAbbreviation => ml.anteMeridiemAbbreviation;
@override
String get copyButtonLabel => ml.copyButtonLabel;
@override
String get cutButtonLabel => ml.cutButtonLabel;
@override
DatePickerDateOrder get datePickerDateOrder => DatePickerDateOrder.mdy;
@override
DatePickerDateTimeOrder get datePickerDateTimeOrder =>
DatePickerDateTimeOrder.date_time_dayPeriod;
@override
String datePickerDayOfMonth(int dayIndex) {
return dayIndex.toString();
}
@override
String datePickerHour(int hour) {
return hour.toString().padLeft(2, "0");
}
@override
String datePickerHourSemanticsLabel(int hour) {
return "$hour" + "时";
}
@override
String datePickerMediumDate(DateTime date) {
return ml.formatMediumDate(date);
}
@override
String datePickerMinute(int minute) {
return minute.toString().padLeft(2, '0');
}
@override
String datePickerMinuteSemanticsLabel(int minute) {
return "$minute" + "分";
}
@override
String datePickerMonth(int monthIndex) {
return "$monthIndex";
}
@override
String datePickerYear(int yearIndex) {
return yearIndex.toString();
}
@override
String get pasteButtonLabel => ml.pasteButtonLabel;
@override
String get postMeridiemAbbreviation => ml.postMeridiemAbbreviation;
@override
String get selectAllButtonLabel => ml.selectAllButtonLabel;
@override
String timerPickerHour(int hour) {
return hour.toString().padLeft(2, "0");
}
@override
String timerPickerHourLabel(int hour) {
return "$hour".toString().padLeft(2, "0") + "时";
}
@override
String timerPickerMinute(int minute) {
return minute.toString().padLeft(2, "0");
}
@override
String timerPickerMinuteLabel(int minute) {
return minute.toString().padLeft(2, "0") + "分";
}
@override
String timerPickerSecond(int second) {
return second.toString().padLeft(2, "0");
}
@override
String timerPickerSecondLabel(int second) {
return second.toString().padLeft(2, "0") + "秒";
}
static const LocalizationsDelegate delegate =
_ChineseDelegate();
static Future load(Locale locale) async {
var localizaltions = ChineseCupertinoLocalizations();
await localizaltions.init();
return SynchronousFuture(localizaltions);
}
}
class _ChineseDelegate extends LocalizationsDelegate {
const _ChineseDelegate();
@override
bool isSupported(Locale locale) {
return locale.languageCode == 'zh';
}
@override
Future load(Locale locale) {
return ChineseCupertinoLocalizations.load(locale);
}
@override
bool shouldReload(LocalizationsDelegate old) {
return false;
}
}
这个东西弄到项目里
然后在 Application 里配置一下
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
// This is the theme of your application.
//
// Try running your application with "flutter run". You'll see the
// application has a blue toolbar. Then, without quitting the app, try
// changing the primarySwatch below to Colors.green and then invoke
// "hot reload" (press "r" in the console where you ran "flutter run",
// or simply save your changes to "hot reload" in a Flutter IDE).
// Notice that the counter didn't reset back to zero; the application
// is not restarted.
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
localizationsDelegates: >[
ChineseCupertinoLocalizations.delegate, // 这里加上这个,是自定义的delegate
DefaultCupertinoLocalizations.delegate, // 这个截止目前只包含英文
// 下面两个是Material widgets的delegate, 包含中文
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: [
const Locale('en', 'US'), // English
const Locale('zh', 'Hans'), // China
const Locale('zh', ''), // China
// ... other locales the app supports
],
);
}
}
这样就能完成默认的中文的本地化,当然之前那个 Cupertino 的 delegate 实际上也是借助了 Material 中的 delegate 本地化
这里还要注意,一定要保证你的设备是本地语言是中文(因为很多朋友是使用模拟器开发的,默认是英文)
这里要解析一波源码了,为什么会出现这种情况呢
主要原因就是在某个版本,加入了一整套的 Cupertino 相关的支持,但是又因为某些原因遗忘了非英文版本,造成了默认的情况下,不包含其他语言
而在未设置对应语言的 delegate 时,又没有一个默认的 delegate,从而造成空指针异常,进而抛出错误
这个是 Cupertino 中,弹出剪切/复制/粘贴/全选那个按钮那个 toolbar 的配置界面,这里会使用到这个类,然而又因为得到的是空的,所以会报空指针异常
而获取的方式是使用CupertinoLocalizations.of(context);
的方式
查看这个方法的定义处又可以跟踪到另一个地方
然后来到这段代码
Future
简单来说,这个方法是根据本地的语言读取所有支持这个语言的 delegate
然后问题来了, 没读取到怎么办呢
有几处代码需要关注一下
这里就看出来了,为什么会有空指针异常的原因 3 => 2 => 1 但是 1 也没读取到 ,自然就空指针了
本篇介绍了解决方案 pastelabel
copylabel
各种 label 空指针的原因和解决方案