0

I am setting up an animated profile page with NestedScrollView and slivers. But when I tap on the button to follow a store, it doesn't change until I scroll and I don't understand.

Here is the profile page :

 Scaffold(
          backgroundColor: primaryDark,
          body: NestedScrollView(
              floatHeaderSlivers: true,
              headerSliverBuilder:
                  (BuildContext context, bool innerBoxIsScrolled) {
                return <Widget>[
                  SliverPersistentHeader(
                    delegate: SliverPersistentDelegate(
                        widget.user, state.products, follow, setState),
                    pinned: true,
                  ),
                  // lets create a long list to make the content scrollable
                  SliverOverlapAbsorber(
                    handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                        context),
                    sliver: SliverToBoxAdapter(
                      child: Column(
                        children: [
                          Container(
                            color: primaryDark,
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                Text(
                                  widget.user.username,
                                  style: TextStyle(
                                      fontSize: 16,
                                      color: primaryWhite,
                                      fontWeight: FontWeight.bold),
                                ),
                                const SizedBox(height: 5),
                                Text(
                                  widget.user.city.isEmpty
                                      ? widget.user.country
                                      : (widget.user.city +
                                          ', ' +
                                          widget.user.country),
                                  style: TextStyle(
                                    fontSize: 14,
                                    color: primaryWhite,
                                  ),
                                ),
                                const SizedBox(height: 5),
                                Padding(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 16.0),
                                  child: StatefulBuilder(
                                      builder: (context, state) {
                                    return rowStars(
                                      // callback: (){},
                                      numberOfFullStars: widget.user.userNote,
                                      type: "sellerStars",
                                      colors: [primaryGreen, primaryDark],
                                      sizes: [12.5, 7.5],

                                      //
                                    );
                                  }),
                                ),
                                const SizedBox(height: 15),
                                Divider(
                                  height: 0,
                                  color: primaryGrey4,
                                ),
                                const SizedBox(height: 5),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ];
              },
              body: _buildContent(
                context,
                width,
                state.user,
                state.products,
                state.showMessage,
              )),
        );

and the SliverPersistentDelegate

class SliverPersistentDelegate extends SliverPersistentHeaderDelegate {
  final UserModel user;
  final List<Product> products;
  bool follow;
  final double maxHeaderHeight = 120;
  final double minHeaderHeight = kToolbarHeight + 20;
  final double maxImageSize = 63;
  final double minImageSize = 0;
  final StateSetter stateSetter;
  SliverPersistentDelegate(
      this.user, this.products, this.follow, this.stateSetter);

  @override
  Widget build(
    BuildContext context,
    double shrinkOffset,
    bool overlapsContent,
  ) {
    final size = MediaQuery.of(context).size;
    final percent = shrinkOffset / (maxHeaderHeight - 65);
    final percent2 = shrinkOffset / (maxHeaderHeight);
    final currentImageSize = (maxImageSize * (1 - percent)).clamp(
      minImageSize,
      maxImageSize,
    );
    final currentImagePosition = ((size.width / 2 - 65) * (1 - percent)).clamp(
      minImageSize,
      maxImageSize,
    );

    return Container(
      color: primaryDark,
      child: Container(
        color: primaryGrey7.withOpacity(percent2 * 2 < 1 ? percent2 * 2 : 1),
        child: Stack(
          children: [
            Positioned(
              top: MediaQuery.of(context).viewPadding.top + 15,
              left: currentImagePosition + 55,
              child: (user.isOfficial)
                  ? Row(
                      mainAxisAlignment: MainAxisAlignment.start,
                      //crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          user?.username ?? "",
                          style: TextStyle(
                            color: primaryWhite.withOpacity(percent2),
                            fontSize: 20,
                            fontWeight: FontWeight.w700,
                            fontStyle: FontStyle.normal,
                          ),
                        ),
                        SizedBox(width: 2.0),
                        currentImageSize <= 8 && user.isOfficial
                            ? SvgPicture.asset(
                                "assets/svg/certification.svg",
                              )
                            : SizedBox.shrink()
                      ],
                    )
                  : Text(
                      user?.username ?? "",
                      style: TextStyle(
                        color: primaryWhite.withOpacity(percent2),
                        fontSize: 24,
                        fontWeight: FontWeight.w700,
                        fontStyle: FontStyle.normal,
                      ),
                    ),
            ),
            Positioned(
              left: 15,
              top: currentImageSize == 0
                  ? MediaQuery.of(context).viewPadding.top + 15
                  : MediaQuery.of(context).viewPadding.top + 33,
              child: GestureDetector(
                onTap: () => Navigator.pop(context),
                child: Icon(
                  Icons.arrow_back_sharp,
                  size: 30,
                  color: primaryWhite,
                ),
              ),
            ),
            Positioned(
                right: 50,
                top: currentImageSize == 0
                    ? MediaQuery.of(context).viewPadding.top + 15
                    : MediaQuery.of(context).viewPadding.top + 33,
                child: (userConnected != null &&
                        userConnected.id != null &&
                        user.id != userConnected.id)
                    ? GestureDetector(
                        onTap: () {
                          if (follow) {
                            // unfollow event
                            BlocProvider.of<ProfileVisitedBloc>(context).add(
                              ProfileVisitedEventUnfollowing(
                                user: user,
                              ),
                            );
                            BlocProvider.of<FollowingBloc>(context).add(
                              FollowingDisplayStarted(
                                uid: userConnected.id,
                              ),
                            );
                            stateSetter(
                              () {
                                follow = false;
                              },
                            );
                          } else {
                            // follow event
                            BlocProvider.of<ProfileVisitedBloc>(context).add(
                              ProfileVisitedEventFollowing(user: user),
                            );

                            BlocProvider.of<FollowingBloc>(context).add(
                              FollowingDisplayStarted(
                                uid: userConnected.id,
                              ),
                            );
                            stateSetter(
                              () {
                                follow = true;
                              },
                            );
                          }
                        },
                        child: SvgPicture.asset(
                          (follow)
                              ? "assets/svg/icon_follow.svg"
                              : "assets/svg/icon_unfollow.svg",
                          width: 30,
                          height: 30,
                        ),
                      )
                    : SizedBox.shrink()),
            Positioned(
                right: 7,
                top: currentImageSize == 0
                    ? MediaQuery.of(context).viewPadding.top + 15
                    : MediaQuery.of(context).viewPadding.top + 33,
                child: (userConnected != null &&
                        userConnected.id != null &&
                        user.id != userConnected.id)
                    ? GestureDetector(
                        onTap: () {
                          displayCupertinoDialogReport(
                            user,
                            MediaQuery.of(context).size.width,
                            context,
                            products,
                          );
                        },
                        child: Icon(
                          Icons.more_vert,
                          size: 30,
                          color: primaryWhite,
                        ),
                      )
                    : SizedBox.shrink()),
            Positioned(
              left: currentImagePosition + 87,
              top: MediaQuery.of(context).viewPadding.top + 15,
              bottom: 0,
              child: Hero(
                tag: 'profile',
                child: Container(
                    width: currentImageSize,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                    ),
                    child: user.isOfficial
                        ? SvgPicture.asset(
                            'assets/svg/tag_faces_official.svg',
                          )
                        : SvgPicture.asset(
                            'assets/svg/tag_faces.svg',
                          )),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  double get maxExtent => maxHeaderHeight;

  @override
  double get minExtent => minHeaderHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    return false;
  }
}

POST: i tried to include a StateStater in the parameters to update the value of the "follow" variable but nothing.

The full page :


class AnimatedUserVisitedProfile extends StatefulWidget {
  final User user;

  const AnimatedUserVisitedProfile({Key key, this.user}) : super(key: key);

  @override
  State<AnimatedUserVisitedProfile> createState() =>
      _AnimatedUserVisitedProfileState();
}

class _AnimatedUserVisitedProfileState
    extends State<AnimatedUserVisitedProfile> {
  Completer<void> _refreshCompleter;

  @override
  void initState() {
    super.initState();
    _refreshCompleter = Completer<void>();
    BlocProvider.of<ProfileVisitedBloc>(context).add(
      ProfileVisitedEventClicked(
        uid: widget.user.id,
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final width = MediaQuery.of(context).size.width;
    return BlocConsumer<ProfileVisitedBloc, ProfileVisitedState>(
        listener: (context, state) {
      if (state is ProfileVisitedStateLoaded) {
        _refreshCompleter?.complete();
        _refreshCompleter = Completer();
      }
    }, builder: (context, state) {
      if (state is ProfileVisitedStateLoaded) {
        if (state.showMessage != null && state.showMessage) {
          Timer.periodic(Duration(seconds: 1), (timer) {
            if (this.mounted) {
              BlocProvider.of<ProfileVisitedBloc>(context).add(
                ProfileVisitedMessageDisappeared(),
              );
              Navigator.pop(context);
            }
            timer.cancel();
          });
        }
        bool follow = (userConnected == null)
            ? false
            : (widget.user != null &&
                    widget.user.followers.contains(userConnected.id))
                ? true
                : false;
        return Scaffold(
          backgroundColor: primaryDark,
          body: NestedScrollView(
              floatHeaderSlivers: true,
              headerSliverBuilder:
                  (BuildContext context, bool innerBoxIsScrolled) {
                return <Widget>[
                  SliverPersistentHeader(
                    delegate: SliverPersistentDelegate(
                        widget.user, state.products, follow, setState),
                    pinned: true,
                  ),
              
                  SliverOverlapAbsorber(
                    handle: NestedScrollView.sliverOverlapAbsorberHandleFor(
                        context),
                    sliver: SliverToBoxAdapter(
                      child: Column(
                        children: [
                          Container(
                            color: primaryDark,
                            child: Column(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                              
                                Text(
                                  widget.user.username,
                                  style: TextStyle(
                                      fontSize: 16,
                                      color: primaryWhite,
                                      fontWeight: FontWeight.bold),
                                ),
                                const SizedBox(height: 5),
                                Text(
                                  widget.user.city.isEmpty
                                      ? widget.user.country
                                      : (widget.user.city +
                                          ', ' +
                                          widget.user.country),
                                  style: TextStyle(
                                    fontSize: 14,
                                    color: primaryWhite,
                                  ),
                                ),
                                const SizedBox(height: 5),
                                Padding(
                                  padding: const EdgeInsets.symmetric(
                                      horizontal: 16.0),
                                  child: StatefulBuilder(
                                      builder: (context, state) {
                                    return rowStars(
                                      // callback: (){},
                                      numberOfFullStars: widget.user.userNote,
                                      type: "sellerStars",
                                      colors: [primaryGreen, primaryDark],
                                      sizes: [12.5, 7.5],

                                      //
                                    );
                                  }),
                                ),
                                const SizedBox(height: 15),
                                Divider(
                                  height: 0,
                                  color: primaryGrey4,
                                ),
                                const SizedBox(height: 5),
                              ],
                            ),
                          ),
                        ],
                      ),
                    ),
                  ),
                ];
              },
              body: _buildContent(
                context,
                width,
                state.user,
                state.products,
                state.showMessage,
              )),
        );
      }
      return Center(
        child: Container(
          color: Colors.black,
          child: loading(),
        ),
      );
    });
  }

  Widget _buildContent(
    BuildContext context,
    double width,
    User user,
    List<Product> products,
    bool showMessage,
  ) {//return a ListView of products
}

class SliverPersistentDelegate extends SliverPersistentHeaderDelegate {
  final UserModel user;
  final List<Product> products;
  bool follow;
  final double maxHeaderHeight = 120;
  final double minHeaderHeight = kToolbarHeight + 20;
  final double maxImageSize = 63;
  final double minImageSize = 0;
  final StateSetter stateSetter;
  SliverPersistentDelegate(
      this.user, this.products, this.follow, this.stateSetter);

  @override
  Widget build(
    BuildContext context,
    double shrinkOffset,
    bool overlapsContent,
  ) {
    final size = MediaQuery.of(context).size;
    final percent = shrinkOffset / (maxHeaderHeight - 65);
    final percent2 = shrinkOffset / (maxHeaderHeight);
    final currentImageSize = (maxImageSize * (1 - percent)).clamp(
      minImageSize,
      maxImageSize,
    );
    final currentImagePosition = ((size.width / 2 - 65) * (1 - percent)).clamp(
      minImageSize,
      maxImageSize,
    );

    return Container(
      color: primaryDark,
      child: Container(
        color: primaryGrey7.withOpacity(percent2 * 2 < 1 ? percent2 * 2 : 1),
        child: Stack(
          children: [
            Positioned(
              top: MediaQuery.of(context).viewPadding.top + 15,
              left: currentImagePosition + 55,
              child: (user.isOfficial)
                  ? Row(
                      mainAxisAlignment: MainAxisAlignment.start,
                      //crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          user?.username ?? "",
                          style: TextStyle(
                            color: primaryWhite.withOpacity(percent2),
                            fontSize: 20,
                            fontWeight: FontWeight.w700,
                            fontStyle: FontStyle.normal,
                          ),
                        ),
                        SizedBox(width: 2.0),
                        currentImageSize <= 8 && user.isOfficial
                            ? SvgPicture.asset(
                                "assets/svg/certification.svg",
                              )
                            : SizedBox.shrink()
                      ],
                    )
                  : Text(
                      user?.username ?? "",
                      style: TextStyle(
                        color: primaryWhite.withOpacity(percent2),
                        fontSize: 24,
                        fontWeight: FontWeight.w700,
                        fontStyle: FontStyle.normal,
                      ),
                    ),
            ),
            Positioned(
              left: 15,
              top: currentImageSize == 0
                  ? MediaQuery.of(context).viewPadding.top + 15
                  : MediaQuery.of(context).viewPadding.top + 33,
              child: GestureDetector(
                onTap: () => Navigator.pop(context),
                child: Icon(
                  Icons.arrow_back_sharp,
                  size: 30,
                  color: primaryWhite,
                ),
              ),
            ),
            Positioned(
                right: 50,
                top: currentImageSize == 0
                    ? MediaQuery.of(context).viewPadding.top + 15
                    : MediaQuery.of(context).viewPadding.top + 33,
                child: (userConnected != null &&
                        userConnected.id != null &&
                        user.id != userConnected.id)
                    ? GestureDetector(
                        onTap: () {
                          if (follow) {
                            // unfollow event
                            BlocProvider.of<ProfileVisitedBloc>(context).add(
                              ProfileVisitedEventUnfollowing(
                                user: user,
                              ),
                            );
                            BlocProvider.of<FollowingBloc>(context).add(
                              FollowingDisplayStarted(
                                uid: userConnected.id,
                              ),
                            );
                            stateSetter(
                              () {
                                follow = false;
                              },
                            );
                          } else {
                            // follow event
                            BlocProvider.of<ProfileVisitedBloc>(context).add(
                              ProfileVisitedEventFollowing(user: user),
                            );

                            BlocProvider.of<FollowingBloc>(context).add(
                              FollowingDisplayStarted(
                                uid: userConnected.id,
                              ),
                            );
                            stateSetter(
                              () {
                                follow = true;
                              },
                            );
                          }
                        },
                        child: SvgPicture.asset(
                          (follow)
                              ? "assets/svg/icon_follow.svg"
                              : "assets/svg/icon_unfollow.svg",
                          width: 30,
                          height: 30,
                        ),
                      )
                    : SizedBox.shrink()),
            Positioned(
                right: 7,
                top: currentImageSize == 0
                    ? MediaQuery.of(context).viewPadding.top + 15
                    : MediaQuery.of(context).viewPadding.top + 33,
                child: (userConnected != null &&
                        userConnected.id != null &&
                        user.id != userConnected.id)
                    ? GestureDetector(
                        onTap: () {
                          displayCupertinoDialogReport(
                            user,
                            MediaQuery.of(context).size.width,
                            context,
                            products,
                          );
                        },
                        child: Icon(
                          Icons.more_vert,
                          size: 30,
                          color: primaryWhite,
                        ),
                      )
                    : SizedBox.shrink()),
            Positioned(
              left: currentImagePosition + 87,
              top: MediaQuery.of(context).viewPadding.top + 15,
              bottom: 0,
              child: Hero(
                tag: 'profile',
                child: Container(
                    width: currentImageSize,
                    decoration: BoxDecoration(
                      shape: BoxShape.circle,
                    ),
                    child: user.isOfficial
                        ? SvgPicture.asset(
                            'assets/svg/tag_faces_official.svg',
                          )
                        : SvgPicture.asset(
                            'assets/svg/tag_faces.svg',
                          )),
              ),
            ),
          ],
        ),
      ),
    );
  }

  @override
  double get maxExtent => maxHeaderHeight;

  @override
  double get minExtent => minHeaderHeight;

  @override
  bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {
    return false;
  }
}

Rassuul
  • 3
  • 3

0 Answers0