dart 如何在不显示键盘的情况下聚焦TextField?

c9qzyr3d  于 2023-06-19  发布在  其他
关注(0)|答案(3)|浏览(158)

我需要专注于一个文本字段,但不显示键盘。如果用户点击文本字段,则需要显示键盘。
我试了两种方法。

第一次尝试:

这样的键盘显示和它的屏幕构建后,这是不好看隐藏。
建设者:

TextFormField(
    controller: barcodeStringController,
    focusNode: myFocusNode,
    autofocus: true,
    textAlign: TextAlign.right,
    textInputAction: TextInputAction.done,
    textCapitalization: TextCapitalization.characters,
    style: TextStyle(fontSize: 20),
    maxLines: null,
    onTap: () {
      SystemChannels.textInput.invokeMethod('TextInput.show');
    },
    //... Other event listeners to handle submit
),

在build()之外:

void _onAfterBuild(BuildContext context) {
  SystemChannels.textInput.invokeMethod('TextInput.hide');
}

第二次尝试:

这样键盘就隐藏在较低的位置,看起来更好。问题是onTap从未被调用,所以键盘永远不会显示,onTap也不会。
建设者:

GestureDetector(
    onTap: () {
        SystemChannels.textInput.invokeMethod('TextInput.show');
    },
    child: TapOnlyFocusTextField(
        controller: barcodeStringController,
        focusNode: myFocusNode, //this is a TapOnlyFocusTextFieldFocusNode
        textAlign: TextAlign.right,
        textInputAction: TextInputAction.done,
        textCapitalization: TextCapitalization.characters,
        style: TextStyle(fontSize: 20),
        cursorColor: Colors.black,
        //... Other event listeners to handle submit
    ),
),

TapOnlyFocusTextField类:

class TapOnlyFocusTextField extends EditableText {
  TapOnlyFocusTextField({
    @required TextEditingController controller,
    @required TextStyle style,
    @required Color cursorColor,
    bool autofocus = false,
    Color selectionColor,
    FocusNode focusNode,
    TextAlign textAlign,
    TextInputAction textInputAction,
    TextCapitalization textCapitalization,
    onSubmitted,
    onChanged,
  }) : super(
          controller: controller,
          focusNode: focusNode,
          style: style,
          cursorColor: cursorColor,
          autofocus: autofocus,
          selectionColor: selectionColor,
          textAlign: textAlign,
          textInputAction: textInputAction,
          textCapitalization: textCapitalization,
          maxLines: null,
          onSubmitted: onSubmitted,
          backgroundCursorColor: Colors.black,
          onChanged: onChanged,
        );

  @override
  EditableTextState createState() {
    return TapOnlyFocusTextFieldState();
  }
}

class TapOnlyFocusTextFieldState extends EditableTextState {
  @override
  void requestKeyboard() {
    super.requestKeyboard();
    //hide keyboard
    SystemChannels.textInput.invokeMethod('TextInput.hide');
  }
}

TapOnlyFocusTextFieldFocusNode类:

class TapOnlyFocusTextFieldFocusNode extends FocusNode {
  @override
  bool consumeKeyboardToken() {
    // prevents keyboard from showing on first focus
    return false;
  }
}

我知道在Flutter Github上已经有一个公开的问题,但我需要找到一个解决方案:https://github.com/flutter/flutter/issues/16863

deikduxw

deikduxw1#

text_input. dart有一个方法

void show({bool ifShowKeyBoard = true}) {
      assert(attached);
      if (ifShowKeyBoard) {
        TextInput._instance._show();
      }
    }

我把方法改了一下,这样就行了

dgenwo3n

dgenwo3n2#

如图所示:https://stackoverflow.com/a/60392327/4693979
但我更喜欢在initState中这样做:

void initState() {
    super.initState();
    Future.delayed(
      Duration(),
      () => SystemChannels.textInput.invokeMethod('TextInput.hide'),
    );
  }

别忘了将自动对焦设置为true。

oxiaedzo

oxiaedzo3#

如何在不显示键盘的情况下关注TextField

您可以创建自己的UIViewRepresentable并更改UITextFieldinputView
下面的XTextField只会在按住焦点后点击时显示键盘。根据您的喜好定制。

import SwiftUI
import UIKit

public struct XTextField: UIViewRepresentable {
    public init(
        _ placeholder: String,
        text: Binding<String>,
        onEditingChanged: ((Bool) -> Void)?,
        onCommit: (() -> Void)?,
        isFirstResponder: Binding<Bool>
    ) {
        self.placeholder = placeholder
        _text = text
        self.onEditingChanged = onEditingChanged
        self.onCommit = onCommit
        _isFirstResponder = isFirstResponder
    }

    public class Coordinator: NSObject, UITextFieldDelegate {
        init(_ xTextField: Binding<XTextField>) {
            _parent = xTextField
        }

        public func textFieldDidChangeSelection(_ textField: UITextField) {
            parent.text = textField.text ?? ""
        }

        public func textFieldDidBeginEditing(_: UITextField) {
            parent.isFirstResponder = true
            parent.onEditingChanged?(true)
        }

        public func textFieldDidEndEditing(_: UITextField) {
            parent.onEditingChanged?(false)
        }

        public func textFieldShouldReturn(_: UITextField) -> Bool {
            parent.isFirstResponder = false
            parent.onCommit?()
            return true
        }

        @Binding var parent: XTextField

        @objc func inputViewTapped(_ gesture: UITapGestureRecognizer) {
            if let textField = gesture.view as? UITextField {
                // Keyboard doesn't show unless tapped AFTER already being
                // firstResponder.
                if textField.isFirstResponder {
                    textField.inputView = nil // restores regular keyboard
                    textField.resignFirstResponder()
                } else {
                    textField.inputView = dummyInputView // suppresses keyboard
                }

                textField.becomeFirstResponder()
            }
        }
    }

    public func makeCoordinator() -> Coordinator {
        Coordinator(Binding(get: { self }, set: { _ in }))
    }

    public func makeUIView(context: Context) -> UITextField {
        let textField = UITextField()
        textField.delegate = context.coordinator
        textField.placeholder = placeholder
        textField.inputView = Self.dummyInputView // supress keyboard

        let tapGesture = UITapGestureRecognizer(
            target: context.coordinator,
            action: #selector(Coordinator.inputViewTapped(_:))
        )
        textField.addGestureRecognizer(tapGesture)

        return textField
    }

    public func updateUIView(_ uiView: UITextField, context _: Context) {
        uiView.text = text
        if isFirstResponder {
            Task { uiView.becomeFirstResponder() }
            return
        } else {
            Task { uiView.resignFirstResponder() }
        }
    }

    static let dummyInputView = UIView()

    @Binding var text: String
    @Binding var isFirstResponder: Bool

    private let placeholder: String
    private let onEditingChanged: ((Bool) -> Void)?
    private let onCommit: (() -> Void)?
}

相关问题