繁体   English   中英

Flutter:使列表可滚动

[英]Flutter: Make list scrollable

这是一个典型的问题,可能被认为是低质量的,但我已经研究了大约两个小时,我只是想更好地理解这段代码,所以不仅仅是告诉我如何修复,你能不能也请解释一下发生了什么。 我相信对于比我更有经验的人来说,应该很容易发现。

我正在尝试制作一个可滚动的列表,并绘制列表的每一行,并能够单击每个行项目。 但是我的应用程序绘制了所有项目,但我只能看到一些项目,只要屏幕允许,这意味着它是不可滚动的。

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: AppBar(
      title: const Text('Some App Page'),
    ),
    body: ListView(
      children: <Widget>[
        Stack(
          alignment: const Alignment(1.0, 1.0),
          children: <Widget>[
            TextField(
              controller: cityController,
              keyboardType: TextInputType.number,
              decoration: const InputDecoration(hintText: 'Enter city...'),
            ),
            TextButton(
              onPressed: () {
                cityController.clear();
              },
              child: const Icon(Icons.clear),
            ),
          ],
        ),
        ElevatedButton(
          onPressed: () {
            _futureTime = fetchTimes(int.parse(cityController.text));
            if (cityController.text.isNotEmpty) {
              setState(() {
                cityController.clear(); // Clear value
              }); // clear the textField
              FocusScope.of(context)
                  .requestFocus(FocusNode()); // hide the keyboard
            }
          },
          child: const Text('Get City', style: TextStyle(fontSize: 20)),
        ),
        Column(
          children: <Widget>[
            Center(
              child: FutureBuilder<Times>(
                future: _futureTime,
                builder: (context, snapshot) {
                  if (!snapshot.hasData) {
                    return const CircularProgressIndicator();
                  }
                  return ListView.builder(
                    scrollDirection: Axis.vertical,
                    shrinkWrap: true,
                    itemBuilder: (BuildContext context, int index) {
                      return myTimeCard( date, index);
                    },
                    itemCount: data == null ? 0 : data.length,
                  );
                },
              ),
            ),
          ],
        ),
      ],
    ),
  );
}

Widget myTimeCard(String date, int index) {
  return InkWell(
    onTap: () {
      // Navigate to the next page & pass data.
      print("tapped, -> " + index.toString()); // for debugging purpose!
    },
    child: Stack(
      children: <Widget>[
        Opacity(
          opacity: 1,
          child: Container(
            decoration: BoxDecoration(
              borderRadius: BorderRadius.circular(8.0),
            ),
          ),
        ),
        Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Row(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                Padding(
                  padding: const EdgeInsets.only(right: 16.0),
                  child: Text(
                    index.toString(),
                    style: const TextStyle(
                        color: Colors.black,
                        fontSize: 22.0,
                        fontWeight: FontWeight.bold),
                  ),
                ),
              ],
            )
          ],
        )
      ],
    ),
  );
}

您正在使用两个相互嵌套的ListView 在这种情况下,您可能需要让 Flutter 知道哪个 ListView 是主要的。 因此,有一个名为primary的属性。 尝试将内部 Listview 的 primary 设置为false

return ListView.builder(
                primary: false,
                scrollDirection: Axis.vertical,
                shrinkWrap: true,
                itemBuilder: (BuildContext context, int index) {
                  return myTimeCard( date, index);
                },
                itemCount: data == null ? 0 : data.length,
              );

您分享的代码无法编译,因为我没有额外的上下文,所以我不得不花费一些时间才能使其编译,请确保将来提供可编译的代码。

您面临的问题是因为主ListView正在控制滚动,要查看效果尝试通过按住Get City按钮的屏幕滚动。

解决这个问题的方法有很多,看你的目标,是想让整个屏幕滚动,还是只是数据列表

