繁体   English   中英

flutter CarouselSlider 移动时不改变页面

[英]flutter CarouselSlider is not changing page when moving

我创建了一个 CarouselSlider 试图使其按预期工作但只有图像发生变化,而不是点指示器或标题:

这是我的代码:

屏幕

class OnBoarding extends StatefulWidget {
  static var tag = "/ShWalkThroughScreen";

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

class _OnBoardingState extends State<OnBoarding> {

  OnBoardingController _onBoardingController = Get.put(OnBoardingController());
  @override
  void dispose() {
    super.dispose();
    changeStatusColor(Colors.white);
  }

  @override
  Widget build(BuildContext context) {
    changeStatusColor(Colors.white);
    var width = MediaQuery.of(context).size.width;
    width = width - 50;
    _onBoardingController.gettingWalkThroughData();
    return Obx(()=> Scaffold(
        body: SafeArea(
          child: Container(
            height: MediaQuery.of(context).size.height,
            child: SingleChildScrollView(
              child: Column(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: <Widget>[
                  Container(
                    margin: EdgeInsets.fromLTRB(spacing_large, spacing_large, spacing_large, spacing_standard_new),
                    child: Column(
                      children: <Widget>[
                        text(_onBoardingController.mHeadingList[_onBoardingController.position.value], textColor: sh_textColorPrimary, fontSize: textSizeLarge, fontFamily: fontBold),
                        SizedBox(height: 10.0),
                        text(_onBoardingController.mSubtitle1ingList[_onBoardingController.position.value], fontSize: textSizeLargeMedium, maxLine: 3, isCentered: true),
                      ],
                    ),
                  ),
                  ShCarouselSlider(
                    viewportFraction: 0.8,
                    height: MediaQuery.of(context).size.height * 0.5,
                    enlargeCenterPage: true,
                    scrollDirection: Axis.horizontal,
                    items: _onBoardingController.mSliderList.map((slider) {
                      return Builder(
                        builder: (BuildContext context) {
                          return Container(
                            width: width * 0.9,
                            //height: width + width * 0.1,
                            decoration: BoxDecoration(
                              color: sh_white,
                              borderRadius: BorderRadius.all(Radius.circular(spacing_standard)),
                              boxShadow: [BoxShadow(color: Colors.grey.withOpacity(0.4), spreadRadius: spacing_control_half, blurRadius: 10, offset: Offset(1, 3))],
                            ),
                            margin: EdgeInsets.all(spacing_standard_new),
                            child: Center(
                                child: CachedNetworkImage(
                                    placeholder: placeholderWidgetFn() as Widget Function(BuildContext, String), imageUrl: slider, width: MediaQuery.of(context).size.width, fit: BoxFit.cover),
                            ),
                          );
                        },
                      );
                    }).toList(),
                    onPageChanged: (index) {
                      _onBoardingController.changeIndex(index);
                    },
                  ),
                  Padding(
                    padding: const EdgeInsets.all(spacing_large),
                    child: Column(
                      children: <Widget>[
                        Obx(()=> DotsIndicator(
                            dotsCount: 3,
                            position: _onBoardingController.position.value,
                            decorator: DotsDecorator(color: sh_view_color, activeColor: sh_colorPrimary, activeSize: const Size.square(14.0), spacing: EdgeInsets.all(spacing_control)),
                          ),
                        ),
                        SizedBox(height: spacing_standard),
                        SizedBox(
                          width: double.infinity,
                          height: 50,
                          child: MaterialButton(
                            padding: EdgeInsets.all(spacing_standard),
                            child: Text(sh_text_start_to_shopping, style: TextStyle(fontSize: 18)),
                            textColor: sh_white,
                            shape: RoundedRectangleBorder(borderRadius: new BorderRadius.circular(40.0)),
                            color: sh_colorPrimary,
                            onPressed: () {
                              finish(context);
                              ShHomeScreen().launch(context);
                            },
                          ),
                        ),
                        SizedBox(height: spacing_standard),
                        InkWell(
                          onTap: () {
                            Navigator.pushReplacement(context, MaterialPageRoute(builder: (BuildContext context) {
                              return T3SignIn();
                            }));
                          },
                          child: Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              text(sh_lbl_already_have_a_account),
                              text(sh_lbl_sign_in, textColor: sh_textColorPrimary, fontFamily: fontBold),
                            ],
                          ),
                        )
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }
}

// ignore: must_be_immutable
class ShSliderWidget extends StatelessWidget {

  OnBoardingController _onBoardingController = Get.put(OnBoardingController());
  @override
  Widget build(BuildContext context) {
    var width = MediaQuery.of(context).size.width;
    width = width - 50;
    final Size cardSize = Size(width, width / 1.8);

    return ShCarouselSlider(
      viewportFraction: 0.9,
      height: cardSize.height,
      enlargeCenterPage: true,
      scrollDirection: Axis.horizontal,
      items: _onBoardingController.mSliderList.map((slider) {
        return Builder(
          builder: (BuildContext context) {
            return Obx(()=> Container(
                width: MediaQuery.of(context).size.width,
                height: cardSize.height,
                margin: EdgeInsets.symmetric(horizontal: 8.0),
                child: Card(
                  semanticContainer: true,
                  clipBehavior: Clip.antiAliasWithSaveLayer,
                  elevation: 0,
                  margin: EdgeInsets.all(0),
                  shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10.0)),
                  child: CachedNetworkImage(
                      placeholder: placeholderWidgetFn() as Widget Function(BuildContext, String),
                      imageUrl: slider,
                      fit: BoxFit.fill,
                      width: MediaQuery.of(context).size.width,
                      height: cardSize.height),
                ),
              ),
            );
          },
        );
      }).toList(),
      onPageChanged: (index) {
        _onBoardingController.position.value = index;

      },
    );
  }
}

小工具

class ShCarouselSlider extends StatefulWidget {
  ShCarouselSlider(
      {@required List<Widget> this.items,
        this.height,
        this.aspectRatio: 16 / 9,
        this.viewportFraction: 0.8,
        this.initialPage: 0,
        int realPage: 10000,
        this.enableInfiniteScroll: true,
        this.reverse: false,
        this.autoPlay: false,
        this.autoPlayInterval: const Duration(seconds: 4),
        this.autoPlayAnimationDuration = const Duration(milliseconds: 800),
        this.autoPlayCurve: Curves.fastOutSlowIn,
        this.pauseAutoPlayOnTouch,
        this.enlargeCenterPage = false,
        this.onPageChanged,
        this.scrollPhysics,
        this.scrollDirection: Axis.horizontal})
      : this.realPage = enableInfiniteScroll ? realPage + initialPage : initialPage,
        this.itemCount = items.length,
        this.itemBuilder = null,
        this.pageController = PageController(
          viewportFraction: viewportFraction as double,
          initialPage: enableInfiniteScroll ? realPage + (initialPage as int) : initialPage as int,
        );

  /// The on demand item builder constructor
  ShCarouselSlider.builder(
      {@required this.itemCount,
        @required this.itemBuilder,
        this.height,
        this.aspectRatio: 16 / 9,
        this.viewportFraction: 0.8,
        this.initialPage: 0,
        int realPage: 10000,
        this.enableInfiniteScroll: true,
        this.reverse: false,
        this.autoPlay: false,
        this.autoPlayInterval: const Duration(seconds: 4),
        this.autoPlayAnimationDuration = const Duration(milliseconds: 800),
        this.autoPlayCurve: Curves.fastOutSlowIn,
        this.pauseAutoPlayOnTouch,
        this.enlargeCenterPage = false,
        this.onPageChanged,
        this.scrollPhysics,
        this.scrollDirection: Axis.horizontal})
      : this.realPage = enableInfiniteScroll ? realPage + initialPage : initialPage,
        this.items = null,
        this.pageController = PageController(
          viewportFraction: viewportFraction as double,
          initialPage: enableInfiniteScroll ? realPage + (initialPage as int) : initialPage as int,
        );

  /// The widgets to be shown in the carousel of default constructor
  final List<Widget> items;

  /// The widget item builder that will be used to build item on demand
  final IndexedWidgetBuilder itemBuilder;

  /// The widgets count that should be shown at carousel
  final int itemCount;

  /// Set carousel height and overrides any existing [aspectRatio].
  final double height;

  /// Aspect ratio is used if no height have been declared.
  ///
  /// Defaults to 16:9 aspect ratio.
  final double aspectRatio;

  /// The fraction of the viewport that each page should occupy.
  ///
  /// Defaults to 0.8, which means each page fills 80% of the carousel.
  final num viewportFraction;

  /// The initial page to show when first creating the [ShCarouselSlider].
  ///
  /// Defaults to 0.
  final num initialPage;

  /// The actual index of the [PageView].
  ///
  /// This value can be ignored unless you know the carousel will be scrolled
  /// backwards more then 10000 pages.
  /// Defaults to 10000 to simulate infinite backwards scrolling.
  final num realPage;

  ///Determines if carousel should loop infinitely or be limited to item length.
  ///
  ///Defaults to true, i.e. infinite loop.
  final bool enableInfiniteScroll;

  /// Reverse the order of items if set to true.
  ///
  /// Defaults to false.
  final bool reverse;

  /// Enables auto play, sliding one page at a time.
  ///
  /// Use [autoPlayInterval] to determent the frequency of slides.
  /// Defaults to false.
  final bool autoPlay;

  /// Sets Duration to determent the frequency of slides when
  ///
  /// [autoPlay] is set to true.
  /// Defaults to 4 seconds.
  final Duration autoPlayInterval;

  /// The animation duration between two transitioning pages while in auto playback.
  ///
  /// Defaults to 800 ms.
  final Duration autoPlayAnimationDuration;

  /// Determines the animation curve physics.
  ///
  /// Defaults to [Curves.fastOutSlowIn].
  final Curve autoPlayCurve;

  /// Sets a timer on touch detected that pause the auto play with
  /// the given [Duration].
  ///
  /// Touch Detection is only active if [autoPlay] is true.
  final Duration pauseAutoPlayOnTouch;

  /// Determines if current page should be larger then the side images,
  /// creating a feeling of depth in the carousel.
  ///
  /// Defaults to false.
  final bool enlargeCenterPage;

  /// The axis along which the page view scrolls.
  ///
  /// Defaults to [Axis.horizontal].
  final Axis scrollDirection;

  /// Called whenever the page in the center of the viewport changes.
  final Function(int index) onPageChanged;

  /// How the carousel should respond to user input.
  ///
  /// For example, determines how the items continues to animate after the
  /// user stops dragging the page view.
  ///
  /// The physics are modified to snap to page boundaries using
  /// [PageScrollPhysics] prior to being used.
  ///
  /// Defaults to matching platform conventions.
  final ScrollPhysics scrollPhysics;

  /// [pageController] is created using the properties passed to the constructor
  /// and can be used to control the [PageView] it is passed to.
  final PageController pageController;

  /// Animates the controlled [ShCarouselSlider] to the next page.
  ///
  /// The animation lasts for the given duration and follows the given curve.
  /// The returned [Future] resolves when the animation completes.
  Future<void> nextPage({@required Duration duration, @required Curve curve}) {
    return pageController.nextPage(duration: duration, curve: curve);
  }

  /// Animates the controlled [ShCarouselSlider] to the previous page.
  ///
  /// The animation lasts for the given duration and follows the given curve.
  /// The returned [Future] resolves when the animation completes.
  Future<void> previousPage({@required Duration duration, @required Curve curve}) {
    return pageController.previousPage(duration: duration, curve: curve);
  }

  /// Changes which page is displayed in the controlled [ShCarouselSlider].
  ///
  /// Jumps the page position from its current value to the given value,
  /// without animation, and without checking if the new value is in range.
  void jumpToPage(int page) {
    final index = _getRealIndex(pageController.page.toInt(), realPage - initialPage as int, itemCount);
    return pageController.jumpToPage(pageController.page.toInt() + page - index);
  }

  /// Animates the controlled [ShCarouselSlider] from the current page to the given page.
  ///
  /// The animation lasts for the given duration and follows the given curve.
  /// The returned [Future] resolves when the animation completes.
  Future<void> animateToPage(int page, {@required Duration duration, @required Curve curve}) {
    final index = _getRealIndex(pageController.page.toInt(), realPage - initialPage as int, itemCount);
    return pageController.animateToPage(pageController.page.toInt() + page - index, duration: duration, curve: curve);
  }

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

class _ShCarouselSliderState extends State<ShCarouselSlider> with TickerProviderStateMixin {
  Timer timer;

  @override
  void initState() {
    super.initState();
    timer = getTimer();
  }

  Timer getTimer() {
    return widget.autoPlay
        ? Timer.periodic(widget.autoPlayInterval, (_) {
      widget.pageController.nextPage(duration: widget.autoPlayAnimationDuration, curve: widget.autoPlayCurve);
    })
        : null;
  }

  void pauseOnTouch() {
    timer.cancel();
    timer = Timer(widget.pauseAutoPlayOnTouch, () {
      timer = getTimer();
    });
  }

  Widget getWrapper(Widget child) {
    if (widget.height != null) {
      final Widget wrapper = Container(height: widget.height, child: child);
      return widget.autoPlay && widget.pauseAutoPlayOnTouch != null ? addGestureDetection(wrapper) : wrapper;
    } else {
      final Widget wrapper = AspectRatio(aspectRatio: widget.aspectRatio, child: child);
      return widget.autoPlay && widget.pauseAutoPlayOnTouch != null ? addGestureDetection(wrapper) : wrapper;
    }
  }

  Widget addGestureDetection(Widget child) => GestureDetector(onPanDown: (_) => pauseOnTouch(), child: child);

  @override
  void dispose() {
    super.dispose();
    timer?.cancel();
  }

  @override
  Widget build(BuildContext context) {
    return getWrapper(CarouselSlider(
      options: CarouselOptions(
        enlargeCenterPage: true,
        viewportFraction: 0.8,
      ),
      items: widget.items.map((i) {
        return Container(
          child: i,
        );
      }).toList(),
    ));
  }
}

/// Converts an index of a set size to the corresponding index of a collection of another size
/// as if they were circular.
///
/// Takes a [position] from collection Foo, a [base] from where Foo's index originated
/// and the [length] of a second collection Baa, for which the correlating index is sought.
///
/// For example; We have a Carousel of 10000(simulating infinity) but only 6 images.
/// We need to repeat the images to give the illusion of a never ending stream.
/// By calling _getRealIndex with position and base we get an offset.
/// This offset modulo our length, 6, will return a number between 0 and 5, which represent the image
/// to be placed in the given position.
int _getRealIndex(int position, int base, int length) {
  final int offset = position - base;
  return _remainder(offset, length);
}

/// Returns the remainder of the modulo operation [input] % [source], and adjust it for
/// negative values.
int _remainder(int input, int source) {
  if (source == 0) return 0;
  final int result = input % source;
  return result < 0 ? source + result : result;
}

Controller

class OnBoardingController extends GetxController {
  var onBoardingLoading = false.obs;
  var position = 0.obs;
  var mSliderList = <String>[].obs;
  var mHeadingList = <String>["Hi, Welcome", "Most Unique Styles!", "Shop Till You Drop!"].obs;
  var mSubtitle1ingList = <String>[
    "We make around your city Affordable,easy and efficient.",
    "Shop the most trending fashion on the biggest shopping website",
    "Grab the best seller pieces at bargain prices."
  ];

  gettingWalkThroughData() {
    onBoardingLoading.value = true;
    ApiServices().getWalkTrough().then((resp) {
      onBoardingLoading.value = false;
      mSliderList.clear();
      mHeadingList.clear();
      mSubtitle1ingList.clear();
      for (var item in resp['data']){
        mSliderList.add("${Constants.IMAGE_BASE_URL}${item['image']}/");
        mHeadingList.add(item['title']);
        mSubtitle1ingList.add(item['sub_title']);
      }
    });
  }

  changeIndex(int index){
    position.value = index;
  }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM