一尘不染

如何在Flutter中创建圆形ListView

flutter

如何在Flutter中创建圆形ListView?我想要一些可以让小部件列表围绕原点旋转的东西。

类似于以下内容: 与此类似。

任何帮助,将不胜感激。


阅读 578

收藏
2020-08-13

共1个答案

一尘不染

通告列表视图演示。可能对您有帮助。

Main.dart

import 'package:master/numbers_list.dart';
import 'package:master/radial_list.dart';
import 'package:meta/meta.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(MyHomePage());
}

class MyHomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      theme: new ThemeData(
        accentColor: Colors.blue,
      ),
      home: HomePage(),
    );
  }
}



class HomePage extends StatefulWidget {

  RadialListViewModel radialList;

  HomePage({
    @required this.radialList
  });

  @override
  HomePageState createState() {
    return new HomePageState();
  }
}

class HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: new AppBar(
        title: Text("My Home Page"),
      ),
      body: Stack(
        children: <Widget>[
          RadialList(
            radialList: radialNumbers,
            radius: 150.00,
          ),

        ],
      )
    );
  }
}

numbers_list.dart

import 'package:master/radial_list.dart';

final RadialListViewModel radialNumbers = new RadialListViewModel(
  items: [
    new RadialListItemViewModel(
      number: 1,
      isSelected: true,
    ),
    new RadialListItemViewModel(
      number: 2,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 3,
      isSelected: false,
    ),new RadialListItemViewModel(
      number: 4,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 5,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 6,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 7,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 8,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 9,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 10,
      isSelected: false,
    ),
    new RadialListItemViewModel(
      number: 11,
      isSelected: false,
    ),new RadialListItemViewModel(
      number: 12,
      isSelected: false,
    ),
  ]
);

radial_list.dart

import 'package:flutter/material.dart';
import 'dart:math';
import 'package:master/radial_position.dart';

class RadialList extends StatefulWidget {

  final RadialListViewModel radialList;
  final double radius;

  RadialList({
    this.radialList,
    this.radius,

  });

  List<Widget> _radialListItems(){

    final double firstItemAngle = pi;
    final double lastItemAngle = pi;
    final double angleDiff = (firstItemAngle + lastItemAngle) / (radialList.items.length);

    double currentAngle = firstItemAngle;
    return radialList.items.map((RadialListItemViewModel viewModel){
      final listItem = _radialListItem(viewModel,currentAngle);
      currentAngle += angleDiff;
      return listItem;
    }).toList();
  }

  Widget _radialListItem(RadialListItemViewModel viewModel, double angle){
      return Transform(
        transform: new Matrix4.translationValues(
          180.0,
          250.0,
          0.0
        ),
        child: RadialPosition(
          radius: radius,
          angle: angle,
          child: new RadialListItem(
            listItem: viewModel,
          ),
        ),
      );
  }

  @override
  RadialListState createState() {
    return new RadialListState();
  }
}

class RadialListState extends State<RadialList> {
  @override
  Widget build(BuildContext context) {
    return new Stack(
      children: widget._radialListItems(),
    );
  }
}

class RadialListItem extends StatefulWidget {

  final RadialListItemViewModel listItem;

  RadialListItem({
    this.listItem
  });

  @override
  RadialListItemState createState() {
    return new RadialListItemState();
  }

}

class RadialListItemState extends State<RadialListItem> {
  @override
  Widget build(BuildContext context) {
    return Transform(
      transform: new Matrix4.translationValues(-30.0, -30.0, 0.0),
      child: Container(
        width: 60.0,
        height: 60.0,
        decoration: new BoxDecoration(
          shape: BoxShape.circle,
          color: Colors.deepPurpleAccent,
          border: new Border.all(
            color: Colors.red,
            width: 2.0
          )
        ),
        child: Padding(
          padding: const EdgeInsets.all(0.0),
          child: OutlineButton(
            shape: new RoundedRectangleBorder(borderRadius: new BorderRadius.circular(60.0)),
            color: Colors.transparent,
            onPressed: () {
              setState(() {
                widget.listItem.isSelected = true;
                //widget.listItem.number = widget.listItem.number + 1;
              });
            },
            child: new Text(
                widget.listItem.number.toString(),
                style: new TextStyle(
                color: widget.listItem.isSelected ? Colors.red : Colors.yellow,
                fontSize: 20.0
              ),
            ),
          ),
        ),
      ),
    );
  }
}

class RadialListViewModel{
  final List<RadialListItemViewModel> items;

  RadialListViewModel({
    this.items = const [],
  });

}


class RadialListItemViewModel{
  int number;
  bool isSelected;

  RadialListItemViewModel({
    this.isSelected=false,
    this.number,
  });

}

radial_position.dart

   import 'package:flutter/material.dart';
import 'dart:math';


class RadialPosition extends StatefulWidget {

  final double radius;
  final double angle;
  final Widget child;

  RadialPosition({
    this.angle,
    this.child,
    this.radius,
  });


  @override
  RadialPositionState createState() {
    return new RadialPositionState();
  }
}

class RadialPositionState extends State<RadialPosition> {
  @override
  Widget build(BuildContext context) {
    final x = cos(widget.angle)  * widget.radius;
    final y = sin(widget.angle) * widget.radius;

    return Transform(
      transform: new Matrix4.translationValues(x, y, 0.0),
      child: widget.child,
    );
  }
}
2020-08-13