fluttercandies / extended_text_field

extended official text field to quickly build special text like inline image, @somebody, custom background etc.
MIT License
565 stars 148 forks source link

[ios] 有@字段时,继续输入,正在输入中时光标不在末尾,在倒数第一个字前面,输入完成后会偏移到末尾 #205

Closed zhanglijie5997 closed 1 year ago

zhanglijie5997 commented 1 year ago

Version

11.0.1

Platforms

iOS

Device Model

iPhone 13

flutter info

[✓] Flutter (Channel stable, 3.7.7, on macOS 12.6.3 21G419 darwin-x64, locale zh-Hans-CN)
    • Flutter version 3.7.7 on channel stable at /Users/ljz/flutter
    • Upstream repository https://github.com/flutter/flutter.git
    • Framework revision 2ad6cd72c0 (3 weeks ago), 2023-03-08 09:41:59 -0800
    • Engine revision 1837b5be5f
    • Dart version 2.19.4
    • DevTools version 2.20.1
    • Pub download mirror https://pub.flutter-io.cn
    • Flutter download mirror https://storage.flutter-io.cn

[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.0)
    • Android SDK at /Users/ljz/Library/Android/sdk
    • Platform android-33, build-tools 33.0.0
    • ANDROID_HOME = /Users/ljz/Library/Android/sdk
    • Java binary at: /Applications/Android Studio.app/Contents/jre/Contents/Home/bin/java
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)
    • All Android licenses accepted.

[✓] Xcode - develop for iOS and macOS (Xcode 14.2)
    • Xcode at /Applications/Xcode.app/Contents/Developer
    • Build 14C18
    • CocoaPods version 1.11.3

[✓] Chrome - develop for the web
    • Chrome at /Applications/Google Chrome.app/Contents/MacOS/Google Chrome

[✓] Android Studio (version 2021.3)
    • Android Studio at /Applications/Android Studio.app/Contents
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart
    • Java version OpenJDK Runtime Environment (build 11.0.13+0-b1751.21-8125866)

[✓] IntelliJ IDEA Ultimate Edition (version 2021.2.3)
    • IntelliJ at /Applications/IntelliJ IDEA.app
    • Flutter plugin version 69.0.2
    • Dart plugin version 212.5632

[✓] IntelliJ IDEA Ultimate Edition (version 2019.3.1)
    • IntelliJ at /Users/ljz/Applications/JetBrains Toolbox/IntelliJ IDEA Ultimate.app
    • Flutter plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/9212-flutter
    • Dart plugin can be installed from:
      🔨 https://plugins.jetbrains.com/plugin/6351-dart

[✓] IntelliJ IDEA Ultimate Edition (version 2019.3.1)
    • IntelliJ at /Users/ljz/Library/Application
      Support/JetBrains/Toolbox/apps/IDEA-U/ch-0/193.5662.53/IntelliJ IDEA.app
    • Flutter plugin version 45.1.2
    • Dart plugin version 193.7547

[✓] VS Code (version 1.76.2)
    • VS Code at /Applications/Visual Studio Code.app/Contents
    • Flutter extension version 3.60.0

[✓] Connected device (3 available)
    • iPhone13 (mobile) • 00008110-000470CA2E2A801E • ios            • iOS 16.1.1 20B101
    • macOS (desktop)   • macos                     • darwin-x64     • macOS 12.6.3 21G419
      darwin-x64
    • Chrome (web)      • chrome                    • web-javascript • Google Chrome
      111.0.5563.110

How to reproduce?

https://user-images.githubusercontent.com/42401363/228120060-858d1192-2529-461b-8041-b8fa9eac9f7f.mp4

Logs

Example code (optional)

import 'package:extended_text_field/extended_text_field.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:jdn/utils/utils.dart';

typedef AtTextCallback = Function(String showText, String actualText);

class AtSpecialTextSpanBuilder extends SpecialTextSpanBuilder {
  final AtTextCallback? atCallback;

  /// key:userid
  /// value:username
  final Map<String, String> allAtMap;
  final TextStyle? atStyle;

