如何在一屏中使用多滚动-Flutter

how to use multi scroll in one screen -Flutter

我想像 trello 一样在 flutter 中创建一个网页 ui,因为我想要一个水平主滚动条和一个垂直辅助滚动条,但我无法在列中垂直滚动我附加了我想要创建的内容和我的代码,如果您仍然不明白,请告诉我

这是我的代码:-


class PlaningWeekScreenWeb extends StatelessWidget {
  const PlaningWeekScreenWeb({Key? key}) : super(key: key);

  // Use this for set width of card and row in list
  final double cardWidth = 180.0;
  @override
  Widget build(BuildContext context) {
    return Row(
      children: [
        Expanded(child: _getSideMenu()),
        Container(
          height: Get.height,
          width: 1,
          color: scrollBarColor,
        ),
        Expanded(
          child: _getMainScreen(),
          flex: 6,
        ),
      ],
    );
  }

  Widget _getMainScreen() {
    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      child: ListView.builder(
          itemCount: 4,
          shrinkWrap: true,
          physics: NeverScrollableScrollPhysics(),
          scrollDirection: Axis.horizontal,
          padding: EdgeInsets.zero,
          itemBuilder: (context, i) {
            return Row(
              children: [
                Column(
                  mainAxisAlignment: MainAxisAlignment.start,
                  children: [
                    SizedBox(
                      width: cardWidth,
                      child: Row(
                        children: [
                          (10.0).addWSpace(),
                          "29".h3(
                              size: 25,
                              weight: FontWeight.w700,
                              color: GrayColor),
                          (5.0).addWSpace(),
                          Expanded(
                              child: "Sun".h3(
                                  color: GrayColor,
                                  weight: FontWeight.w400,
                                  size: 15)),
                          (10.0).addWSpace(),
                        ],
                      ),
                    ),
                    Container(
                      color: scrollBarColor,
                      height: 1,
                      width: cardWidth,
                    ),
                    SizedBox(
                      width: cardWidth,
                      child: Row(
                        crossAxisAlignment: CrossAxisAlignment.start,
                        children: [
                          SingleChildScrollView(
                            primary: false,
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.start,
                              children: [
                                PlaningWeekCard(
                                  device: Device.Web,
                                  onTap: () {},
                                  width: cardWidth,
                                ),
                                PlaningWeekCard(
                                  device: Device.Web,
                                  onTap: () {},
                                  width: cardWidth,
                                ),
                                PlaningWeekCard(
                                  device: Device.Web,
                                  onTap: () {},
                                  width: cardWidth,
                                ),
                                PlaningWeekCard(
                                  device: Device.Web,
                                  onTap: () {},
                                  width: cardWidth,
                                ),
                                PlaningWeekCard(
                                  device: Device.Web,
                                  onTap: () {},
                                  width: cardWidth,
                                ),
                                PlaningWeekCard(
                                  device: Device.Web,
                                  onTap: () {},
                                  width: cardWidth,
                                ),
                              ],
                            ),
                          ),
                          Container(
                            height: Get.height,
                            width: 1,
                            color: scrollBarColor,
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ],
            );
          }),
    );
  }

  Widget _getSideMenu() {
    return Container(
      height: Get.height,
      // width: 220,
      child: SingleChildScrollView(
        padding: EdgeInsets.zero,
        child: Column(
          mainAxisAlignment: MainAxisAlignment.start,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            "Employers".h3(weight: FontWeight.w700, size: 22),
            (10.0).addHSpace(),
            PerytonSearchField(
              hintText: 'Name',
            ),
            (10.0).addHSpace(),
            ExpansionTile(
              title: Row(
                children: [
                  PerytonCheckBox(val: false),
                  (5.0).addWSpace(),
                  Expanded(child: "Codonnier Offieces".expansionTileTittleWeb())
                ],
              ),
              children: [
                _getRow("Norway office"),
                _getRow("Surat office"),
                _getRow("Bardoli office"),
                _getRow("Usa office"),
              ],
            ),
            (10.0).addHSpace(),
            ExpansionTile(
              title: Row(
                children: [
                  PerytonCheckBox(val: false),
                  (5.0).addWSpace(),
                  Expanded(child: "Codonnier Branches".expansionTileTittleWeb())
                ],
              ),
              children: [
                _getRow("Amsterdam office"),
                _getRow("Surat office"),
                _getRow("Suart-6 office"),
                _getRow("california office"),
              ],
            ),
            (10.0).addHSpace(),
            ExpansionTile(
              title: Row(
                children: [
                  PerytonCheckBox(val: false),
                  (5.0).addWSpace(),
                  Expanded(
                      child: "Codonnier sub branches".expansionTileTittleWeb())
                ],
              ),
              children: [
                _getRow("van gogh branch"),
                _getRow("Mota varacha branch"),
                _getRow("vesu branch"),
                _getRow("san francisco office"),
              ],
            ),
            (10.0).addHSpace(),
            "Workers".h3(weight: FontWeight.w700, size: 22),
            (10.0).addHSpace(),
            PerytonSearchField(
              hintText: 'Name',
            ),
            (10.0).addHSpace(),
            _getRow("Harsh codonnier"),
            (10.0).addHSpace(),
            _getRow("Dipak codonnier"),
            (10.0).addHSpace(),
            _getRow("Subham codonnier"),
            (10.0).addHSpace(),
            _getRow("ravi codonnier"),
            (10.0).addHSpace(),
          ],
        ).pSymmetricOnly(horizontal: 10),
      ),
    );
  }

  Widget _getRow(String name) {
    return Row(
      children: [
        PerytonCheckBox(val: false),
        (5.0).addWSpace(),
        Expanded(child: name.expansionTileWeb())
      ],
    );
  }
}


这是我的卡片小工具:-

class PlaningDayCard extends StatelessWidget {
  PlaningDayCard(
      {Key? key,
      required this.device,
      required this.onTap,
      required this.width})
      : super(key: key);
  final Device device;
  final double width;
  final Function onTap;
  @override
  Widget build(BuildContext context) {
    return ResponsiveWidget(
        mobile: _getMobileCard(),
        tablet: _getWebCard(),
        desktop: _getWebCard(),
        device: device);
  }

  Widget _getWebCard() {
    return SizedBox(
      width: width - 2,
      child: Card(
          color: Colors.white,
          shape: RoundedRectangleBorder(
            side: BorderSide(color: Colors.white, width: 0.0),
            borderRadius: BorderRadius.circular(15),
          ),
          child: Material(
            borderRadius: BorderRadius.circular(15),
            clipBehavior: Clip.antiAlias,
            color: Colors.transparent,
            child: InkWell(
              onTap: () {
                onTap.call();
              },
              child: Column(
                mainAxisAlignment: MainAxisAlignment.start,
                children: [
                  Row(
                    children: [
                      Expanded(
                        child: "Scrubbing sinks, tubs, showers"
                            .h2(weight: FontWeight.w700, size: 15),
                      ),
                    ],
                  ),
                  (6.0).addHSpace(),
                  Row(
                    children: [
                      ImageAssetIconWithColor(
                        color: GrayColor,
                        size: 15,
                        image: ImageIcons.icTriangle,
                      ),
                      (8.0).addWSpace(),
                      Expanded(
                        child: "Main Office".h2(
                            weight: FontWeight.w500,
                            color: GrayColor,
                            size: 14),
                      ),
                    ],
                  ),
                  (8.0).addWSpace(),
                  Row(
                    mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      "09:00—13:00".h2(
                          weight: FontWeight.w700, color: GrayColor, size: 13),
                    ],
                  )
                ],
              ).pSymmetricOnly(vertical: 5, horizontal: 6),
            ),
          )),
    );
  }

  Widget _getMobileCard() {
    return SizedBox(
      width: width - 2,
      child: Card(
          color: Colors.white,
          shape: RoundedRectangleBorder(
            side: BorderSide(color: Colors.white, width: 0.0),
            borderRadius: BorderRadius.circular(15.sp),
          ),
          child: Material(
            borderRadius: BorderRadius.circular(15.sp),
            clipBehavior: Clip.antiAlias,
            color: Colors.transparent,
            child: InkWell(
              onTap: () {
                onTap.call();
              },
              child: Column(
                children: [],
              ),
            ),
          )),
    );
  }
}

完成运行代码:

import 'package:flutter/material.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {

return MaterialApp(
  home: Scaffold(
    body: SafeArea(
      child: SingleChildScrollView(
        child: Container(
                height: 200,
                child: GridView.count(
                  scrollDirection: Axis.horizontal,
                  crossAxisCount: 1 ,
                  children: List.generate(50,(index){
                    return Container(
                      child: Card(
                        child: ListView(
                  shrinkWrap: true,
                  scrollDirection: Axis.vertical,
                  children: <Widget>[
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.yellowAccent,
                    ),
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.blue,
                    ),
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.green,
                    ),
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.red,
                    ),Container(
                      width: 50,
                      height: 100,
                      color: Colors.yellowAccent,
                    ),
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.blue,
                    ),
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.green,
                    ),
                    Container(
                      width: 50,
                      height: 100,
                      color: Colors.red,
                   )
                  ],
                ),
                        color: Colors.amber,
                      ),
                    );

                  }),
                ),
              )         ),
    ),
  ),
);
  }
}
class myScroll extends MaterialScrollBehavior {
@override
Set<PointerDeviceKind> get dragDevices => {
PointerDeviceKind.touch,
PointerDeviceKind.mouse,

};
} 

