FlutterFlow支付墙按钮加载RevenueCat订阅时放大问题解决
问题描述
我在FlutterFlow中构建了一个支付墙组件,但支付按钮在加载RevenueCat订阅计划时会自行放大,iOS端按钮点击前后尺寸有明显变化。
以下是组件代码:
import '../flutter_flow/flutter_flow_theme.dart'; import '../flutter_flow/flutter_flow_util.dart'; import '../flutter_flow/flutter_flow_widgets.dart'; import '../flutter_flow/custom_functions.dart' as functions; import '../flutter_flow/revenue_cat_util.dart' as revenue_cat; import 'package:auto_size_text/auto_size_text.dart'; import 'package:flutter/material.dart'; import 'package:flutter_spinkit/flutter_spinkit.dart'; import 'package:google_fonts/google_fonts.dart'; import 'package:provider/provider.dart'; import 'paywall_model.dart'; export 'paywall_model.dart'; class PaywallWidget extends StatefulWidget { const PaywallWidget({Key? key}) : super(key: key); @override _PaywallWidgetState createState() => _PaywallWidgetState(); } class _PaywallWidgetState extends State<PaywallWidget> { late PaywallModel _model; @override void setState(VoidCallback callback) { super.setState(callback); _model.onUpdate(); } @override void initState() { super.initState(); _model = createModel(context, () => PaywallModel()); } @override void dispose() { _model.maybeDispose(); super.dispose(); } @override Widget build(BuildContext context) { context.watch<FFAppState>(); return ClipRRect( borderRadius: BorderRadius.circular(0.0), child: Container( width: double.infinity, height: MediaQuery.of(context).size.height * 1.0, decoration: BoxDecoration( color: FlutterFlowTheme.of(context).primaryBackground, boxShadow: [ BoxShadow( blurRadius: 4.0, color: Color(0x33000000), offset: Offset(0.0, 2.0), ) ], borderRadius: BorderRadius.circular(0.0), shape: BoxShape.rectangle, border: Border.all( color: FlutterFlowTheme.of(context).primaryBackground, ), ), child: Padding( padding: EdgeInsetsDirectional.fromSTEB(12.0, 12.0, 12.0, 12.0), child: Column( mainAxisSize: MainAxisSize.max, mainAxisAlignment: MainAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Container( width: 500.0, height: 187.1, child: Stack( children: [ Align( alignment: AlignmentDirectional(-0.96, -0.18), child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 10.0, 30.0, 10.0, 30.0), child: SelectionArea( child: Text( revenue_cat.offerings!.current!.lifetime!.product .description, textAlign: TextAlign.start, style: FlutterFlowTheme.of(context).bodyText2, )), ), ), Align( alignment: AlignmentDirectional(-0.96, -0.85), child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 10.0, 10.0, 10.0, 10.0), child: SelectionArea( child: AutoSizeText( revenue_cat .offerings!.current!.lifetime!.product.title .maybeHandleOverflow( maxChars: 100, replacement: '…', ), textAlign: TextAlign.start, style: FlutterFlowTheme.of(context) .subtitle1 .override( fontFamily: 'AvernirNextLTPro', color: FlutterFlowTheme.of(context).primaryText, useGoogleFonts: false, ), )), ), ), Align( alignment: AlignmentDirectional(0.0, 0.0), child: Padding( padding: EdgeInsetsDirectional.fromSTEB( 10.0, 80.0, 10.0, 0.0), child: FFButtonWidget( onPressed: () { print('Button pressed ...'); }, text: functions.concatPriceString(revenue_cat .offerings! .current! .lifetime! .product .priceString)!, options: FFButtonOptions( width: 300.0, padding: EdgeInsetsDirectional.fromSTEB( 0.0, 20.0, 0.0, 20.0), color: Color(0xFF485946), textStyle: FlutterFlowTheme.of(context).subtitle2.override( fontFamily: 'AvernirNextLTPro', color: Colors.white, useGoogleFonts: false, ), elevation: 2.0, borderSide: BorderSide( color: Colors.transparent, width: 1.0, ), borderRadius: BorderRadius.circular(25.0), ), ), ), ), ], ), ), ], ), ), ), ); } }
解决方案
1. 修复异步加载导致的布局重绘
RevenueCat订阅计划是异步加载的,直接访问revenue_cat.offerings!.current!.lifetime!会导致初始状态为null,加载完成后触发重建,引发按钮布局异常。
修改步骤:
- 在
PaywallModel中添加变量存储订阅产品信息 - 在
initState中异步加载订阅计划,加载完成后更新状态
示例修改:
// PaywallModel中新增变量 class PaywallModel extends FlutterFlowModel { // ... 原有代码 PurchasesPackage? lifetimePackage; void setLifetimePackage(PurchasesPackage? package) { lifetimePackage = package; notifyListeners(); } } // 组件中添加异步加载逻辑 @override void initState() { super.initState(); _model = createModel(context, () => PaywallModel()); _loadOfferings(); } Future<void> _loadOfferings() async { try { final offerings = await revenue_cat.getOfferings(); if (offerings != null && offerings.current != null) { _model.setLifetimePackage(offerings.current!.lifetime); } } catch (e) { print('加载订阅计划失败: $e'); } } // build方法中使用_model.lifetimePackage替代直接访问 @override Widget build(BuildContext context) { context.watch<FFAppState>(); final lifetimePackage = _model.lifetimePackage; // 加载中显示占位 if (lifetimePackage == null) { return Center(child: SpinKitCircle(color: FlutterFlowTheme.of(context).primary)); } // ... 原有布局代码,替换所有revenue_cat.offerings!.current!.lifetime!为lifetimePackage }
2. 固定按钮尺寸,避免文本触发缩放
给按钮外层套SizedBox固定宽高,移除按钮自身的width设置,避免文本长度变化导致尺寸异常:
Align( alignment: AlignmentDirectional(0.0, 0.0), child: Padding( padding: EdgeInsetsDirectional.fromSTEB(10.0, 80.0, 10.0, 0.0), child: SizedBox( width: 300.0, height: 60.0, // 匹配按钮上下padding(20*2)+文本高度 child: FFButtonWidget( onPressed: () { print('Button pressed ...'); }, text: functions.concatPriceString(lifetimePackage.product.priceString)!, options: FFButtonOptions( padding: EdgeInsetsDirectional.fromSTEB(0.0, 20.0, 0.0, 20.0), // 移除width设置,由外层SizedBox控制 // width: 300.0, // ... 其他选项不变 ), ), ), ), )
3. 限制AutoSizeText的布局影响
给标题的AutoSizeText设置固定行数和最小字体,避免文本缩放影响父容器布局:
AutoSizeText( lifetimePackage.product.title.maybeHandleOverflow( maxChars: 100, replacement: '…', ), textAlign: TextAlign.start, maxLines: 1, minFontSize: 16, style: FlutterFlowTheme.of(context).subtitle1.override( fontFamily: 'AvernirNextLTPro', color: FlutterFlowTheme.of(context).primaryText, useGoogleFonts: false, ), )
4. 替换Stack为Column,提升布局稳定性
Stack依赖定位容易引发布局偏移,改用Column组织标题、描述和按钮,布局逻辑更清晰稳定:
Container( width: 500.0, height: 187.1, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // 标题 Padding( padding: EdgeInsetsDirectional.fromSTEB(10.0, 10.0, 10.0, 10.0), child: AutoSizeText( lifetimePackage.product.title.maybeHandleOverflow( maxChars: 100, replacement: '…', ), textAlign: TextAlign.start, maxLines: 1, minFontSize: 16, style: FlutterFlowTheme.of(context).subtitle1.override( fontFamily: 'AvernirNextLTPro', color: FlutterFlowTheme.of(context).primaryText, useGoogleFonts: false, ), ), ), // 描述 Padding( padding: EdgeInsetsDirectional.fromSTEB(10.0, 0.0, 10.0, 20.0), child: Text( lifetimePackage.product.description, textAlign: TextAlign.start, style: FlutterFlowTheme.of(context).bodyText2, ), ), // 按钮(居中) Center( child: SizedBox( width: 300.0, height: 60.0, child: FFButtonWidget( // ... 按钮配置 ), ), ), ], ), )
内容的提问来源于stack exchange,提问作者jayapriya durairajan
相关产品推荐
相关产品推荐

