第二十二回:对齐和边距类Widget

文章介绍了Flutter中Align和Padding类的使用方法,用于控制Widget的对齐和边距。Align通过alignment属性实现对齐,Padding则通过padding属性设置内边距。示例代码展示了各种对齐和边距设置的效果,强调在实际项目中根据布局情况选择Container的alignment或Align进行对齐控制,以及使用Padding或Container的margin来管理内外边距。


我们在上一章回中介绍了布局约束类Widget相关的内容,,本章回中将介绍 对齐和边距类Widget.闲话休提,让我们一起Talk Flutter吧。

概念介绍

我们在上一章回中介绍了布局约束类Widget,主要用来控制Widget的长度和宽度,布局的长宽确定后还一些细节需要调整,这些细节就是对齐和边距。长宽,对齐和边距一起作用于widget后就可以准确地描述一个Widget在布局中的位置。

在Flutter中对齐使用Align类表示,边距使用Padding类表示,这些类提供了相关的属性来控制自己,接下来将详细介绍它们的使用方法。

使用方法

Align

Align类提供alignmentchild属性,给alignment属性赋值可以约束child属性中的widget.

给alignment属性赋值可以使用常量,比如center,这种对齐是模糊对齐。或者使FractionalOffset类的对象赋值,这种对齐是精准对齐,该类表示比率,它的构造方法接收两个参数,分别表示x和y方向的比率,而具体的值为child中组件的长度或者宽度乘以这个比率。比FractionalOffset(0.5,0.5)center的对齐效果相同。
此外,Container组件也提供了alignment属性,我建议不要混合使用Container和Align的alignment属性,它们两个中选择一个使用就可以达到对齐效果。

Padding

Padding类提供padding和child属性,给panding属性赋值可以约束child属性中的widget.

padding属性赋值需要使用EdgeInsets.all()/only()方法。其中all()表示在start,top,right,bottom四个方向上都添加边距。only()表示只在四个方向中的某一个方向上添加边距。

此外,给margin属性赋值时也可以使用这些方法。不过margin属性是Container组件的属性,它控制的是组件外部的边距,而padding属性是Padding组件的属性,它控制的是组件内部的边距。

示例代码

return Scaffold(
    appBar: AppBar(
      title: const Text("Example of Align and Padding"),
      backgroundColor: Colors.purpleAccent,
    ),
    body: Column(
      mainAxisAlignment: MainAxisAlignment.spaceEvenly,
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        //Container也有Align功能,它和Align最好二选一
        Container(
          margin:const EdgeInsets.only(left: 30.0),
          width: 200,
          height: 200,
          color: Colors.blue,
          alignment:const FractionalOffset(0.1,0.2),
          child: const Text("Column 1"),
        ),
        //三种方法都可以实现居中对齐
        const Align(
          alignment: Alignment.center,
          child: Text("This is a text"),
        ),
        const Align(
          alignment: FractionalOffset(0.5, 0.5),
          child: Text("This is a text"),
        ),
        const Center(
          child: Text("This is a text"),
        ),
        //全部和部分设置内边距
        const Padding(
          padding:EdgeInsets.all(10.0),
          child: Text("This is a text"),
        ),
        const Padding(
          padding: EdgeInsets.only(left: 10.0),
          child: Text("This is a text"),
        ),
      ],
    )
);

我在这里只列出了核心代码,完整的代码可以查看Github上ex013文件中的代码。我建议大家动手调整一下代码,这样可以体会到对齐的边距的真实效果。

经验总结

在实际项目中对齐常用来控制布局中的子组件,也就是指父布局中子组件的对齐方式。我的经验是:

  • 如果父布局中使用了Container组件,那么使用它的对齐属性控制子组件的对齐方式;
  • 如果父布局中没有使用Container组件那么需要在子组件外嵌套一个Align组件,专门使用它来控制子组件的对齐方式。这两种方法在代码中都有示例,大家可以参考示例程序中的代码。

边距分内外两种边距,我的经验是:

  • 如果父布局中没有使用Container组件那么需要在子组件外嵌套一个Padding组件,专门使用它来控制子组件的内边距;
  • 如果父布局中使用了Container组件那么直接使用父布局的margin属性,它可以控制子组件的外部边距。通常外部边距使用的情况比较多。

看官们,关于对齐和边距类Widget相关的内容就介绍到这里,欢迎大家在评论区交流与讨论!

