searchfield icon indicating copy to clipboard operation
searchfield copied to clipboard

Migrate Searchfield to use OverlayPortal

Open maheshj01 opened this issue 1 year ago • 3 comments

This will solve

  • Issue https://github.com/maheshmnj/searchfield/issues/84
  • Issue https://github.com/maheshmnj/searchfield/issues/38
sample demo code
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        title: 'Flutter Demo',
        theme: ThemeData(
          primarySwatch: Colors.blue,
        ),
        home: MyHomePage(
          title: "My Home Page",
        ));
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Padding(
              padding: EdgeInsets.all(8.0),
              child: CustomWidget(),
            ),
            const Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headlineMedium,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: const Icon(Icons.add),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

class CustomWidget extends StatefulWidget {
  const CustomWidget({Key? key}) : super(key: key);
  @override
  State<CustomWidget> createState() => _CustomWidgetState();
}

class _CustomWidgetState extends State<CustomWidget> {
  final ScrollController _scrollController = ScrollController();

  Widget _list() {
    return Container(
      height: 5 * 40,
      child: Scrollbar(
          controller: _scrollController,
          thumbVisibility: true,
          child: ListView.builder(
              controller: _scrollController,
              padding: EdgeInsets.zero,
              itemCount: 20,
              itemBuilder: (context, index) => ListTile(
                    title: Text('item $index'),
                    onTap: () {
                      _portalController.hide();
                    },
                  ))),
    );
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((x) {
      final renderBox = gkey.currentContext!.findRenderObject() as RenderBox;
      tSize = renderBox.size;
      offset = renderBox.localToGlobal(Offset.zero);
    });
  }

  late Offset offset;
  late Size tSize;
  GlobalKey gkey = GlobalKey();
  final OverlayPortalController _portalController = OverlayPortalController();
  @override
  Widget build(BuildContext context) {
    Widget textfield() => TextFormField(
          key: gkey,
          decoration: InputDecoration(
            focusedBorder: OutlineInputBorder(
              borderSide: BorderSide(
                color: Colors.black.withOpacity(0.8),
              ),
            ),
            border: const OutlineInputBorder(
              borderSide: BorderSide(color: Colors.red),
            ),
          ),
          onTap: () {
            print("offset: $offset, size= $tSize");
            if (!_portalController.isShowing) {
              _portalController.show();
            }
          },
          onChanged: (query) {},
        );
    
    final size = MediaQuery.of(context).size;
    final padding = MediaQuery.of(context).padding;
    print(padding);
//     final rightOffset = size.width - tSize.width - offset.dx;
    return OverlayPortal(
        controller: _portalController,
        overlayChildBuilder: (BuildContext context) {
          return Positioned(
              right: 0,
              left: offset.dx,
              top: offset.dy + tSize.height, // + textfield height
              child: Material(color: Colors.red, child: _list()));
        },
        child: textfield());
  }
}

maheshj01 avatar May 26 '23 19:05 maheshj01