Skip to content

Instantly share code, notes, and snippets.

@NinoBass
Created February 2, 2026 09:07
Show Gist options
  • Select an option

  • Save NinoBass/f8df67b0f275f5b28139d287f3c844a1 to your computer and use it in GitHub Desktop.

Select an option

Save NinoBass/f8df67b0f275f5b28139d287f3c844a1 to your computer and use it in GitHub Desktop.
Search State Animation
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class AnimatedSwitcherWithFadeUi extends StatelessWidget {
const AnimatedSwitcherWithFadeUi({
required this.showMainWidget,
required this.mainWidget,
this.alignment = Alignment.topCenter,
this.duration = const Duration(milliseconds: 300),
this.animationAxis = Axis.vertical,
this.emptyWidget,
super.key,
});
final bool showMainWidget;
final Widget mainWidget;
final Widget? emptyWidget;
final Duration duration;
final Alignment alignment;
final Axis animationAxis;
@override
Widget build(BuildContext context) {
return AnimatedSwitcher(
duration: duration,
switchInCurve: Curves.fastOutSlowIn,
switchOutCurve: Curves.fastOutSlowIn,
layoutBuilder: (currentChild, previousChildren) {
return Stack(
alignment: Alignment.topCenter,
children: <Widget>[
...previousChildren,
if (currentChild != null) currentChild,
],
);
},
transitionBuilder: (child, animation) {
return FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axis: animationAxis,
axisAlignment: animationAxis == Axis.horizontal ? 1 : -1,
child: child,
),
);
},
child: showMainWidget ? emptyWidget : mainWidget,
);
}
}
class ContactsOverviewHeaderUi extends GetView<ContactsOverviewController> {
const ContactsOverviewHeaderUi({
super.key,
});
@override
ContactsOverviewController get controller => Get.isRegistered<ContactsOverviewController>()
? Get.find<ContactsOverviewController>()
: Get.put(ContactsOverviewController());
@override
Widget build(BuildContext context) {
return Obx(
() {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
AnimatedSwitcherWithFadeUi(
showMainWidget: controller.searchFieldIsFocused.value,
emptyWidget: const Gap.x4(),
mainWidget: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20).copyWith(bottom: 16, top: 20).r,
child: Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
TextUi(
LocaleKeys.contacts,
style: title1.copyWith(
fontSize: 28,
fontFamily: semiBoldText,
height: 1.r,
color: context.contentDefault,
),
),
if (controller.contacts.isNotEmpty) ...[
const Gap(8),
TextUi.body2(
controller.contacts.length == 1
? '1 ${context.tr(LocaleKeys.person)}'
: '${controller.contacts.length} ${context.tr(LocaleKeys.people)}',
localizeText: false,
fontFamily: regularText,
height: 1,
color: grayScale225,
).paddingOnly(bottom: 4.r),
],
],
),
),
),
if (controller.contacts.isNotEmpty) ...[
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20).r,
child: Row(
children: [
Expanded(
child: KeyedSubtree(
key: const ValueKey('contacts_search_field'),
child: FocusScope(
skipTraversal: true,
child: SearchFieldUi(
backgroundColor: context.backgroundDefaultTertiary,
hintText: context.tr(LocaleKeys.searchByNameCompany),
onChanged: controller.updateSearchQuery,
controller: controller.searchController,
onTap: () {
controller.searchFieldIsFocused
..value = true
..refresh();
},
suffixIcon: controller.searchQuery.isEmpty
? const SizedBox.shrink()
: GestureDetector(
onTap: () {
controller.clearQuery();
HapticFeedback.lightImpact();
},
child: Padding(
padding: const EdgeInsets.only(
left: 12,
right: 16,
).r,
child: SvgIconUi(
closeIcon,
width: 12.r,
height: 12.r,
color: grayScale600,
),
),
),
),
),
),
),
AnimatedSwitcherWithFadeUi(
duration: const Duration(milliseconds: 200),
showMainWidget: !controller.searchFieldIsFocused.value,
alignment: Alignment.centerRight,
animationAxis: Axis.horizontal,
emptyWidget: const SizedBox.shrink(),
mainWidget: GestureDetector(
onTap: () {
removePrimaryFocusFromUiElement(context);
controller.searchFieldIsFocused.value = false;
controller.clearQuery();
HapticFeedback.lightImpact();
},
child: Padding(
padding: const EdgeInsets.only(left: 8).r,
child: TextUi.body2(
LocaleKeys.cancel,
color: context.contentDefault,
),
),
),
),
],
),
),
],
],
);
},
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment