美文网首页
Flutter实现Indicator

Flutter实现Indicator

作者: 最近不在 | 来源:发表于2018-07-09 09:49 被阅读41次
    QQ截图20180628210619.jpg

    需求分析

    • 需要添加一组子控件
    • 支持选中/未选中分别显示
    • 支持点击事件回调

    这里我们先使用Row实现一个LineIndicator

    import 'package:flutter/material.dart';
    
    class LinePageIndicator extends StatelessWidget {
      final int count;
      final int currentIndex;
      final Color normalColor;
      final Color selectColor;
      final double width;
      final double height;
      final double padding;
      final ValueChanged onItemTap;
    
      LinePageIndicator({
        Key key,
        @required this.count,
        @required this.normalColor,
        @required this.selectColor,
        @required this.currentIndex,
        this.width : 16.0,
        this.height : 6.0,
        this.padding : 6.0,
        this.onItemTap,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        var container = Container(
          decoration: BoxDecoration(
          ),
          height: height,
          width: width * count + padding * (count + 1),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceEvenly,
            children: getChildren(),
          ),
        );
        return container;
      }
    
      List<Widget> getChildren() {
        List<Widget> children = [];
        for (int i = 0; i < count; i++) {
          var colorVal = (i == currentIndex ? this.selectColor : this.normalColor);
          children.add(GestureDetector(
            child: Container(
              width: width,
              height: height,
              decoration: BoxDecoration(
                color: colorVal,
                shape: BoxShape.rectangle,
              ),
            ),
            onTap: () {
              onItemTap(i);
            },
          ));
        }
        return children;
      }
    }
    

    这样就实现了一个Indicator.

    如果我们要一个CircleIndicator又的重写大部分逻辑, 仅仅是形状改变以及区域计算变了.

    这里我们可以抽离出一个基类, 使用ListView模式, 只用渲染一个子项目, 以及实现宽高的计算.
    抽离出的代码如下:

    import 'package:flutter/material.dart';
    
    abstract class CustomPageIndicator extends StatelessWidget {
      final int count;
      final int currentIndex;
      final ValueChanged onItemTap;
      final Axis scrollDirection;
    
      CustomPageIndicator({
        Key key,
        @required this.count,
        this.currentIndex : 0,
        this.scrollDirection,
        this.onItemTap,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        var container = Container(
          height: scrollDirection == Axis.horizontal ? getHeight() : getWidth(),
          width: scrollDirection == Axis.horizontal ? getWidth() : getHeight(),
          child: getItems(),
        );
        return container;
      }
    
      Widget getItems() {
        return ListView.builder(
          itemCount: count,
          scrollDirection: scrollDirection,
          itemBuilder: (context, i) => GestureDetector(
            child: renderRow(i),
            onTap: () {
              onItemTap(i);
            },
          ),
        );
      }
    
      Widget renderRow(i);
    
      double getHeight();
    
      double getWidth();
    }
    

    接着我们继承CustomPageIndicator实现一个CircleIndicator:

    import 'package:app2/widgets/indicator/CustomPageIndicator.dart';
    import 'package:flutter/material.dart';
    
    class CirclePageIndicator extends CustomPageIndicator {
      final Color normalColor;
      final Color selectColor;
      final double size;
      final double padding;
    
      CirclePageIndicator({
        Key key,
        int count,
        int currentIndex,
        ValueChanged onItemTap,
        Axis scrollDirection : Axis.vertical,
        this.padding : 2.0,
        @required this.normalColor,
        @required this.selectColor,
        this.size : 12.0,
      }) : super(key: key, count: count, currentIndex: currentIndex, onItemTap: onItemTap, scrollDirection: scrollDirection);
    
      @override
      Widget renderRow(i) {
        var colorVal = (i == currentIndex ? this.selectColor : this.normalColor);
        return Padding(
          padding: EdgeInsets.all(padding),
          child: Container(
            width: size,
            height: size,
            decoration: BoxDecoration(
              color: colorVal,
              shape: BoxShape.circle,
            ),
          ),
        );
      }
    
      double getHeight() {
        return size + padding*2;
      }
    
      double getWidth() {
        return size * count + padding * count * 2;
      }
    }
    

    这样我们就只需要简单编写就完成需求了.

    调用代码:

    import 'package:app2/widgets/indicator/CirclePageIndicator.dart';
    import 'package:app2/widgets/indicator/LinePageIndicator.dart';
    import 'package:flutter/material.dart';
    
    class BannerView extends StatefulWidget {
      @override
      State<StatefulWidget> createState() {
        return BannerViewState();
      }
    }
    
    class BannerViewState extends State<BannerView> {
    
      PageController pageController = PageController();
      int curIndex = 0;
      var data = ['1', '2', '3', '4', '5', '6', '7'];
    
      @override
      Widget build(BuildContext context) {
        return Stack(
          children: [
            getPages(),
            Padding(
              padding: EdgeInsets.fromLTRB(0.0, 20.0, 0.0, 0.0),
              child: Align(
                alignment: Alignment.topCenter,
                child: getTopIndicator(),
              ),
            ),
            Padding(
              padding: EdgeInsets.fromLTRB(20.0, 0.0, 0.0, 0.0),
              child: Align(
                alignment: Alignment.centerLeft,
                child: getLeftIndicator(),
              ),
            ),
            Padding(
              padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 20.0),
              child: Align(
                alignment: Alignment.bottomCenter,
                child: getBottomIndicator(),
              ),
            ),
          ],
        );
      }
    
      Widget getTopIndicator() {
        return LinePageIndicator(
          count: data.length,
          currentIndex: curIndex,
          normalColor: Colors.red,
          selectColor: Colors.yellow,
          onItemTap: (index) {
            pageController.jumpToPage(index);
          },
        );
      }
    
      Widget getLeftIndicator() {
        return CirclePageIndicator(
          scrollDirection: Axis.vertical,
          count: data.length,
          currentIndex: curIndex,
          normalColor: Colors.red,
          selectColor: Colors.yellow,
          onItemTap: (index) {
            pageController.jumpToPage(index);
          },
        );
      }
    
      Widget getBottomIndicator() {
        return CirclePageIndicator(
          scrollDirection: Axis.horizontal,
          count: data.length,
          currentIndex: curIndex,
          normalColor: Colors.red,
          selectColor: Colors.yellow,
          onItemTap: (index) {
            pageController.jumpToPage(index);
          },
        );
      }
    
      Widget getPages() {
        return PageView.custom(
          onPageChanged: (index) {
            setState(() {
              curIndex = index;
            });
          },
          controller: pageController,
          childrenDelegate: SliverChildBuilderDelegate(
              (context, index) {
                return Container(
                  height: 20.0,
                  alignment: Alignment.center,
                  color: Colors.lightBlue[100 * (index % data.length)],
                  child: Text('page $index'),
                );
              },
              childCount: data.length
          )
        );
      }
    }
    
    

    相关文章

      网友评论

          本文标题:Flutter实现Indicator

          本文链接:https://www.haomeiwen.com/subject/yvrzuftx.html