A Focusable and Blurable TextField Widget in Flutter

You are currently viewing A Focusable and Blurable TextField Widget in Flutter
Focusable TextField

A Focusable and Blurable TextField Widget in Flutter

Flutter Focus Widget

A focusable and blurable widget of based on the FocusNode.

When the FocusWidget had focusTap this FocusWidget outside area will call the FocusNode’s unfocus method and trigger the FocusNode’s listener

Example

Focusable TextField
Focusable TextField
import 'package:flutter/cupertino.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/widgets.dart';

typedef FocusNodeBuilder = Widget Function(
    BuildContext context, FocusNode focusNode);
typedef OnLostFocus = void Function(Widget widget, FocusNode focusNode);

class FocusWidget extends StatefulWidget {
  final FocusNode focusNode;
  final Widget child;
  final OnLostFocus? onLostFocus;
  final bool showFocusArea;

  const FocusWidget({
    Key? key,
    required this.child,
    required this.focusNode,
    this.showFocusArea = false,
    this.onLostFocus,
  }) : super(key: key);

  @override
  FocusWidgetState createState() => FocusWidgetState();

  static FocusWidget builder(
    BuildContext context, {
    required FocusNodeBuilder builder,
    showFocusArea = false,
    OnLostFocus? onLostFocus,
  }) {
    // print('builder area $showFocusArea');
    final focusNode = FocusNode();
    return FocusWidget(
      focusNode: focusNode,
      showFocusArea: showFocusArea,
      onLostFocus: onLostFocus,
      child: builder(
        context,
        focusNode,
      ),
    );
  }
}

class FocusWidgetState extends State<FocusWidget> {
  OverlayEntry? _overlayEntry;
  late Rect rect;

  @override
  void initState() {
    // print('state init');
    widget.focusNode.addListener(update);
    super.initState();
  }

  @override
  void didUpdateWidget(FocusWidget oldWidget) {
    // print('didUpdateWidget');
    widget.focusNode.removeListener(update);
    widget.focusNode.addListener(update);
    super.didUpdateWidget(oldWidget);
  }

  @override
  void dispose() {
    widget.focusNode.removeListener(update);
    super.dispose();
  }

  void update() {
    final renderBox = context.findRenderObject() as RenderBox;
    final size = renderBox.size;
    final offset = renderBox.localToGlobal(Offset.zero);
    rect = Rect.fromLTWH(offset.dx, offset.dy, size.width, size.height);
    _createOverlay();
  }

  void _removeOverlay() {
    _overlayEntry?.remove();
    _overlayEntry = null;
  }

  void _createOverlay() {
    _removeOverlay();
    if (widget.focusNode.hasFocus) {
      // print('has focus');
      final children = <Widget>[
        Listener(
          behavior: HitTestBehavior.translucent,
          onPointerMove: (e) {
            final scope = FocusScope.of(context);
            scope.unfocus();
          },
          onPointerUp: (e) {
            // print('onPointerDown');
            if (rect.contains(e.position) == false) {
              // print('超出');
              final scope = FocusScope.of(context);
              scope.unfocus();
              if (widget.onLostFocus != null)
                widget.onLostFocus?.call(widget.child, widget.focusNode);
              _removeOverlay();
            }
          },
        ),
      ];
      if (widget.showFocusArea) {
        children.insert(
            0,
            Positioned.fromRect(
              rect: rect,
              child: Container(
                color: Color(0x60ff0000),
              ),
            ));
      }
      _overlayEntry = new OverlayEntry(
        builder: (context) {
          return Stack(
            children: children,
          );
        },
      );
      Overlay.of(context)?.insert(_overlayEntry!);
    }
  }

  @override
  Widget build(BuildContext context) {
    return NotificationListener<LayoutChangedNotification>(
      child: widget.child,
      onNotification: (LayoutChangedNotification notification) {
        // print('notification $notification');
        update();
        return true;
      },
    );
  }
}

Credits:
This is developed by gzlock
Download this project from the below link.
https://github.com/gzlock/flutter_focus_widget/archive/refs/heads/master.zip
You can visit original source page from the below link:
https://github.com/gzlock/flutter_focus_widget

See also  Material Range Slider for Flutter

Spread the love

Leave a Reply