SingleChildScrollView 环绕您要滚动的每个页面。 还要提到 scrollDirection: Axis.vertical.

希望有用! :)

You can achieve this with more than one ways. But I think the simplest way is that make Row as parent widget put all the ListView in Row after wrapping every ListView by Expanded widget.

Widget build(BuildContext context) {
return Scaffold(
  appBar: AppBar(
    title: Text(widget.title),
  ),
  body: Padding(
    padding: const EdgeInsets.symmetric(horizontal: 10.0),
    child: Row(
      children: <Widget>[
        Expanded(
          child: ListView.separated(
            itemCount: 10,
            controller: ScrollController(),
            separatorBuilder: (_, __) => const SizedBox(height: 10),
            itemBuilder: ((context, index) => Container(
                  height: 80,
                  width: double.infinity,
                  color: Colors.red,
                )),
          ),
        ),
        const SizedBox(width: 10),
        Expanded(
          child: ListView.separated(
            controller: ScrollController(),
            itemCount: 2,
            separatorBuilder: (_, __) => const SizedBox(height: 10),
            itemBuilder: ((context, index) => Container(
                  height: 100,
                  width: double.infinity,
                  color: Colors.yellow,
                )),
          ),
        ),
        const SizedBox(width: 10),
        Expanded(
          child: ListView.separated(
            controller: ScrollController(),
            itemCount: 6,
            separatorBuilder: (_, __) => const SizedBox(height: 10),
            itemBuilder: ((context, index) => Container(
                  height: 70,
                  width: double.infinity,
                  color: Colors.green,
                )),
          ),
        )
      ],
    ),
  ),
);

}

  1. 首先必须用单个滚动子视图包装它。
  2. 然后把它包成行,
  3. 然后将其包装在 ListView 中
  4. 使用扩展,这样一切都可以看到。