#include "widget.h" #include <QDebug> #include <QMessageBox> #include <QFont> #include <QMediaPlaylist> Widget::Widget(QWidget *parent) : QWidget(parent), stackedWidget(nullptr), mainPage(nullptr), loginRegisterPage(nullptr), pageLogin(nullptr), pageRegister(nullptr), titleLabel(nullptr), btnRegisterLogin(nullptr), btnStartGame(nullptr), btnSettings(nullptr), btnLeaderboard(nullptr), btnExit(nullptr), gifLabel(nullptr), movie(nullptr), settingmusicPage(nullptr), dbManager(nullptr), roleSelectionPage(nullptr), levelSelectionPage(nullptr), selectedRoleIndex(-1) { setWindowTitle("哈基迷大探险"); resize(800, 700); move(550, 50); setWindowIcon(QIcon(":/picture/mimi1.png")); stackedWidget = new QStackedWidget(this); QVBoxLayout *mainContainerLayout = new QVBoxLayout(this); mainContainerLayout->addWidget(stackedWidget); mainContainerLayout->setContentsMargins(0, 0, 0, 0); setLayout(mainContainerLayout); mainPage = new QWidget(); QVBoxLayout *mainPageLayout = new QVBoxLayout(mainPage); titleLabel = new QLabel(mainPage); titleLabel->setAlignment(Qt::AlignCenter); titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); titleLabel->setMinimumSize(800, 200); QPixmap originalPixmap(":/picture/title.png"); if (!originalPixmap.isNull()) { QPixmap scaledPixmap = originalPixmap.scaled( titleLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation ); titleLabel->setPixmap(scaledPixmap); } else { titleLabel->setText("图片加载失败"); titleLabel->setStyleSheet("color: red"); } mainPageLayout->addWidget(titleLabel); mainPageLayout->addSpacing(40); QGridLayout *gridLayout = new QGridLayout(); btnRegisterLogin = new QPushButton("注册/登录", mainPage); btnStartGame = new QPushButton("开始游戏", mainPage); btnSettings = new QPushButton("游戏设置", mainPage); btnLeaderboard = new QPushButton("排行榜", mainPage); btnExit = new QPushButton("退出游戏", mainPage); QFont btnFont("Arial", 14); QPushButton* btns[] = {btnRegisterLogin, btnStartGame, btnSettings, btnLeaderboard, btnExit}; for (auto btn : btns) { btn->setFont(btnFont); btn->setMinimumSize(200, 50); btn->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); btn->setStyleSheet( "QPushButton {" " background-color: pink;" " color: white;" " border: 2px solid white;" " font: bold 14px;" " border-radius: 10px;" "}" "QPushButton:hover {" " background-color: #ff88aa;" "}" "QPushButton:pressed {" " background-color: white;" " color: pink;" "}" ); } gridLayout->addWidget(btnRegisterLogin, 0, 0); gridLayout->addWidget(btnStartGame, 0, 1); gridLayout->addWidget(btnSettings, 1, 0); gridLayout->addWidget(btnLeaderboard, 1, 1); gridLayout->addWidget(btnExit, 2, 0, 1, 2); gridLayout->setSpacing(20); gridLayout->setContentsMargins(50, 20, 50, 20); mainPageLayout->addLayout(gridLayout); gifLabel = new QLabel(mainPage); gifLabel->setAlignment(Qt::AlignCenter); movie = new QMovie(":/gif/mimi2.gif", QByteArray(), mainPage); if (movie->isValid()) { gifLabel->setMovie(movie); movie->start(); gifLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); } else { gifLabel->setText("动图加载失败"); gifLabel->setStyleSheet("color: red"); } mainPageLayout->addWidget(gifLabel); mainPageLayout->setContentsMargins(10, 10, 10, 10); mainPageLayout->setSpacing(10); mainPage->setLayout(mainPageLayout); loginRegisterPage = new childwidget(); pageLogin = new Login(); pageRegister = new RegisterWidget(); stackedWidget->addWidget(mainPage); stackedWidget->addWidget(loginRegisterPage); stackedWidget->addWidget(pageLogin); stackedWidget->addWidget(pageRegister); dbManager = new DatabaseManager(this); if (!dbManager->initDatabase()) { QMessageBox::critical(this, "数据库错误", "无法初始化数据库,请检查应用权限"); } roleSelectionPage = new RoleSelection(); stackedWidget->addWidget(roleSelectionPage); levelSelectionPage = new LevelSelection(); stackedWidget->addWidget(levelSelectionPage); rankingListPage = new RankingList(); stackedWidget->addWidget(rankingListPage); settingmusicPage = new settingmusic(this); stackedWidget->addWidget(settingmusicPage); connect(settingmusicPage, &settingmusic::backToPrevious, this, [=]() { stackedWidget->setCurrentWidget(mainPage); }); connect(btnSettings, &QPushButton::clicked, this, [=]() { stackedWidget->setCurrentWidget(settingmusicPage); }); connect(btnLeaderboard, &QPushButton::clicked, this, [=]() { QVector<RankingInfo> rankingData = dbManager->getRankingList(-1); rankingListPage->setRankingData(rankingData); stackedWidget->setCurrentWidget(rankingListPage); qDebug() << "切换到排行榜页面"; }); connect(rankingListPage, &RankingList::backToMainPage, this, [=]() { stackedWidget->setCurrentWidget(mainPage); }); connect(btnRegisterLogin, &QPushButton::clicked, this, &Widget::onRegisterLoginClicked); connect(loginRegisterPage, &childwidget::backToMainPage, this, &Widget::onBackToMainPage); connect(loginRegisterPage, &childwidget::gotoLoginPage, this, &Widget::onGotoLogin); connect(loginRegisterPage, &childwidget::gotoRegisterPage, this, &Widget::onGotoRegister); connect(pageLogin, &Login::loginRequested, this, &Widget::handleLogin); connect(pageRegister, &RegisterWidget::registerRequested, this, &Widget::handleRegister); connect(pageLogin, &Login::backToPrevious, this, &Widget::onRegisterLoginClicked); connect(pageRegister, &RegisterWidget::backToPrevious, this, &Widget::onRegisterLoginClicked); connect(btnExit, &QPushButton::clicked, this, &Widget::close); connect(btnSettings, &QPushButton::clicked, this, [=]() { stackedWidget->setCurrentWidget(settingmusicPage); }); connect(this, &Widget::loginSuccess, this, [=]() { stackedWidget->setCurrentWidget(roleSelectionPage); qDebug() << "登录成功,跳转至角色选择页"; }); connect(roleSelectionPage, &RoleSelection::backToPrevious, this, [=]() { stackedWidget->setCurrentWidget(mainPage); }); connect(roleSelectionPage, &RoleSelection::roleConfirmed, this, [=](int index) { QMessageBox::information(this, "选择成功", QString("你选择了角色:%1").arg(roleSelectionPage->getRoleInfo(index).name)); selectedRoleIndex = index; stackedWidget->setCurrentWidget(levelSelectionPage); }); connect(levelSelectionPage, &LevelSelection::backToRoleSelection, this, [=]() { stackedWidget->setCurrentWidget(roleSelectionPage); }); connect(levelSelectionPage, &LevelSelection::levelConfirmed, this, &Widget::handleLevelSelected); connect(btnStartGame, &QPushButton::clicked, this, [=]() { if (currentUsername.isEmpty()) { QMessageBox::information(this, "提示", "请先登录才能开始游戏!"); stackedWidget->setCurrentWidget(pageLogin); } else { stackedWidget->setCurrentWidget(roleSelectionPage); } }); } Widget::~Widget() { delete movie; } void Widget::onRegisterLoginClicked() { stackedWidget->setCurrentWidget(loginRegisterPage); qDebug() << "切换到登录/注册选择页面"; } void Widget::onBackToMainPage() { stackedWidget->setCurrentWidget(mainPage); qDebug() << "切回主页面"; } void Widget::onGotoLogin() { stackedWidget->setCurrentWidget(pageLogin); qDebug() << "切换到登录页面"; } void Widget::onGotoRegister() { stackedWidget->setCurrentWidget(pageRegister); qDebug() << "切换到注册页面"; } void Widget::handleLogin(const QString& username, const QString& password) { if (dbManager->verifyUser(username, password)) { QMessageBox::information(this, "登录成功", "欢迎回来," + username + "!"); currentUsername = username; emit loginSuccess(); } else { QMessageBox::warning(this, "登录失败", "用户名或密码错误"); } } void Widget::handleRegister(const QString &username, const QString &password, const QString &confirmPassword) { if (password != confirmPassword) { QMessageBox::warning(this, "注册失败", "两次输入的密码不一致!"); return; } if (!dbManager->m_db.isOpen() && !dbManager->m_db.open()) { QMessageBox::critical(this, "注册失败", "数据库连接失败,请重试!"); return; } if (dbManager->registerUser(username, password)) { QMessageBox::information(this, "注册成功", "注册成功,请登录!"); stackedWidget->setCurrentWidget(pageLogin); } else { QMessageBox::warning(this, "注册失败", "用户名已存在或注册失败!"); } } void Widget::handleRoleSelected(int index) { selectedRoleIndex = index; qDebug() << "选择角色索引:" << index; stackedWidget->setCurrentWidget(levelSelectionPage); } void Widget::handleLevelSelected(int levelIndex) { if (selectedRoleIndex == -1) { QMessageBox::warning(this, "错误", "请先选择角色!"); return; } Player::RoleType roleType = (selectedRoleIndex == 0) ? Player::RoleType::Mimi : Player::RoleType::Yika; GameWidget* gameWidget = new GameWidget(roleType, levelIndex, currentUsername, dbManager, this); gameWidget->show(); } 具体解释一下每行代码什么意思
09-23
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

talk_8

真诚赞赏,手有余香

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值