选择按钮时如何取消选择其他按钮?

时间:2021-06-17 05:50:57

标签: flutter dart flutter-provider

我正在构建一个折线图,可以通过选择来编辑这些点,但是,我希望这些点像单选按钮一样工作,一次只能选择一个。我现在无法让它工作:

enter image description here

图形是通过从 SQflite 获取数据来呈现的,然后我使用 Provider 来构建它

main.dart :

FutureProvider<List<Map<String, dynamic>>?>(
        create: (context) {
          return RecordsDatabase.instance.getRecords();
        },
        initialData: null,
        catchError: (_, __) => <Map<String, dynamic>>[
          {'error': 'Something went wrong'}
        ],
        child: (),
      )

首页

Consumer<List<Map<String, dynamic>>?>(
        builder: (context, List<Map<String, dynamic>>? records, child) {
      if (records == null) {
        return const CircularProgressIndicator();
      } else if (records.isNotEmpty && records.first.containsKey('error')) {
        return Text(records.first['error'] as String);
      } else {
        GraphState graph = GraphState(records: records, context: context);

        return MultiProvider(
          providers: [
            ChangeNotifierProvider<GraphState>(create: (_) => graph),
            ChangeNotifierProvider<ButtonMode>(
                create: (context) => ButtonMode())
          ],
          child: Scaffold(
            backgroundColor: Colors.black,
            body: Stack(children: [
              Center(
                  child: (records.isEmpty == true)
                      ? CircularProgressIndicator()
                      : graph.records.isEmpty
                          ? Text(
                              'No Records',
                              style:
                                  TextStyle(color: Colors.white, fontSize: 24),
                            )
                          : MyGraph()),

GraphState 模型在一个大列表中渲染点、线和指导线,然后在 MyGraph() 的 Stack 中渲染

GraphState({required this.records, required this.context}) {
        titles = renderSideTitleWeights();
    spots = renderSpots();
    spotLines = renderLines();
    horizontalGuidelines = renderHorizontalLines();
    graphList = new List.from(horizontalGuidelines)
      ..addAll(spotLines)
      ..addAll(spots);
  }


//render the spots of the graph
  //render the spots of the graph
  List<GraphSpot> renderSpots() {
   
    List<GraphSpot> spots = spotsXPos.mapIndexed<GraphSpot>((record, index) {
      return GraphSpot(
        x: record['xPos'],
        y: record['yPos'],
        date: record['record_date'],
        weight: record['weight'],
        id: index,
        selected: false,
             );
    }).toList();

    return spots;
  }

和 GraphSpot 小部件渲染图形上的点:

class GraphSpot extends StatefulWidget {
  final double x;
  final double y;
  final String date;
  final double weight;
  final int id;
  final bool selected;

  GraphSpot({
    required this.x,
    required this.y,
    required this.date,
    required this.weight,
    required this.id,
    required this.selected,
  });

  @override
  _GraphSpotState createState() => _GraphSpotState();
}

class _GraphSpotState extends State<GraphSpot> {
  @override
  Widget build(BuildContext context) {
    return Consumer<ButtonMode>( //ButtonMode change the add button to edit and delete
      builder: (context, buttonMode, child) {
        return Positioned(
          left: widget.x - 5, //minus half of the width of the spot to center
          bottom: widget.y -
              10, //minus half of the height of the spot and padding to center
          child: GestureDetector(
            onTap: () {
              !widget.selected
                  ? buttonMode.setEditing()
                  : buttonMode.setAdd();
        
            },
            child: Column(
              children: [
                Container(
                  width: 40,
                  decoration: new BoxDecoration(
                    color: Colors.lightGreen,
                    shape: BoxShape.rectangle,
                  ),
                  child: Text(widget.weight.toStringAsFixed(1),
                      textAlign: TextAlign.center,
                      style: TextStyle(
                          color: Colors.blue,
                          fontSize: 14,
                          fontWeight: FontWeight.bold)),
                ),
                DecoratedBox(
                  decoration: selected
                      ? BoxDecoration(
                          shape: BoxShape.circle,
                          border: Border.all(width: 3, color: Colors.red))
                      : BoxDecoration(shape: BoxShape.circle),
                  child: Padding(
                    padding: const EdgeInsets.all(5.0),
                    child: Container(
                      width: 10,
                      height: 10,
                      decoration: BoxDecoration(
                        color: Colors.blue,
                        shape: BoxShape.circle,
                      ),
                    ),
                  ),
                )
              ],
            ),
          ),
        );
      },
    );
  }
}

我不知道我的代码在哪里以及如何实现它。

1 个答案:

答案 0 :(得分:1)

我需要更多代码才能准确回答。

然而,一种解决方案是提升状态。

在 Flutter 中,将状态保持在使用它的小部件上方是有意义的。

因此呈现 GraphSpot 的 StatefulWidget 可以有一个 _selectedIndex 属性来保存所选索引。然后你可以将一个 onGraphSpotTap 函数传递给每个 GraphSpot Widget。

int? _selectedIndex;
 
List<GraphSpot> spots = spotsXPos.mapIndexed<GraphSpot>((record, index) {
  return GraphSpot(
    x: record['xPos'],
    y: record['yPos'],
    date: record['record_date'],
    weight: record['weight'],
    id: index,
    selected: index == _selectedIndex ? true : false,
    onGraphSpotTap: () {
        setState(() {
          _selectedIndex = index;
        });
      }

         );
}).toList();

然后在您的 GraphSpot 中添加新的 onGraphSpotTap 属性。

class GraphSpot extends StatelessWidget {
  .....
  final VoidCallback? onGraphSpotTap;

  ....
  onTap: onGraphSpotTap

不要忘记根据其选定的属性修改GraphSpot Widget渲染