方式 1. 使整个屏幕可滚动:通过将滚动控制保持在主ListView中,并使所有下降的小部件不可滚动,在您的情况下,通过使包装数据的小部件成为Column而不是ListView

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final TextEditingController cityController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Some App Page'),
      ),
      body: ListView(
        children: <Widget>[
          Stack(
            alignment: const Alignment(1.0, 1.0),
            children: <Widget>[
              TextField(
                controller: cityController,
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(hintText: 'Enter city...'),
              ),
              TextButton(
                onPressed: () {
                  cityController.clear();
                },
                child: const Icon(Icons.clear),
              ),
            ],
          ),
          ElevatedButton(
            onPressed: () {
              _futureTime = fetchTimes(int.parse(cityController.text));
              if (cityController.text.isNotEmpty) {
                setState(() {
                  cityController.clear(); // Clear value
                }); // clear the textField
                FocusScope.of(context)
                    .requestFocus(FocusNode()); // hide the keyboard
              }
            },
            child: const Text('Get City', style: TextStyle(fontSize: 20)),
          ),
          Column(
            children: <Widget>[
              Center(
                child: FutureBuilder<Times>(
                  future: _futureTime,
                  builder: (context, snapshot) {
                    // if (!snapshot.hasData) {
                    //   return const CircularProgressIndicator();
                    // }

                    final data =

                        // snapshot.data;
                        List.generate(50, (index) => index.toString());

                    return Column(
                      children: [
                        for (int i = 0; i < data.length; i++)
                          myTimeCard(data[i], i)
                      ],
                    );
                  },
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  Widget myTimeCard(String date, int index) {
    return InkWell(
      onTap: () {
        // Navigate to the next page & pass data.
        print("tapped, -> " + index.toString()); // for debugging purpose!
      },
      child: Stack(
        children: <Widget>[
          Opacity(
            opacity: 1,
            child: Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8.0),
              ),
            ),
          ),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.only(right: 16.0),
                    child: Text(
                      index.toString(),
                      style: const TextStyle(
                          color: Colors.black,
                          fontSize: 22.0,
                          fontWeight: FontWeight.bold),
                    ),
                  ),
                ],
              )
            ],
          )
        ],
      ),
    );
  }
}

方式2.使非数据小部件不可滚动,并将滚动控件保留在数据小部件中:可以通过将主ListView转换为不可滚动的小部件(在您的情况下为Column )并将数据列表包装在Expanded的小部件,因此它占用了它可以拥有的所有空间(有关扩展的更多信息)

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

  @override
  State<HomeScreen> createState() => _HomeScreenState();
}

class _HomeScreenState extends State<HomeScreen> {
  final TextEditingController cityController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Some App Page'),
      ),
      body: Column(
        children: <Widget>[
          Stack(
            alignment: const Alignment(1.0, 1.0),
            children: <Widget>[
              TextField(
                controller: cityController,
                keyboardType: TextInputType.number,
                decoration: const InputDecoration(hintText: 'Enter city...'),
              ),
              TextButton(
                onPressed: () {
                  cityController.clear();
                },
                child: const Icon(Icons.clear),
              ),
            ],
          ),
          ElevatedButton(
            onPressed: () {
              _futureTime = fetchTimes(int.parse(cityController.text));
              if (cityController.text.isNotEmpty) {
                setState(() {
                  cityController.clear(); // Clear value
                }); // clear the textField
                FocusScope.of(context)
                    .requestFocus(FocusNode()); // hide the keyboard
              }
            },
            child: const Text('Get City', style: TextStyle(fontSize: 20)),
          ),
          FutureBuilder<Times>(
            future: _futureTime,
            builder: (context, snapshot) {
              // if (!snapshot.hasData) {
              //   return const CircularProgressIndicator();
              // }

              final data =

                  // snapshot.data;
                  List.generate(50, (index) => index.toString());

              return Expanded(
                child: ListView.builder(
                  scrollDirection: Axis.vertical,
                  shrinkWrap: true,
                  itemBuilder: (BuildContext context, int index) {
                    return myTimeCard(date, index);
                  },
                  itemCount: data == null ? 0 : data.length,
                ),
              );
            },
          ),
        ],
      ),
    );
  }

  Widget myTimeCard(String date, int index) {
    return InkWell(
      onTap: () {
        // Navigate to the next page & pass data.
        print("tapped, -> " + index.toString()); // for debugging purpose!
      },
      child: Stack(
        children: <Widget>[
          Opacity(
            opacity: 1,
            child: Container(
              decoration: BoxDecoration(
                borderRadius: BorderRadius.circular(8.0),
              ),
            ),
          ),
          Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Padding(
                    padding: const EdgeInsets.only(right: 16.0),
                    child: Text(
                      index.toString(),
                      style: const TextStyle(
                          color: Colors.black,
                          fontSize: 22.0,
                          fontWeight: FontWeight.bold),
                    ),
                  ),
                ],
              )
            ],
          )
        ],
      ),
    );
  }
}

问题来了,因为我们有两个可滚动的ListView 虽然它们都是可滚动的,但当内部ListView获得焦点并且父级变得不聚焦并且滚动事件仅影响内部ListView并且您不能回滚到父级ListView时滚动时,一个简单的解决方案将在内部ListView.builder上使用NeverScrollableScrollPhysics .

child: ListView.builder(
  physics: NeverScrollableScrollPhysics(),
  scrollDirection: Axis.vertical,
singleChildScrollView(
child: ListView.builder(
   sinkwrap:true,
  physics: NeverScrollableScrollPhysics(),
  scrollDirection: Axis.vertical,)
)

简单易行

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM