Parcourir la source

fix:优化会员中心UI布局。

zhoukun il y a 4 mois
Parent
commit
996c2e31f6

BIN
assets/images/icon_apple_recover_subscribe.png


BIN
assets/images/icon_apple_recover_subscribe.webp


BIN
assets/images/icon_member_settlement_bg.webp


BIN
assets/images/icon_member_settlement_confirm.webp


BIN
assets/images/icon_member_vip_back.webp


BIN
assets/images/icon_member_vip_middle_bg.webp


BIN
assets/images/img_member_header_ad_1.webp


BIN
assets/images/img_member_header_ad_2.webp


BIN
assets/images/img_member_header_ad_3.webp


BIN
assets/images/img_member_header_ad_4.webp


+ 1 - 1
lib/module/member/member_controller.dart

@@ -193,7 +193,7 @@ class MemberController extends BaseController implements PaymentStatusCallback {
       children: [
         RichText(
             text: TextSpan(
-                style: TextStyle(fontSize: 12.sp, color: Colors.white),
+                style: TextStyle(fontSize: 11.sp, color: Colors.white,fontWeight: FontWeight.w400),
                 children: [
               TextSpan(text: userIdStr),
               TextSpan(text: '用户 '),

+ 116 - 0
lib/module/member/member_header_cycle_widget.dart

@@ -0,0 +1,116 @@
+import 'package:flutter/cupertino.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_screenutil/flutter_screenutil.dart';
+import 'package:get/get.dart';
+import 'package:location/resource/assets.gen.dart';
+import 'package:smooth_page_indicator/smooth_page_indicator.dart';
+
+// 无限滚动控制器
+class InfiniteScrollController extends PageController {
+  final int itemCount;
+
+  InfiniteScrollController({
+    required this.itemCount,
+    int initialPage = 0,
+  }) : super(initialPage: initialPage * 1000); // 从一个很大的中间值开始
+
+  int getRealIndex(int page) {
+    if (itemCount == 0) return 0;
+    return page % itemCount;
+  }
+}
+
+class MemberHeaderCycleWidget extends StatefulWidget {
+  @override
+  _MemberHeaderCycleWidgetState createState() => _MemberHeaderCycleWidgetState();
+}
+
+class _MemberHeaderCycleWidgetState extends State<MemberHeaderCycleWidget> {
+  late InfiniteScrollController _controller;
+  final List<ImageProvider> _images = [
+    Assets.images.imgMemberHeaderAd1.provider(),
+    Assets.images.imgMemberHeaderAd2.provider(),
+    Assets.images.imgMemberHeaderAd3.provider(),
+    Assets.images.imgMemberHeaderAd4.provider(),
+  ];
+
+  @override
+  void initState() {
+    super.initState();
+    _controller = InfiniteScrollController(itemCount: _images.length);
+    _startAutoPlay();
+  }
+
+  void _startAutoPlay() {
+    Future.delayed(Duration(seconds: 3), () {
+      if (_controller.hasClients) {
+        _controller.nextPage(
+          duration: Duration(milliseconds: 500),
+          curve: Curves.ease,
+        );
+        _startAutoPlay();
+      }
+    });
+  }
+
+  @override
+  void dispose() {
+    _controller.dispose();
+    super.dispose();
+  }
+
+  @override
+  Widget build(BuildContext context) {
+    return Stack(
+      children: [
+        Container(
+          color: Colors.orangeAccent,
+          height: 291.w + MediaQuery.of(Get.context!).padding.top,
+          width: double.infinity,
+          child: PageView.builder(
+            controller: _controller,
+            itemCount: null, // 无限滚动
+            itemBuilder: (context, index) {
+              final realIndex = _controller.getRealIndex(index);
+              return Container(
+                decoration: BoxDecoration(
+                    image: DecorationImage(
+                      image: _images[realIndex],
+                      fit: BoxFit.fill,
+                    )
+                ),
+              );
+            },
+          ),
+        ),
+        Positioned(
+            bottom: 50.w,
+            left: 0,
+            right: 0,
+            height: 5.w,
+            child: Container(
+              alignment: Alignment.center,
+              child: SmoothPageIndicator(
+                controller: _controller,
+                count: _images.length,
+                effect: ExpandingDotsEffect(
+                  expansionFactor: 2,
+                  dotWidth: 5.0,
+                  dotHeight: 5.w,
+                  spacing: 4.0,
+                  dotColor: Colors.grey,
+                  activeDotColor: Colors.deepPurple,
+                ),
+                onDotClicked: (index) {
+                  _controller.animateToPage(
+                    index + _controller.initialPage, // 跳转到对应的位置
+                    duration: Duration(milliseconds: 500),
+                    curve: Curves.ease,
+                  );
+                },
+              ),
+            )),
+      ],
+    );
+  }
+}

+ 209 - 70
lib/module/member/member_page.dart

@@ -23,6 +23,7 @@ import '../../router/app_pages.dart';
 import '../../utils/date_util.dart';
 import '../../widget/animated_switcher_widget.dart';
 import 'member_evaluate_bean.dart';
+import 'member_header_cycle_widget.dart';
 
 ///进入会员类型
 enum MemberPageType {
@@ -56,7 +57,7 @@ class MemberPage extends BasePage<MemberController> {
 
   @override
   Widget buildBody(BuildContext context) {
-    return PopScope(
+          return PopScope(
       canPop: false,
       onPopInvokedWithResult: (bool didPop, dynamic result) async {
         controller.onPopBack();
@@ -68,11 +69,102 @@ class MemberPage extends BasePage<MemberController> {
             controller: controller.scrollController,
             child: Stack(
               children: [
+                MemberHeaderCycleWidget(),
+                Column(
+                  children: [
+                    SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top),
+                    Container(
+                      decoration: BoxDecoration(
+                        color: ColorName.white,
+                        borderRadius: BorderRadius.only(
+                            topLeft: Radius.circular(20.w),
+                            topRight: Radius.circular(20.w)),
+                      ),
+                      child: Stack(
+                        children: [
+                          Container(
+                            decoration: BoxDecoration(
+                                borderRadius: BorderRadius.only(
+                                    topLeft: Radius.circular(20.w),
+                                    topRight: Radius.circular(20.w)),
+                                image: DecorationImage(
+                                  image: Assets.images.iconMemberVipMiddleBg.provider(),
+                                  fit: BoxFit.fill,
+                                )
+                            ),
+                            width: double.infinity,
+                            height: 174,
+                          ),
+                          Container(
+                            width: double.infinity,
+                            decoration: BoxDecoration(
+                                borderRadius: BorderRadius.only(
+                                    topLeft: Radius.circular(20.w),
+                                    topRight: Radius.circular(20.w)),
+                                image: DecorationImage(image: Assets.images.iconMemberVipMiddleBg.provider())
+                            ),
+                            child: Column(
+                              crossAxisAlignment: CrossAxisAlignment.start,
+                              children: [
+                                SizedBox(height: 15.w),
+                                buildUserInfoView(),
+                                SizedBox(height: 26.w),
+                                SizedBox(height: 23.w),
+                                buildGoodsList(),
+                                SizedBox(height: 12.w),
+                                buildPrivacyPolicyView(),
+                                buildPayWayView(),
+                                SizedBox(height: 30.w),
+                                Padding(
+                                  padding: EdgeInsets.only(left: 12.w),
+                                  child: Text(StringName.memberEquityIntroduction,
+                                      style: TextStyle(
+                                          fontSize: 16.sp,
+                                          color: ColorName.black90,
+                                          fontWeight: FontWeight.bold)),
+                                ),
+                                SizedBox(height: 19.w),
+                                buildFunctionList(),
+                                SizedBox(height: 40.w),
+                                Padding(
+                                  padding: EdgeInsets.only(left: 12.w),
+                                  child: Text(StringName.memberUserEvaluate,
+                                      style: TextStyle(
+                                          fontSize: 16.sp,
+                                          color: ColorName.black90,
+                                          fontWeight: FontWeight.bold)),
+                                ),
+                                SizedBox(height: 8.w),
+                                buildUserEvaluateList(),
+                                SizedBox(height: 20.w),
+                                Container(
+                                  padding: EdgeInsets.all(12.w),
+                                  decoration: BoxDecoration(
+                                      color: '#F7F7F7'.color,
+                                      borderRadius: BorderRadius.circular(6.w)),
+                                  margin: EdgeInsets.symmetric(horizontal: 12.w),
+                                  child: Text(StringName.memberTips,
+                                      style: TextStyle(
+                                          fontSize: 12.sp, color: '#A7A7A7'.color)),
+                                ),
+                                SizedBox(height: 100.w)
+                              ],
+                            ),
+                          )
+                        ],
+                      ),
+                    )
+                  ],
+                ),
+              ],
+            )
+            /*Stack(
+              children: [
                 Assets.images.bgMemberHeader.image(width: double.infinity),
                 SafeArea(
                   child: Column(
                     children: [
-                      SizedBox(height: 62.w),
+                      SizedBox(height: 249.w + MediaQuery.of(Get.context!).padding.top),
                       buildUserInfoView(),
                       SizedBox(height: 26.w),
                       Container(
@@ -135,7 +227,7 @@ class MemberPage extends BasePage<MemberController> {
                   ),
                 )
               ],
-            ),
+            ),*/
           ),
           buildHeadBar(),
           buildMemberBottomView()
@@ -270,62 +362,100 @@ class MemberPage extends BasePage<MemberController> {
             controller.memberStatusInfo?.permanent == false,
         child: Align(
           alignment: Alignment.bottomCenter,
-          child: Container(
+          child: Container(//top: 98.w,
+            alignment: Alignment.bottomCenter,
+            height: 190.w + MediaQuery.of(Get.context!).padding.bottom,
             padding: EdgeInsets.only(
-                left: 12.w, right: 12.w, top: 13.w, bottom: 20.w),
+                left: 12.w, right: 12.w, bottom: 17.w + MediaQuery.of(Get.context!).padding.bottom),
             decoration: BoxDecoration(
-              color: Colors.white,
-              boxShadow: [
-                BoxShadow(
-                    color: Colors.black.withOpacity(0.05),
-                    offset: Offset(0, -2),
-                    blurRadius: 4)
-              ],
-              borderRadius: BorderRadius.only(
-                  topLeft: Radius.circular(16.w),
-                  topRight: Radius.circular(16.w)),
+              gradient: LinearGradient(
+                begin: Alignment.bottomCenter, // 0deg 相当于从底部开始
+                end: Alignment.topCenter,
+                colors: [
+                  Colors.white, // #FFF
+                  "#00FFFFFF".color,
+                ],
+                stops: [0.4368, 1.0], // 对应 43.68% 和 100%
+              ),
             ),
             child: Obx(() {
-              return Row(
+              return Column(
+                mainAxisAlignment: MainAxisAlignment.end,
                 children: [
-                  Text('¥',
-                      style: TextStyle(
-                          fontSize: 14.sp,
-                          color: '#EA1231'.color,
-                          fontWeight: FontWeight.bold)),
-                  Text(
-                    controller.selectedGoods?.amount.divideBy100() ?? '--',
-                    style: TextStyle(
-                        fontSize: 24.sp,
-                        color: '#EA1231'.color,
-                        fontWeight: FontWeight.bold),
-                  ),
-                  Text(
-                    ' / ${controller.selectedGoods?.name ?? '--'}',
-                    style: TextStyle(fontSize: 12.sp, color: '#000000'.color),
-                  ),
-                  Spacer(),
-                  GestureDetector(
-                    onTap: controller.onBuyClick,
-                    child: Container(
-                      decoration: BoxDecoration(
-                          color: ColorName.colorPrimary,
-                          borderRadius: BorderRadius.circular(100.w)),
-                      width: 164.w,
-                      height: 44.w,
-                      child: Center(
-                        child: Text(
-                          controller.memberStatusInfo?.expired == false
-                              ? StringName.memberVipRenew
-                              : StringName.memberVipUnlock,
+                  Container(
+                    width: double.infinity,  // 设置容器宽度
+                    height: 50.w, // 设置容器高度
+                    padding: EdgeInsets.only(left: 20.w),
+                    decoration: BoxDecoration(
+                      image: DecorationImage(
+                        image: Assets.images.iconMemberSettlementBg.provider(),
+                        fit: BoxFit.fill,
+                      ),
+                    ),
+                    // 实现内阴影效果
+                    child: Row(
+                      children: [
+                        Transform.translate(
+                          offset: Offset(0, 3), // 向下偏移4像素
+                          child: Text('¥',
+                              style: TextStyle(
+                                  fontSize: 14.sp,
+                                  color: '#FFF8EF'.color,
+                                  fontWeight: FontWeight.bold)),
+                        ),
+                        SizedBox(width: 3.w,),
+                        Text(
+                          controller.selectedGoods?.amount.divideBy100() ?? '--',
                           style: TextStyle(
-                              fontSize: 15.sp,
-                              color: Colors.white,
+                              fontSize: 24.sp,
+                              color: '#FFF8EF'.color,
                               fontWeight: FontWeight.bold),
                         ),
-                      ),
+                        SizedBox(width: 3.w,),
+                        Text("/",
+                        style: TextStyle(
+                            fontSize: 12.sp,
+                            fontWeight: FontWeight.w400,
+                            color: "#FFF8EF".color),),
+                        Text('原价${controller.selectedGoods?.originalAmount.divideBy100()}',
+                            style: TextStyle(
+                                decoration: TextDecoration.lineThrough,
+                                decorationColor: Colors.white,
+                                decorationThickness: 1.0,
+                                fontSize: 12.sp,
+                                fontWeight: FontWeight.w400,
+                                color: "#FFF8EF".color)),
+                        Spacer(),
+                        GestureDetector(
+                          onTap: controller.onBuyClick,
+                          child: Container(
+                            decoration: BoxDecoration(
+                                image: DecorationImage(
+                                  image: Assets.images.iconMemberSettlementConfirm.provider(),
+                                  fit: BoxFit.fill,
+                                )
+                            ),
+                            // width: 164.w,
+                            // height: 44.w,
+                            padding: EdgeInsets.only(left: 64.w,right: 29.w),
+                            child: Center(
+                              child: Text(
+                                controller.memberStatusInfo?.expired == false
+                                    ? StringName.memberVipRenew
+                                    : StringName.memberVipUnlock,
+                                style: TextStyle(
+                                    fontSize: 18.sp,
+                                    color: "#9B3800".color,
+                                    fontWeight: FontWeight.bold),
+                              ),
+                            ),
+                          ),
+                        )
+                      ],
                     ),
-                  )
+                  ),
+                  SizedBox(height: 8.w,),
+                  buildPrivacyPolicyView(),
                 ],
               );
             }),
@@ -352,8 +482,8 @@ class MemberPage extends BasePage<MemberController> {
                         ? controller.getUserName(controller.phone!)
                         : StringName.mineAccountGoLogin,
                     style: TextStyle(
-                        fontSize: 16.sp,
-                        color: Colors.white,
+                        fontSize: 13.sp,
+                        color: "#333333".color,
                         fontWeight: FontWeight.bold)),
               );
             }),
@@ -394,7 +524,7 @@ class MemberPage extends BasePage<MemberController> {
             '${DateUtil.fromMillisecondsSinceEpoch('yyyy.MM.dd', controller.memberStatusInfo?.endTimestamp ?? 0)} ${StringName.memberCardExpirationDesc}';
       }
       return Text(desc,
-          style: TextStyle(fontSize: 12.sp, color: Colors.white60));
+          style: TextStyle(fontSize: 11.sp, color: ColorName.black50,fontWeight: FontWeight.w400));
     });
   }
 
@@ -419,14 +549,15 @@ class MemberPage extends BasePage<MemberController> {
               height: 56.w,
               child: Stack(alignment: Alignment.center, children: [
                 Positioned(
-                    left: 12.w,
+                    left: 15.w,
                     child: GestureDetector(
                       onTap: () => controller.onPopBack(),
-                      child: Assets.images.iconWhiteBack
-                          .image(width: 24.w, height: 24.w),
+                      child: Assets.images.iconMemberVipBack
+                          .image(width: 26.w, height: 26..w),
                     )),
+
                 Container(
-                    padding: EdgeInsets.only(left: 40.w,right: 22.w),
+                    padding: EdgeInsets.only(left: 51.w,right: 12.w),
                     child: buildVerticalSlideshowWidget())
               ]),
             ),
@@ -441,11 +572,11 @@ class MemberPage extends BasePage<MemberController> {
       children: [
         Visibility(visible: !Platform.isIOS, child: Spacer()),
         Container(
-          width: 220.w,
-          height: 24.w,
+          width: 192.w,
+          height: 26.w,
           decoration: BoxDecoration(
-            color: '#1F000000'.color,
-            borderRadius: BorderRadius.circular(100.w),
+            color: ColorName.black40,
+            borderRadius: BorderRadius.circular(87.w),
           ),
           child: Center(
               child: AnimatedSwitcherWidget(
@@ -456,15 +587,23 @@ class MemberPage extends BasePage<MemberController> {
           visible: Platform.isIOS && controller.accountRepository.isLogin.value,
             child: GestureDetector(
               onTap: controller.clickRecoverSubscribe,
-              child: Row(
-                children: [
-                  Assets.images.iconAppleRecoverSubscribe.image(width: 14.w,height: 14.w),
-                  Text(StringName.appleRecoverSubscribeTxt,
-                      style: TextStyle(
-                          fontSize: 12.sp,
-                          color: ColorName.white,
-                          fontWeight: FontWeight.w500)),
-                ],
+              child: Container(
+                height: 26.w,
+                decoration: BoxDecoration(
+                  color: ColorName.black40,
+                  borderRadius: BorderRadius.circular(26.w / 2.0),
+                ),
+                padding: EdgeInsets.symmetric(horizontal: 10.w),
+                child: Row(
+                  children: [
+                    Assets.images.iconAppleRecoverSubscribe.image(width: 14.w,height: 14.w),
+                    Text(StringName.appleRecoverSubscribeTxt,
+                        style: TextStyle(
+                            fontSize: 11.sp,
+                            color: ColorName.white,
+                            fontWeight: FontWeight.w500)),
+                  ],
+                ),
               ),
             )
         )

+ 42 - 2
lib/resource/assets.gen.dart

@@ -92,9 +92,9 @@ class $AssetsImagesGen {
   AssetGenImage get iconAlipayScanPayment =>
       const AssetGenImage('assets/images/icon_alipay_scan_payment.webp');
 
-  /// File path: assets/images/icon_apple_recover_subscribe.png
+  /// File path: assets/images/icon_apple_recover_subscribe.webp
   AssetGenImage get iconAppleRecoverSubscribe =>
-      const AssetGenImage('assets/images/icon_apple_recover_subscribe.png');
+      const AssetGenImage('assets/images/icon_apple_recover_subscribe.webp');
 
   /// File path: assets/images/icon_avatar_close.webp
   AssetGenImage get iconAvatarClose =>
@@ -304,6 +304,22 @@ class $AssetsImagesGen {
   AssetGenImage get iconMemberRetainClose =>
       const AssetGenImage('assets/images/icon_member_retain_close.webp');
 
+  /// File path: assets/images/icon_member_settlement_bg.webp
+  AssetGenImage get iconMemberSettlementBg =>
+      const AssetGenImage('assets/images/icon_member_settlement_bg.webp');
+
+  /// File path: assets/images/icon_member_settlement_confirm.webp
+  AssetGenImage get iconMemberSettlementConfirm =>
+      const AssetGenImage('assets/images/icon_member_settlement_confirm.webp');
+
+  /// File path: assets/images/icon_member_vip_back.webp
+  AssetGenImage get iconMemberVipBack =>
+      const AssetGenImage('assets/images/icon_member_vip_back.webp');
+
+  /// File path: assets/images/icon_member_vip_middle_bg.webp
+  AssetGenImage get iconMemberVipMiddleBg =>
+      const AssetGenImage('assets/images/icon_member_vip_middle_bg.webp');
+
   /// File path: assets/images/icon_member_vip_more.webp
   AssetGenImage get iconMemberVipMore =>
       const AssetGenImage('assets/images/icon_member_vip_more.webp');
@@ -532,6 +548,22 @@ class $AssetsImagesGen {
   AssetGenImage get imgMemberFirstWeekDiscountContainer => const AssetGenImage(
       'assets/images/img_member_first_week_discount_container.webp');
 
+  /// File path: assets/images/img_member_header_ad_1.webp
+  AssetGenImage get imgMemberHeaderAd1 =>
+      const AssetGenImage('assets/images/img_member_header_ad_1.webp');
+
+  /// File path: assets/images/img_member_header_ad_2.webp
+  AssetGenImage get imgMemberHeaderAd2 =>
+      const AssetGenImage('assets/images/img_member_header_ad_2.webp');
+
+  /// File path: assets/images/img_member_header_ad_3.webp
+  AssetGenImage get imgMemberHeaderAd3 =>
+      const AssetGenImage('assets/images/img_member_header_ad_3.webp');
+
+  /// File path: assets/images/img_member_header_ad_4.webp
+  AssetGenImage get imgMemberHeaderAd4 =>
+      const AssetGenImage('assets/images/img_member_header_ad_4.webp');
+
   /// File path: assets/images/img_member_retain_container.webp
   AssetGenImage get imgMemberRetainContainer =>
       const AssetGenImage('assets/images/img_member_retain_container.webp');
@@ -627,6 +659,10 @@ class $AssetsImagesGen {
         iconMemberFun6,
         iconMemberPaymentCompleted,
         iconMemberRetainClose,
+        iconMemberSettlementBg,
+        iconMemberSettlementConfirm,
+        iconMemberVipBack,
+        iconMemberVipMiddleBg,
         iconMemberVipMore,
         iconMemberVipReceiveArrow,
         iconMemberVipSign,
@@ -684,6 +720,10 @@ class $AssetsImagesGen {
         imgDialogLocationAlwaysTip2,
         imgDialogLocationAlwaysTip3,
         imgMemberFirstWeekDiscountContainer,
+        imgMemberHeaderAd1,
+        imgMemberHeaderAd2,
+        imgMemberHeaderAd3,
+        imgMemberHeaderAd4,
         imgMemberRetainContainer,
         imgMemberUserCancelsContainer,
         imgTrackAiAnalyse,

+ 8 - 0
pubspec.lock

@@ -1252,6 +1252,14 @@ packages:
       url: "https://pub.dev"
     source: hosted
     version: "2.0.1"
+  smooth_page_indicator:
+    dependency: "direct main"
+    description:
+      name: smooth_page_indicator
+      sha256: b21ebb8bc39cf72d11c7cfd809162a48c3800668ced1c9da3aade13a32cf6c1c
+      url: "https://pub.dev"
+    source: hosted
+    version: "1.2.1"
   source_gen:
     dependency: transitive
     description:

+ 3 - 0
pubspec.yaml

@@ -142,6 +142,9 @@ dependencies:
   #图片压缩
   image: ^4.5.4
 
+  #指示器
+  smooth_page_indicator: ^1.2.1
+
   ######################地图########################
   flutter_map:
     path: plugins/map