簡體   English   中英

如何構建一個點擊式可擴展容器

[英]How to build an on tap Expandable container

所以我試圖為我的 flutter 應用程序構建一個用戶 ID 頁面,您可以在其中點擊一個容器,容器高度會增加,並顯示一組不同的數據。 在展開時我還想添加一個可滾動的 tabview,這是問題的第二部分。

預期的用戶界面看起來像這樣https://i.stack.imgur.com/62sro.gif

我試過 Expanded 和 expansion tile,不能完全實現 output 還有其他方法可以實現嗎?

歡迎@Anand Pillai,

首先將此行添加到您的 pubspec.yaml expandable: ^5.0.1

試試這個代碼

import 'package:expandable/expandable.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyHomePage(),
    );
  }
}

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

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

class _MyHomePageState extends State<MyHomePage> {
  late PageController _pageController;
  final ExpandableController _controller = ExpandableController();

  int activePage = 1;
  int _counter = 0;
  List<String> images = [
    "https://images.pexels.com/photos/14686142/pexels-photo-14686142.jpeg",
    "https://wallpaperaccess.com/full/2637581.jpg",
    "https://uhdwallpapers.org/uploads/converted/20/01/14/the-mandalorian-5k-1920x1080_477555-mm-90.jpg"
  ];

  List<Widget> indicators(imagesLength, currentIndex) {
    return List<Widget>.generate(imagesLength, (index) {
      return Container(
        margin: const EdgeInsets.all(3),
        width: 10,
        height: 10,
        decoration: BoxDecoration(
            color: currentIndex == index ? Colors.white : Colors.blueGrey,
            shape: BoxShape.circle),
      );
    });
  }

  AnimatedContainer slider(images, pagePosition, active) {
    // double margin = active ? 10 : 20;

    return AnimatedContainer(
      duration: const Duration(milliseconds: 500),
      curve: Curves.easeInOutCubic,
      // margin: EdgeInsets.all(margin),
      decoration: BoxDecoration(
          image: DecorationImage(
        image: NetworkImage(images[pagePosition]),
        fit: BoxFit.cover,
      )),
    );
  }

  @override
  void initState() {
    super.initState();
    _pageController = PageController();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
        body: Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        SizedBox(
          width: MediaQuery.of(context).size.width,
          height: MediaQuery.of(context).size.height,
          child: Stack(
            alignment: Alignment.center,
            children: [imageSlider(), expandedWidget(context)],
          ),
        ),
      ],
    ));
  }

  Positioned expandedWidget(BuildContext context) {
    return Positioned.fill(
        bottom: _controller.expanded ? 0 : 60,
        left: 0,
        right: 0,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.end,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            _controller.expanded
                ? const SizedBox.shrink()
                : Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: indicators(images.length, activePage)),
            ExpandableNotifier(
                child: AnimatedContainer(
              height: _controller.expanded ? 400 : 110.0,
              width: double.infinity,
              alignment: Alignment.bottomCenter,
              padding: const EdgeInsets.all(15.0),
              margin: _controller.expanded
                  ? EdgeInsets.zero
                  : const EdgeInsets.all(8.0),
              decoration: BoxDecoration(
                color: const Color.fromARGB(255, 255, 79, 77).withOpacity(0.8),
                borderRadius: _controller.expanded
                    ? const BorderRadius.only(
                        topRight: Radius.circular(15),
                        topLeft: Radius.circular(15),
                      )
                    : BorderRadius.circular(15.0),
              ),
              duration: const Duration(milliseconds: 500),
              child: Column(
                children: <Widget>[
                  ScrollOnExpand(
                    scrollOnExpand: true,
                    scrollOnCollapse: false,
                    child: ExpandablePanel(
                      controller: _controller
                        ..addListener(() {
                          setState(() {});
                        }),
                      theme: const ExpandableThemeData(
                        headerAlignment: ExpandablePanelHeaderAlignment.center,
                        tapBodyToCollapse: true,
                        iconColor: Colors.white,
                      ),
                      header: Padding(
                          padding: const EdgeInsets.all(10),
                          child: Text(
                            "ExpandablePanel",
                            style: Theme.of(context)
                                .textTheme
                                .bodyText1!
                                .copyWith(color: Colors.white),
                          )),
                      collapsed: const Text(
                        "loremIpsum",
                        style: TextStyle(color: Colors.white),
                        softWrap: true,
                        maxLines: 2,
                        overflow: TextOverflow.ellipsis,
                      ),
                      expanded: Column(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: <Widget>[
                          for (var _ in Iterable.generate(5))
                            const Padding(
                                padding: EdgeInsets.only(bottom: 10),
                                child: Text(
                                  "loremIpsum",
                                  style: TextStyle(color: Colors.white),
                                  softWrap: true,
                                  overflow: TextOverflow.fade,
                                )),
                        ],
                      ),
                      builder: (_, collapsed, expanded) {
                        return Padding(
                          padding: const EdgeInsets.only(
                              left: 10, right: 10, bottom: 10),
                          child: Expandable(
                            collapsed: collapsed,
                            expanded: expanded,
                            theme: const ExpandableThemeData(crossFadePoint: 0),
                          ),
                        );
                      },
                    ),
                  ),
                ],
              ),
            )),
          ],
        ));
  }

  PageView imageSlider() {
    return PageView.builder(
        itemCount: images.length,
        physics: _controller.expanded
            ? const NeverScrollableScrollPhysics()
            : ScrollPhysics(),
        padEnds: false,
        controller: _pageController,
        onPageChanged: (page) {
          setState(() {
            activePage = page;
          });
        },
        itemBuilder: (context, pagePosition) {
          bool active = pagePosition == activePage;
          return slider(images, pagePosition, active);
        });
  }
}
class _MyHomePageState extends State<MyHomePage> {
  double _margin = 30, _height = 100, _width = 300;
  
  final Text _widget1 = const Text('This is my Foo');
  final Text _widget2 = const Text('This is Bar');
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
          child: GestureDetector(
        // When the child is tapped, set state is called.
        onTap: () {
          setState(() {
            _margin = _margin == 30 ? 0 : 30;
            _height = _height == 100 ? 300 : 100;
            _width = _width == 300 ? MediaQuery.of(context).size.width : 300;
          });
        },
        // The custom button
        child: Align(
          alignment: Alignment.bottomCenter,
          child: AnimatedContainer(
            width: _width,
            height: _height,
            curve: Curves.easeInExpo,
            margin: EdgeInsets.fromLTRB(_margin, 0, _margin, _margin),
            duration: Duration(milliseconds: 250),
            padding: const EdgeInsets.all(0),
            decoration: BoxDecoration(
              color: Colors.lightBlue,
              borderRadius: BorderRadius.circular(8.0),
            ),
            child: _margin == 30 ? _widget1 : _widget2,
          ),
        ),
      )),
    );
  }
}

簡單的邏輯是在點擊時為容器設置動畫並更改其中的小部件。 點擊它會調用 setsate 來設置容器的高度、寬度、邊距和子項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM