flutter - 不同尺寸设备中的自适应布局

标签 flutter dart flutter-layout

使用Flutter时,如果在不同尺寸的设备上进行测试,则UI会偏移。正如您在我发布的两张图片中所看到的,第一张图片已在iPhone 8 Plus上进行了测试,并且按钮隐藏在横幅广告下方。但是在iPhone 11 Pro的最大尺寸中,该按钮位于我想要的位置。如何维护UI的自适应布局?

enter image description here

enter image description here

import 'dart:math' as math;
//import 'dart:io';

import 'package:flutter/material.dart';
import 'package:firebase_admob/firebase_admob.dart';
import 'package:climatecountdown/urls.dart';

const String testDevice = 'Mobile_id';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CountDownTimer(),
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        iconTheme: IconThemeData(
          color: Colors.white,
        ),
        accentColor: Colors.red,
      ),
    );
  }
}

class CountDownTimer extends StatefulWidget {
  @override
  _CountDownTimerState createState() => _CountDownTimerState();
}

class _CountDownTimerState extends State<CountDownTimer>
    with TickerProviderStateMixin {

  AnimationController controller;


  static const MobileAdTargetingInfo targetingInfo = MobileAdTargetingInfo(
    nonPersonalizedAds: true,
  );

  BannerAd _bannerAd;

  BannerAd createBannerAd(){
    return BannerAd(
        adUnitId: 'ca-app-pub-1136501702308862/4514755428',
        size: AdSize.banner,
        targetingInfo: targetingInfo,
        listener: (MobileAdEvent event){
          print("BannerAd $event");
        }
    );
  }

  var timeLeft = DateTime.now().difference(DateTime.utc(2031, 1, 1)).inDays;
  var timeRemaining = DateTime.utc(2031, 1, 1).difference(DateTime.now()).inDays;


  String get timerString {
    Duration duration = controller.duration * controller.value;
    return '${duration.inDays}';
  }

  @override
  void initState() {
    FirebaseAdMob.instance.initialize(
      appId: 'APPID',
    );
    _bannerAd = createBannerAd()..load()..show();
    super.initState();
    controller = AnimationController(
      vsync: this,
      duration: Duration(days: timeRemaining),
    );
  }

  @override
  void dispose(){
    _bannerAd.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    ThemeData themeData = Theme.of(context);
    return Scaffold(
      backgroundColor: Colors.white10,
      body: AnimatedBuilder(
          animation: controller,
          builder: (context, child) {
            controller.reverse(
                from: controller.value == 0.0
                    ? 1.0
                    : controller.value);
            return Stack(
              children: <Widget>[
                Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    decoration: const BoxDecoration(
                      gradient: LinearGradient(
                          colors: <Color>[
                            Color(0xFF47B82C),
                            Color(0xFF00C231),
                            Color(0xFF47B82C),
                          ]
                      ),
                    ),
                    height:
                    controller.value * MediaQuery.of(context).size.height,
                  ),
                ),
                Padding(
                  padding: EdgeInsets.all(8.0),
                  child: Column(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: <Widget>[
                      Expanded(
                        child: Align(
                          alignment: FractionalOffset.center,
                          child: AspectRatio(
                            aspectRatio: 1.0,
                            child: Stack(
                              children: <Widget>[
                                Positioned.fill(
                                  child: CustomPaint(
                                      painter: CustomTimerPainter(
                                        animation: controller,
                                        backgroundColor: Colors.white,
                                        color: themeData.indicatorColor,
                                      )),
                                ),
                                Align(
                                  alignment: FractionalOffset.center,
                                  child: Column(
                                    mainAxisAlignment:
                                    MainAxisAlignment.spaceEvenly,
                                    crossAxisAlignment:
                                    CrossAxisAlignment.center,
                                    children: <Widget>[
                                      Text(
                                        "Test Text 1",
                                        style: TextStyle(
                                            fontSize: 20.0,
                                            color: Colors.white),
                                      ),
                                      Text(
                                        timerString,
                                        style: TextStyle(
                                            fontSize: 112.0,
                                            color: Colors.white),
                                      ),
                                      Text(
                                        "Test Text 2",
                                        style: TextStyle(fontSize: 20.0,
                                          color: Colors.white,
                                        ),
                                      ),
                                    ],
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ),
                      ),
                    ],
                  ),
                ),
                new Positioned(
                left: 50,
                  right: 50,
                bottom: 120,
                child: new Container(
                  padding: EdgeInsets.fromLTRB(0, 0, 0, 0),
                  alignment: Alignment.bottomCenter,
                  child: new RaisedButton(
                    color: Colors.white,
                    onPressed: (){
                      Navigator.of(context).push(MaterialPageRoute(
                          builder: (BuildContext context) => URLView(
                            websiteName: "Google",
                            websiteURL: "https://google.com",
                          )));
                    },
                    child: Container(
                      decoration: const BoxDecoration(
                        gradient: LinearGradient(
                          colors: <Color>[
                            Color(0xFFFFFFFF),
                            Color(0xFFFFFFFF),
                            Color(0xFFFFFFFF),
                          ],
                        ),
                      ),
                      padding: const EdgeInsets.all(10.0),
                      child: const Text("Test Buttom",
                          style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold,)
                      ),
                    ),
                  ),
                ),
                ),
              ],
            );
          }),
    );
  }
}
class CustomTimerPainter extends CustomPainter {

  CustomTimerPainter({
    this.animation,
    this.backgroundColor,
    this.color,
  }) : super(repaint: animation);

  final Animation<double> animation;
  final Color backgroundColor, color;

  @override
  void paint(Canvas canvas, Size size) {

    Paint paint = Paint()
      ..color = backgroundColor
      ..strokeWidth = 10.0
      ..strokeCap = StrokeCap.butt
      ..style = PaintingStyle.stroke;

    canvas.drawCircle(size.center(Offset.zero), size.width / 2.0, paint);
    paint.color = color;
    double progress = (1.0 - animation.value) * 2 * math.pi;
    canvas.drawArc(Offset.zero & size, math.pi * 1.5, -progress, false, paint);
  }

  @override
  bool shouldRepaint(CustomTimerPainter old) {
    return animation.value != old.animation.value ||
        color != old.color ||
        backgroundColor != old.backgroundColor;
  }
}

最佳答案

尝试将Column小部件与Center小部件一起使用,而不是Stack,并避免在这种情况下使用Positioned

关于flutter - 不同尺寸设备中的自适应布局,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59901949/

相关文章:

android - 升级 flutter 后创建方法 channel - 无法解析方法 getFlutterView()

dart - 如果不适合侧面,如何在 Flutter 中将文本定位在图像下方?

dart - 导航器多次推送同一个屏幕

android - flutter - 在 null 上调用了方法 '[]'(解析 json)

encoding - Dart的ASCII-8位编码

flutter - 我需要在 Flutter App 中的什么位置存储照片图像?

flutter - 断言失败 : line 5143 pos 16: 'child is! ParentDataElement<ParentData>' : is not true

flutter - 如何将小部件放在 flutter 中的模态障碍上方?

flutter - Flutter 容器中的图标间距

flutter - 如何在 flutter 中从图库中获取图像或视频?