簡體   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