如何为 flutter 中的搜索字段创建以下幻灯片过渡动画?

问题描述 投票:0回答:1

我是 flutter 新手,想构建一些小部件来练习。我正在尝试从 Zomato 应用程序开发这个搜索字段,该应用程序有一些动画。我已经完成了 UI,但无法实现动画。 文本字段的 GIF

我已经在提示文本上实现了滑动过渡,但它可以从 Offset(0, 1) 滑动到 Offset(0, 0) 或 Offset(0, 0) 滑动到 Offset(0, -1)。以下是我为从 (0, 1) 滑动到 (0, 0) 所做的代码。请给我一些想法如何实现这个动画?

import 'dart:async';

import 'package:flutter/material.dart';

class ZomatoTextField extends StatefulWidget {
  const ZomatoTextField({super.key});

  @override
  State<ZomatoTextField> createState() => _ZomatoTextFieldState();
}

class _ZomatoTextFieldState extends State<ZomatoTextField>
    with SingleTickerProviderStateMixin {
  late AnimationController controller;
  late Animation<Offset> slideAnimation;
  // late List<Text> textWidgetList;
  // final List<String> hintList = ['Ice Cream', 'Samosa', 'Biryani'];
  @override
  void initState() {
    controller = AnimationController(
      vsync: this,
      duration: const Duration(milliseconds: 300),
    );
    slideAnimation = Tween<Offset>(
      begin: const Offset(0, 1.5),
      end: Offset.zero,
    ).animate(
      CurvedAnimation(
        parent: controller,
        curve: Curves.ease,
      ),
    );
    Timer(const Duration(milliseconds: 2000), () {
      controller.forward();
    });
    // textWidgetList = List.generate(
    //     hintList.length,
    //     (index) => Text(
    //           hintList[index],
    //           style: const TextStyle(color: Color(0xff767C8F), fontSize: 16),
    //         ));
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      clipBehavior: Clip.hardEdge,
      height: 48,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: const BorderRadius.all(Radius.circular(16)),
        boxShadow: [
          BoxShadow(
            blurRadius: 2,
            color: Colors.grey.withOpacity(0.2),
            offset: const Offset(0, 0),
            spreadRadius: 3,
          ),
        ],
      ),
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      child: Row(
        children: [
          const Icon(
            Icons.search,
            color: Color(0xffE95161),
          ),
          const SizedBox(
            width: 8,
          ),
          Expanded(
            child: SlideTransition(
              position: slideAnimation,
              child: const Text(
                'Search "Ice Cream"',
                style: TextStyle(color: Color(0xff767C8F), fontSize: 16),
              ),
            ),
          ),
          // Expanded(
          //   child: Container(
          //     // color: Colors.red,
          //     child: Column(
          //       crossAxisAlignment: CrossAxisAlignment.start,
          //       children: [...textWidgetList],
          //     ),
          //   ),
          // ),
          const VerticalDivider(
            endIndent: 5,
            indent: 5,
          ),
          const Icon(
            Icons.mic_none_outlined,
            color: Color(0xffE95161),
          ),
        ],
      ),
    );
    // TextField(
    //   controller: TextEditingController(),
    //   showCursor: false,

    //   decoration: const InputDecoration(
    //       contentPadding: EdgeInsets.all(4),
    //       hintText: 'Search "Ice Cream"',
    //       border: OutlineInputBorder(

    //         borderRadius: BorderRadius.all(Radius.circular(16)),
    //       ),
    //       prefixIcon: Icon(
    //         Icons.search,
    //       ),
    //       suffixIcon: Row(
    //         mainAxisSize: MainAxisSize.min,
    //         children: [
    //           Icon(Icons.mic),
    //         ],
    //       )),
    // );
  }
}


flutter dart android-animation flutter-animation slide
1个回答
0
投票

您可以使用

ListWheelScrollView
来存档类似的效果。

class ZomatoTextField extends StatefulWidget {
  const ZomatoTextField({super.key});

  @override
  State<ZomatoTextField> createState() => _ZomatoTextFieldState();
}

class _ZomatoTextFieldState extends State<ZomatoTextField> with SingleTickerProviderStateMixin {
  late ScrollController controller = ScrollController();
  // late List<Text> textWidgetList;
  final List<String> hintList = ['Biriyani 😁', 'Ice Cream', 'Samosa'];

  late Timer timer;
  @override
  void initState() {
    super.initState();

    timer = Timer.periodic(const Duration(seconds: 2), (timer) {
      controller.animateTo(
        timer.tick % hintList.length * 48,
        duration: const Duration(milliseconds: 200),
        curve: Curves.easeIn,
      );
    });
  }

  @override
  void dispose() {
    timer.cancel();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      clipBehavior: Clip.hardEdge,
      height: 48,
      decoration: BoxDecoration(
        color: Colors.white,
        borderRadius: const BorderRadius.all(Radius.circular(16)),
        boxShadow: [
          BoxShadow(
            blurRadius: 2,
            color: Colors.grey.withOpacity(0.2),
            offset: const Offset(0, 0),
            spreadRadius: 3,
          ),
        ],
      ),
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      child: Row(
        children: [
          const Icon(Icons.search, color: Color(0xffE95161)),
          const SizedBox(width: 8),
          Expanded(
            child: ListWheelScrollView(
              itemExtent: 48,
              controller: controller,
              physics: const NeverScrollableScrollPhysics(),
              children: hintList
                  .map((e) => Align(
                        alignment: Alignment.centerLeft,
                        child: Text(
                          e,
                          style: TextStyle(color: Color(0xff767C8F), fontSize: 16),
                        ),
                      ))
                  .toList(),
            ),
          ),
          const VerticalDivider(endIndent: 5, indent: 5),
          const Icon(Icons.mic_none_outlined, color: Color(0xffE95161)),
        ],
      ),
    );
  }
}

AnimatedBuilder 将提供对 ux 的更多控制,您也可以使用 Transfrom.Offset。

© www.soinside.com 2019 - 2024. All rights reserved.