Flutter实现Indicator

2018-07-09  本文已影响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
      )
    );
  }
}

上一篇下一篇

猜你喜欢

热点阅读