LoginSignup
19
10

More than 3 years have passed since last update.

TextFieldの長押しでクラッシュする問題の対応方法

Last updated at Posted at 2019-02-13

2019/08/01 追記
現在は、GlobalCupertinoLocalizations.delegateが実装されているので、こちらを使えば以下の処理をしなくても大丈夫そうです。

Flutterで多言語対応をした場合にiosで言語を日本語にして、TextFieldで長押しするとクラッシュします。
こんなやつです。

error.PNG
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following NoSuchMethodError was thrown building _TextSelectionToolbar(dirty):
flutter: The getter 'pasteButtonLabel' was called on null.
flutter: Receiver: null
flutter: Tried calling: pasteButtonLabel
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
flutter: #1      _TextSelectionToolbar.build (package:flutter/src/cupertino/text_selection.dart:94:51)
・・・

原因は、長押ししたときに表示されるポップアップメニューに対応するラベルがないためです。

解決策

新たにios用のdelegateを作成して、MaterialAppのlocalizationsDelegatesに指定します。
CupertinoLocalizationsを実装します。

japanese_cupertino_localizations.dart
class JapaneseCupertinoLocalizations implements CupertinoLocalizations {
  final _materialDelegate = GlobalMaterialLocalizations.delegate;

  MaterialLocalizations materialLocalizations;

  static const LocalizationsDelegate<CupertinoLocalizations> delegate = _JapaneseDelegate();

  static Future<CupertinoLocalizations> load(Locale locale) async {
    var localizations = JapaneseCupertinoLocalizations();
    await localizations._init();
    return SynchronousFuture<CupertinoLocalizations>(localizations);
  }

  Future _init() async {
    materialLocalizations = await _materialDelegate.load(const Locale('ja'));
  }

  @override
  String get alertDialogLabel => materialLocalizations.alertDialogLabel;

  @override
  String get anteMeridiemAbbreviation => materialLocalizations.anteMeridiemAbbreviation;

  @override
  String get copyButtonLabel => materialLocalizations.copyButtonLabel;

  @override
  String get cutButtonLabel => materialLocalizations.cutButtonLabel;

  @override
  DatePickerDateOrder get datePickerDateOrder => DatePickerDateOrder.mdy;

  @override
  DatePickerDateTimeOrder get datePickerDateTimeOrder => DatePickerDateTimeOrder.date_time_dayPeriod;

  @override
  String datePickerDayOfMonth(int dayIndex) => dayIndex.toString();

  @override
  String datePickerHour(int hour) => hour.toString().padLeft(2, "0");

  @override
  String datePickerHourSemanticsLabel(int hour) => "$hour時";

  @override
  String datePickerMediumDate(DateTime date) => materialLocalizations.formatMediumDate(date);

  @override
  String datePickerMinute(int minute) => minute.toString().padLeft(2, '0');

  @override
  String datePickerMinuteSemanticsLabel(int minute) => "$minute分";

  @override
  String datePickerMonth(int monthIndex) => "$monthIndex";

  @override
  String datePickerYear(int yearIndex) => yearIndex.toString();

  @override
  String get pasteButtonLabel => materialLocalizations.pasteButtonLabel;

  @override
  String get postMeridiemAbbreviation => materialLocalizations.postMeridiemAbbreviation;

  @override
  String get selectAllButtonLabel => materialLocalizations.selectAllButtonLabel;

  @override
  String timerPickerHour(int hour) => hour.toString().padLeft(2, "0");

  @override
  String timerPickerHourLabel(int hour) => "${hour.toString().padLeft(2, '0')}時";

  @override
  String timerPickerMinute(int minute) => minute.toString().padLeft(2, "0");

  @override
  String timerPickerMinuteLabel(int minute) => "${minute.toString().padLeft(2, '0')}分";

  @override
  String timerPickerSecond(int second) => second.toString().padLeft(2, "0");

  @override
  String timerPickerSecondLabel(int second) => "${second.toString().padLeft(2, '0')}秒";
}

class _JapaneseDelegate extends LocalizationsDelegate<CupertinoLocalizations> {
  const _JapaneseDelegate();

  @override
  bool isSupported(Locale locale) {
    return locale.languageCode == 'ja';
  }

  @override
  Future<CupertinoLocalizations> load(Locale locale) {
    return JapaneseCupertinoLocalizations.load(locale);
  }

  @override
  bool shouldReload(LocalizationsDelegate<CupertinoLocalizations> old) {
    return false;
  }
}

多言語対応で指定しているdelegateに追記するだけです。

 MaterialApp(
         localizationsDelegates: [
           MyLocalizationsDelegate.delegate,
+          JapaneseCupertinoLocalizations.delegate,
           GlobalMaterialLocalizations.delegate,
           GlobalWidgetsLocalizations.delegate,
         ],
         supportedLocales: supportedLocales

ちなみに上記の MyLocalizationsDelegate は多言語対応の時に作成したクラスです。詳細はこちらの記事が参考になります。

19
10
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
10