AbdulRahmanAlHamali / flutter_typeahead

A TypeAhead widget for Flutter, where you can show suggestions to users as they type
BSD 2-Clause "Simplified" License
831 stars 351 forks source link

Suggestion box height not adjusting after SlideTransition #85

Closed purtato closed 5 years ago

purtato commented 5 years ago

When triggering a SlideTransition by selecting the TypeAhead, the height of the suggestion box is not recalculated.

Slide Transition moved the TypeAhead in the direction of the arrow: screenshot_modified

I looked at the way TypeAhead handles this on scrolling, but there is no Animation equivalent of Scrollable.of() that I am aware of and I couldn't think of another solution without an ugly api change

KaYBlitZ commented 5 years ago

Can you post the code you used? I have never used a SlideTransition and would like to see how it works.

purtato commented 5 years ago

Adaption of example2:

import 'package:keyboard_visibility/keyboard_visibility.dart';

...

class _FormExampleState extends State<FormExample> with SingleTickerProviderStateMixin, WidgetsBindingObserver {
  final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
  final TextEditingController _typeAheadController = TextEditingController();

  String _selectedCity;

  Animation<Offset> _anim;
  AnimationController _animController;

  @override
  void initState() {

    WidgetsBinding.instance.addObserver(this);

    _animController = AnimationController(
        vsync: this,
        duration: Duration(milliseconds: 300),
        value: 0.0
    );

    // -2.5 refers to moving upwards of 2.5 * height of widget in question
    // proper code would be more verbose with actual pixel calculations
    _anim = MaterialPointArcTween(begin: Offset.zero, end: Offset(0, -2.5)).animate(_animController);

    KeyboardVisibilityNotification().addNewListener(
      onChange: (bool visible) {
        if (visible) {
          _animController.forward();
        } else {
          _animController.reverse(from: 1.0);
        }
      },
    );

    super.initState();
  }

  @override
  void dispose() {
    _animController.dispose();
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Form(
      key: this._formKey,
      child: Padding(
        padding: EdgeInsets.all(32.0),
        child: Column(
          children: <Widget>[
            SizedBox(
              height: 100.0,
            ),
            Text('What is your favorite city?'),
            SlideTransition(
              position: _anim,
              child: TypeAheadFormField(
                textFieldConfiguration: TextFieldConfiguration(
                  decoration: InputDecoration(labelText: 'City'),
                  controller: this._typeAheadController,
                ),
                suggestionsCallback: (pattern) {
                  return CitiesService.getSuggestions(pattern);
                },
                itemBuilder: (context, suggestion) {
                  return ListTile(
                    title: Text(suggestion),
                  );
                },
                transitionBuilder: (context, suggestionsBox, controller) {
                  return suggestionsBox;
                },
                onSuggestionSelected: (suggestion) {
                  this._typeAheadController.text = suggestion;
                },
                validator: (value) {
                  if (value.isEmpty) {
                    return 'Please select a city';
                  }
                },
                onSaved: (value) => this._selectedCity = value,
              ),
            ),
            SizedBox(
              height: 10.0,
            ),
            RaisedButton(
              child: Text('Submit'),
              onPressed: () {},
            )
          ],
        ),
      ),
    );
  }
}

My goal of this was to have adjacent elements fade while shifting the TypeAhead up instead of scrolling.

...

When I spoke of the not so nice api, I was thinking of passing the Animation<?> object to the TypeAhead then using:


// Note there are many animations that can perform movements and they don't necessarily use Animation<Offset>, this can't be checked by the type system
_movementAnimation.addStatusListener((status) {
  if (status == AnimationStatus.completed) {
    // resize()
  }
});

.. or more generically

_movementAnimation.addStatusListener((status) {
  // Animation is in progress
  if (status == AnimationStatus.forward || status == AnimationStatus.reverse) {
    // resize based on timer similar to scroll
  }
});
KaYBlitZ commented 5 years ago

This seems to be the same problem as #88 . This bug can be fixed by increasing the delay in the following lines of TypeAhead:

await Future.delayed(const Duration(milliseconds: 10));
timer += 10;

in _waitChangeMetrics.

So basically what is happening is that _waitChangeMetrics is waiting for the keyboard to be finished toggling before calculating the height. Since your animation is 300 ms, the keyboard toggles much faster and the height of the suggestions box is calculated mid animation. I was able to "fix" this problem by decreasing the animation time to 100 ms and increasing the TypeAhead delay to 150 ms. The suggestions box takes up the full size then, since the height is now calculated after the animation is already finished.

Not sure what a good solution is, since animation times are not constant. It would be nice to have an onAnimationCompleted callback then do something like TypeAhead.resize().

KaYBlitZ commented 5 years ago

Whoops. Just read the second part of your comment lol. That seems perfect. Think we can just expose the resize() call in TypeAhead to fix the problem.

KaYBlitZ commented 5 years ago

Got a fix working. Can you try my solution? In pubspec.yaml add:

flutter_typeahead:
    git:
      url: git://github.com/KaYBlitZ/flutter_typeahead.git
      ref: develop

I also added documentation in README. Basically, create a SuggestionsBoxController and call resize during the status change completions of the animation.

purtato commented 5 years ago

Just gave your solution a try and it works great!

Thanks for all your hard work

KaYBlitZ commented 5 years ago

Nice. Thanks for testing. Will merge into master hopefully in a couple of days. Still need to test the animation problem with dialogs in another issue.

KaYBlitZ commented 5 years ago

Fixed in v1.5.0