【问题标题】:Automatic onTap action of GestureDector widget within horizontal ListView水平 ListView 中 GestureDector 小部件的自动 onTap 操作
【发布时间】:2019-03-02 18:01:30
【问题描述】:

我正在尝试创建一个水平的容器列表视图,这些容器在点击时会改变颜色。我想制作“按下”和“未按下”,这样一次只能按下一个容器,如果按下另一个容器,则之前按下的容器将重新绘制为未按下的颜色。我打算使用带有回调函数的有状态小部件来解决此问题,该回调函数使用 setState 方法更改颜色并更新包含每个容器的颜色状态的地图。

一开始我只是想打印到我正在按下的容器的控制台,但它似乎一次按下了多个容器。我怎样才能解决这个问题?如果有更好的方法来改变容器的颜色,请分享。

容器小部件代码:

class Box extends StatefulWidget {
  int color;
  int index;
  Function callback;

  Box(this.color, this.index, this.callback);

  @override
  _BoxState createState() => _BoxState(color, index, callback);
}

class _BoxState extends State<Box> {
  int color;
  int index;
  Function callback;

  _BoxState(this.color, this.index, this.callback);

  @override
  Widget build(BuildContext context) {
    return GestureDetector(
        onTap: callback(index),
        child: Container(
            width: 150.0,
            decoration: new BoxDecoration(
              color: Color(color),
              shape: BoxShape.circle,
            ),
            child: Center(child: Text("${index + 1}"))));
  }
}

我实现水平列表视图的页面:

class TestPage extends StatelessWidget {
  int _selected;


  var pressStates = {
    //Color states of each container
    //unpressed = 0xFFD0D0DE
    //pressed = 0xFF8A2BE2

    1: 0xFFD0D0DE,
    2: 0xFFD0D0DE,
    3: 0xFFD0D0DE,
    4: 0xFFD0D0DE,
    5: 0xFFD0D0DE,
    6: 0xFFD0D0DE,
    7: 0xFFD0D0DE,
    8: 0xFFD0D0DE,
    9: 0xFFD0D0DE,
    10: 0xFFD0D0DE,
    11: 0xFFD0D0DE,
    12: 0xFFD0D0DE,
  };

  @override
  Widget build(BuildContext context) {
    var _width = MediaQuery.of(context).size.width;

    callback(int index) {
      _selected = index + 1;
      print("tapped ${index + 1}, state: ${_selected}");
    }

    final _test = ListView.builder(
        scrollDirection: Axis.horizontal,
        itemCount: pressStates.length,
        itemBuilder: (context, index) {
          return Box(pressStates[index + 1], index, callback);
        });

    return new Scaffold(
      backgroundColor: Colors.black54,
      body: new Container(height: 300.0, width: _width, child: _test),
    );
  }
}

控制台输出:

I/flutter (11600): tapped 1, state: 1
I/flutter (11600): tapped 2, state: 2
I/flutter (11600): tapped 3, state: 3
I/flutter (11600): tapped 4, state: 4
I/flutter (11600): tapped 5, state: 5

【问题讨论】:

    标签: dart flutter


    【解决方案1】:

    如果您将onTap 属性替换为

    ,您的代码将正常打印
    onTap: () { callback(index); },
    

    但是您应该重构代码以使 Test 类成为 StatefulWidget,因为它保存了所选圆圈的状态。并使 Box 无状态。

    import 'package:flutter/material.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Flutter Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: TestPage(),
        );
      }
    }
    
    class TestPage extends StatefulWidget {
      @override
      TestPageState createState() {
        return new TestPageState();
      }
    }
    
    class TestPageState extends State<TestPage> {
      int _selected;
    
      var selectedColor = 0xFFD000DE;
      var unselectedColor = 0xFFD0D0DE;
    
      callback(int index) {
        _selected = index;
        setState(() {});
        print("tapped ${index + 1}, state: ${_selected}");
      }
    
      @override
      Widget build(BuildContext context) {
        var _width = MediaQuery.of(context).size.width;
    
        final _test = ListView.builder(
            scrollDirection: Axis.horizontal,
            itemCount: 12,
            itemBuilder: (context, index) {
              return Box(
                _selected == index ? selectedColor : unselectedColor,
                index,
                callback,
              );
            });
    
        return new Scaffold(
          backgroundColor: Colors.black54,
          body: Container(height: 300.0, width: _width, child: _test),
        );
      }
    }
    
    class Box extends StatelessWidget {
      final int color;
      final int index;
      final Function callback;
    
      Box(this.color, this.index, this.callback);
    
      @override
      Widget build(BuildContext context) {
        return GestureDetector(
            onTap: () {
              callback(index);
            },
            child: Container(
                width: 150.0,
                decoration: new BoxDecoration(
                  color: Color(color),
                  shape: BoxShape.circle,
                ),
                child: Center(child: Text("${index + 1}"))));
      }
    }
    

    【讨论】:

    • 这行得通!快速提问为什么 setState 方法没有函数使用?我以为 _selected = index 会在里面
    • 还有什么是typedef VoidCallback MyCallback(int index);
    • `setState()' 只是添加了一些断言并检查函数是否为未来。除此之外,在外面调用这个函数和在里面调用它的效果是一样的。
    • 我已经删除了 MyCallback()。这是一些测试的剩余部分。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多