当我使用 ListView 时,ListTile OnTap 正在工作。但是当我使用 ListWheelScrollView 它不起作用

Posted

技术标签:

【中文标题】当我使用 ListView 时,ListTile OnTap 正在工作。但是当我使用 ListWheelScrollView 它不起作用【英文标题】:ListTile OnTap is working when I use ListView. But when i use ListWheelScrollView it doesnt work 【发布时间】:2019-10-08 21:04:37 【问题描述】:

当我使用 ListView 时,ListTile OnTap 正在工作。但是当我使用 ListWheelScrollView 时它不起作用。我的意思是它不会被窃听。视图发生变化。但我似乎无法点击它。我在很多地方和链接中寻找解决方案,但仍然找不到解决方案。

这些是我做的代码。

@override
  Widget build(BuildContext context) 
    return new ListWheelScrollView(
      physics:FixedExtentScrollPhysics(),
      children: getPostList(),
      itemExtent: 100.0,
    );
  

  List<PostListItem> getPostList() 
    return _postModal
        .map((contact) => new PostListItem(contact))
        .toList();
  

这就是我构建 ListTile 的地方

@override
  Widget build(BuildContext context) 
    return new ListTile(
      onTap:  () 
          var route = new MaterialPageRoute(
            builder: (BuildContext context) =>
                new OnTapPost(value: _postModal.fullName),
          );
          Navigator.of(context).push(route);
        ,
        leading: new Image.asset('assets/images/logo.png'),
        title: new Text(_postModal.fullName),
        subtitle: new Text(_postModal.email)
    );

  

在上面的代码中,列表项没有被点击。但是,如果我将 ListWheelScrollView 替换为 ListView ,如下所示,它可以完美运行。

@override
  Widget build(BuildContext context) 
    return new ListView(
      children: getPostList(),
    );
  

  List<PostListItem> getPostList() 
    return _postModal
        .map((contact) => new PostListItem(contact))
        .toList();
  

【问题讨论】:

这可能是个问题,您现在只需要使用不同类型的列表。见github.com/flutter/flutter/issues/38803 我猜终于发布了解决方案。它在链接pub.dev/packages/clickable_list_wheel_view 【参考方案1】:

更新:Flutter 团队的另一个外观尚未更新,但另一个 hack 解决方案。通过用 Gesturedetector 包装整个 listscrollwheel 小部件。每个滚动都使用列表滚动视图的“onSelectedItemChanged”设置状态。但是手势检测器小部件只有在点击时才会使用它。

  import 'package:flutter/cupertino.dart';
  import 'package:flutter/material.dart';
   
    
    class ServicesList extends StatefulWidget 
    
      final type;
    
      ServicesList(this.type);
    
      @override
      _ServicesListState createState() => _ServicesListState();
    
    
    class _ServicesListState extends State<ServicesList> 
    
      double _height ,_width;
      int serviceIndex;
      final FixedExtentScrollController _controller = FixedExtentScrollController();

 

List<Service> serviceList = [
    Service(name: 'service 1'),
    Service(name: 'service 4'),
    Service(name: 'service 3'),

];
    
      @override
      void initState() 
    
        serviceIndex = 0;
        // TODO: implement initState
        super.initState();
      
    
      detectService(index) 
        print('clicked container : $index'); //do whatever you want with the clicked index
      
    
    
      @override
      Widget build(BuildContext context) 
    
        _height = MediaQuery.of(context).size.height;
        _width = MediaQuery.of(context).size.width;
               
        return scrollWheel();
      
    
    
    
      Widget scrollWheel() 
        return GestureDetector(
          onTap: ()
            detectService(serviceIndex);
            ,
          child: ListWheelScrollView(
            controller: _controller,
            diameterRatio: 1.5,
            itemExtent: 80,
            onSelectedItemChanged: (e)=>
    
              setState(() 
                serviceIndex = e;
              )
            ,
            magnification: 0.2,
            physics: FixedExtentScrollPhysics(),
            children: serviceList.map((e) 
    
    
                return Container(
                  padding:  const EdgeInsets.all(6.0),
                  alignment: Alignment.center,
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(10.0),
                    color: Colors.blue,
                  ),
                  child:Text('item $e.name');
                );
          ).toList(), //List of widgets
          ),
        );
      
    
  
   class Service 
      String name;
 
     Service( this.name );
  

【讨论】:

【参考方案2】:

两到三年后,@TWL (https://github.com/flutter/flutter/issues/38803) 提供的链接中也进行了一次大讨论,该问题似乎已通过 ListWheelScrollView 的包装器解决,该包装器允许儿童响应 onTap 事件。 https://pub.dev/packages/clickable_list_wheel_view

虽然这些年来我现在不需要这个解决方案,但我希望它可以帮助其他想要解决这个问题的人。

干杯!

【讨论】:

【参考方案3】:

我有同样的问题 如果您仍想在您的情况下使用 ListWheelScrollView 而不是 ListView,

您可以将 ListWheelScrollView 包装在 GestureDetector 中,并制作一个您的 _postModals 列表。 使用 onSelectedItemChanged 确定当前选择的列表项索引,然后创建全局索引变量。这是我的意思的一个例子:

import 'package:flutter/material.dart';

class ListScrollWheelExample extends StatelessWidget 
@override
Widget build(BuildContext context) 

List<PostModal> _postModals = [
  //Add your postModals here
];
int Index;

return GestureDetector(
  onTap: ()
    var route = new MaterialPageRoute(
      builder: (BuildContext context) =>
      new OnTapPost(value: _postModals[Index].fullName),
    );
    Navigator.of(context).push(route);
  ,
  child: ListWheelScrollView(
    onSelectedItemChanged: (int index)
      Index = index;
    ,
    offAxisFraction: -0.85,
    diameterRatio: 0.75,
    physics: FixedExtentScrollPhysics(),
    itemExtent: 100,
    children: <Widget>[

      getPostList(),

    ],
  ),
);


在你的 ListTile 中:

leading: new Image.asset('assets/images/logo.png'),
title: new Text(_postModals[Index].fullName),
subtitle: new Text(_postModals[Index].email)

我使用这种方式是因为我仍然喜欢滚轮的外观,并且我不想转换为 ListView,但尽量不要使 ListWheelScrollView 的直径过大以保持点击功能按预期工作。

编辑: 如果您希望多个项目可点击(3 或 4 个可见项目),您可以将 ListWheelScrollView 包装在具有 3 或 4 个手势检测器的堆栈中。然后使用 Index-1 和 Index+1 ,...等

【讨论】:

这不能解决问题。问题是关于点击列表中的任何项目,而不仅仅是在 ListWheelScrollView 中心选择的项目, @BrysonThill 我的回答解决了这个问题,因为在我们的例子中,我们使用 FixedExtentScrollPhysics() ,它的用法主要用于单击 ScrollWheel 中的当前项目,而且它再次不是 ListView,不是所有项目都出现在前面。

以上是关于当我使用 ListView 时,ListTile OnTap 正在工作。但是当我使用 ListWheelScrollView 它不起作用的主要内容,如果未能解决你的问题,请参考以下文章