水平ListView中的GestureDector小部件的自动onTap操作

时间:2018-09-26 21:54:58

标签: dart flutter

我正在尝试创建一个水平的容器列表视图,这些容器在点击时会改变颜色。我要进行“按下”和“未按下”操作,以便一次只能按下一个容器,如果按下另一个容器,则以前按下的容器会重新涂成未按下的颜色。我打算使用带状态的窗口小部件来处理此问题,该窗口小部件具有使用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

1 个答案:

答案 0 :(得分:1)

如果您仅将onTap属性替换为

,您的代码就会显示正常
onTap: () { callback(index); },

但是您应该重构您的代码以使Test类成为StatefulWidget,因为它保存选定圆的状态。并使盒子变成无状态。

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}"))));
  }
}