希望这对你有用。

完整的测试代码

import 'dart:math';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';

class TrelloExample extends StatefulWidget {
  const TrelloExample({Key? key}) : super(key: key);

  @override
  State<TrelloExample> createState() => _TrelloExampleState();
}

class _TrelloExampleState extends State<TrelloExample> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      backgroundColor: Colors.white,
      body: Padding(
        padding: const EdgeInsets.only(top: 64.0),
        child: ScrollConfiguration(
           behavior: ScrollConfiguration.of(context).copyWith(
            dragDevices: {
              PointerDeviceKind.touch,
              PointerDeviceKind.mouse,
            },
          ),
          child: SingleChildScrollView(
            physics: const ClampingScrollPhysics(),
            scrollDirection: Axis.horizontal,
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: List.generate(
                16,
                (index) => SingleChildScrollView(
                  physics: const ClampingScrollPhysics(),
                  child: Padding(
                    padding: EdgeInsets.only(
                        right: 16.0, left: index == 0 ? 16.0 : 0.0),
                    child: Column(
                      children: List.generate(
                        index % 2 == 1
                            ? 16
                            : index % 3 == 1
                                ? 8
                                : index % 1 == 1
                                    ? 4
                                    : 6,
                        (index) => Padding(
                          padding: const EdgeInsets.only(bottom: 16.0),
                          child: Material(
                            elevation: 4.0,
                            child: Container(
                              padding: const EdgeInsets.all(38.0),
                              color: Color(
                                      (Random().nextDouble() * 0xFFFFFF).toInt())
                                  .withOpacity(1.0),
                              child: Text(
                                "Trello Ticket Item $index",
                                style: const TextStyle(
                                  fontSize: 16.0,
                                  color: Colors.black,
                                  fontWeight: FontWeight.bold,
                                ),
                              ),
                            ),
                          ),
                        ),
                      ),
                    ),
                  ),
                ),
              ),
            ),
          ),
        ),
      ),
    );
  }
}