  AtSpecialTextSpanBuilder({
    this.atCallback,
    this.atStyle,
    this.allAtMap = const <String, String>{},
  });
  final emojiFaces = <String, String>{
    '[亲亲]': 'ic_face_01',
    '[看穿]': 'ic_face_02',
    '[色]': 'ic_face_03',
    '[吓哭]': 'ic_face_04',
    '[笑脸]': 'ic_face_05',
    '[眨眼]': 'ic_face_06',
    '[搞怪]': 'ic_face_07',
    '[龇牙]': 'ic_face_08',
    '[无语]': 'ic_face_09',
    '[可怜]': 'ic_face_10',
    '[咒骂]': 'ic_face_11',
    '[晕]': 'ic_face_12',
    '[尴尬]': 'ic_face_13',
    '[暴怒]': 'ic_face_14',
    '[可爱]': 'ic_face_15',
    '[哭泣]': 'ic_face_16',
  };
  final regexAt = r"(@\S+\s)";

  @override
  TextSpan build(
    String data, {
    TextStyle? textStyle,
    SpecialTextGestureTapCallback? onTap,
  }) {
    StringBuffer buffer = StringBuffer();
    if (kIsWeb) {
      return TextSpan(text: data, style: textStyle);
    }
    // if (allAtMap.isEmpty) {
    //   return TextSpan(text: data, style: textStyle);
    // }
    final List<InlineSpan> children = <InlineSpan>[];

    var regexEmoji = emojiFaces.keys
        .toList()
        .join('|')
        .replaceAll('[', '\\[')
        .replaceAll(']', '\\]');

    final list = [regexAt, regexEmoji];
    final pattern = '(${list.toList().join('|')})';
    final atReg = RegExp(regexAt);
    final emojiReg = RegExp(regexEmoji);

    data.splitMapJoin(
      RegExp(pattern),
      // RegExp(r"(@\S+\s)"),
      onMatch: (Match m) {
        late InlineSpan inlineSpan;
        String value = m.group(0)!;
        try {
          if (atReg.hasMatch(value)) {
            String id = value.replaceFirst("@", "").trim();
            LogUtil.e('id________:$id $allAtMap');

            if (allAtMap.containsKey(id)) {
              var name = allAtMap[id]!;
              // inlineSpan = ExtendedWidgetSpan(
              //   child: Text('@$name ', style: atStyle),
              //   style: atStyle,
              //   actualText: '$value',
              //   start: m.start,
              // );

              inlineSpan = SpecialTextSpan(
                text: '$value ',
                actualText: '$name',
                start: m.start,
                style: atStyle,
              );
              buffer.write('@$name');
            } else {
              inlineSpan = TextSpan(text: '$value', style: textStyle);
              buffer.write('$value');
            }
          } else if (emojiReg.hasMatch(value)) {
            // inlineSpan = ImageSpan(
            //   ImageUtil.emojiImage(value),
            //   imageWidth: atStyle!.fontSize!,
            //   imageHeight: atStyle!.fontSize!,
            //   start: m.start,
            //   actualText: '$value',
            // );
          }
          /*String id = value.replaceAll("@", "").trim();
        if (allAtMap.containsKey(id)) {
          var name = allAtMap[id]!;
          inlineSpan = ExtendedWidgetSpan(
            child: Text('@$name ', style: atStyle),
            style: atStyle,
            actualText: '$value',
            start: m.start,
          );
          buffer.write('@$name ');
        }*/
          else {
            /* inlineSpan = SpecialTextSpan(
            text: '${m.group(0)}',
            style: TextStyle(color: Colors.blue),
            start: m.start,
          );*/
            inlineSpan = TextSpan(text: '$value', style: textStyle);
            buffer.write('$value');
          }
        } catch (e) {
          print('error: $e');
        }
        children.add(inlineSpan);
        return "";
      },
      onNonMatch: (text) {
        children.add(TextSpan(text: text, style: textStyle));
        buffer.write(text);
        return '';
      },
    );
    if (null != atCallback) atCallback!(buffer.toString(), data);
    return TextSpan(children: children, style: textStyle);
  }

  @override
  SpecialText? createSpecialText(
    String flag, {
    TextStyle? textStyle,
    SpecialTextGestureTapCallback? onTap,
    required int index,
  }) {
    return null;
  }
}

ExtendedTextField(
  specialTextSpanBuilder: AtSpecialTextSpanBuilder(
    atCallback: (v1, v2) {},
    allAtMap: {'123': '123'},
  )
)

Contact

13650653625@163.com

zmtzawqlp commented 1 year ago

如果用正则就好好用demo里面的写法,自己好好检查下错误

zhanglijie5997 commented 1 year ago

如果用正则就好好用demo里面的写法,自己好好检查下错误

谢谢