【07】flutter完成主页-完成底部菜单栏并且做自定义组件-完整短视频仿抖音上下滑动页面
上篇我们做了自定义组件,本文继续完善注册相关页面并且实现跳转
闲话不多,开源仓库地址,可以观摩已经写好的代码:
https://gitee.com/youyacao/ff-flutter
我们新建 index.dart,首先写页面,插入基础内容有两种,在Flutter中,Scaffold 和 Container 是两个非常重要的小部件,它们分别有不同的用途和功能。
这两个小部件写法是一直的,但是写页面大框架的时候我们需要选择Scaffold,我们在写底部菜单栏就应该选择 Container 。
扩展知识
return Scaffold( 和return Container( 的区别是什么
在Flutter中,Scaffold
和 Container
是两个非常重要的小部件,它们分别有不同的用途和功能。
Scaffold
是一个用于实现Material Design布局结构的控件,通常用于创建一个完整的应用页面。它提供了一些特有的属性和功能,能够轻松实现应用常见的布局元素,例如应用栏(AppBar)、抽屉(Drawer)、浮动操作按钮(FloatingActionButton)、底部导航栏(BottomNavigationBar)等。
dart
Scaffold(
appBar: AppBar(
title: Text('My App'),
),
body: Center(
child: Text('Hello, world!'),
),
floatingActionButton: FloatingActionButton(
onPressed: () {},
child: Icon(Icons.add),
),
)
Container
是一个通用的小部件,它可以包含单个子组件并允许进行一些简单的布局配置。Container
主要用于包装和装饰子组件,比如设置边距、内边距、对齐方式、背景颜色、边框等属性。与 Scaffold
不同,Container
不提供预定义的布局结构。
dart
Container(
padding: EdgeInsets.all(16.0),
margin: EdgeInsets.all(16.0),
alignment: Alignment.center,
color: Colors.blue,
child: Text(
'Hello, world!',
style: TextStyle(color: Colors.white),
),
)
我们插入
class IndexScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1E1E1E), // 设置背景颜色为 #1E1E1E
appBar: AppBar(
title: Text('Index Screen'),
),
body: Center(
child: Text('Welcome to the Index Screen'),
),
);
}
}
首先我们来做首页:
我们再将页面其他内容 写入 scaffold 里面,正确融入进去
通常,我们会使用 Column 和 Row 来组织这些组件来实现,
当写顶部左边文字后,写右边下载图标和按钮,我们发现 iconlogo 不对,
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
class IndexScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1E1E1E), // 设置背景颜色为 #1E1E1E
appBar: AppBar(
title: Text('Index Screen'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 16, top: 16, right: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Free Friend",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
DownloadButton(),
],
),
),
// 其他内容可以继续添加在这里
Expanded(
child: Center(
child: Text('Welcome to the Index Screen'),
),
),
],
),
);
}
}
class DownloadButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton.icon(
onPressed: () {
// 处理下载逻辑
},
icon: FlutterLogo(size: 30),
label: Text(
"Download",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 26,
fontFamily: "PingFang SC",
fontWeight: FontWeight.w800,
),
),
style: ElevatedButton.styleFrom(
primary: Color(0xffe7568c),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(27),
),
padding: EdgeInsets.symmetric(horizontal: 17, vertical: 9),
minimumSize: Size(195, 54),
),
);
}
}
我们替换图标为
icon: Icon(Icons.system_update_alt, size: 30),
扩展知识-关于flutter图标库的
Flutter 提供了一整套 Material Design 图标库,包含了数百个常用图标。你可以使用这些图标来实现多种设计需求。Material Icons 是一个非常丰富的图标库,每个图标都有一个唯一的名称和代码点,可以在代码中直接引用。
要在Flutter中使用这些图标,你需要导入 flutter/material.dart
包,然后使用 Icon
小部件和 Icons
类来引用图标。
dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: Text('Flutter Icons 示例'),
),
body: Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(Icons.home, size: 50.0), // Home 图标
SizedBox(width: 20),
Icon(Icons.favorite, size: 50.0, color: Colors.red), // Favorite 图标
SizedBox(width: 20),
Icon(Icons.settings, size: 50.0), // Settings 图标
],
),
),
),
);
}
}
以下是一些常用的图标和它们的名称:
图标 | 名称 | 用法 |
---|---|---|
Icons.home | Icon(Icons.home) | |
Icons.favorite | Icon(Icons.favorite) | |
Icons.settings | Icon(Icons.settings) | |
Icons.search | Icon(Icons.search) | |
Icons.account_circle | Icon(Icons.account_circle) | |
Icons.add | Icon(Icons.add) | |
Icons.email | Icon(Icons.email) | |
Icons.alarm | Icon(Icons.alarm) | |
Icons.camera_alt | Icon(Icons.camera_alt) | |
Icons.check_circle | Icon(Icons.check_circle) |
这些只是 Flutter Material Icons 库中的一小部分。要查看完整的图标列表和它们的名称,你可以访问 Material Icons 库,并在代码中相应地使用 Icons.<icon_name>
来引用图标。
以下是我们的代码 但是我们发现问题:
The named parameter ‘primary’ isn’t defined. Try correcting the name to an existing named parameter’s name, or defining a named parameter with the name ‘primary’.
提示primary未定义
在 Flutter 中,ElevatedButton.styleFrom 方法并没有 primary 这个命名参数。相反,你应该使用 primaryColor 或 backgroundColor 来设置按钮的背景颜色。
import 'package:flutter/material.dart';
import 'package:logging/logging.dart';
class IndexScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1E1E1E), // 设置背景颜色为 #1E1E1E
appBar: AppBar(
title: Text('Index Screen'),
),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 16, top: 16, right: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Free Friend",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
DownloadButton(),
],
),
),
// 其他内容可以继续添加在这里
Expanded(
child: Center(
child: Text('Welcome to the Index Screen'),
),
),
],
),
);
}
}
class DownloadButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton.icon(
onPressed: () {
// 处理下载逻辑
},
icon: Icon(Icons.system_update_alt, size: 30),
label: Text(
"Download",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 26,
fontFamily: "PingFang SC",
fontWeight: FontWeight.w800,
),
),
style: ElevatedButton.styleFrom(
primary: Color(0xffe7568c),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(27),
),
padding: EdgeInsets.symmetric(horizontal: 17, vertical: 9),
minimumSize: Size(195, 54),
),
);
}
}
扩展知识
在Flutter中,primary
和 backgroundColor
都是用于设置颜色的属性,但它们用于不同的场景和目的。
primary
primary
颜色通常用于应用的主要颜色。这是Material Design中的一个核心概念,用于突出显示应用程序的品牌颜色和主要UI元素。它在应用的许多地方都会被用到,例如应用栏、浮动操作按钮(FAB)等。
dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: ThemeData(
primaryColor: Colors.blue, // 设置应用的主要颜色
),
home: Scaffold(
appBar: AppBar(
title: Text('Primary Color 示例'),
),
body: Center(
child: ElevatedButton(
onPressed: () {},
child: Text('按钮'),
),
),
),
);
}
}
backgroundColor
backgroundColor
用于设置组件或容器的背景颜色。它可以用于多种小部件,例如 Container
、Scaffold
和 AppBar
等。使用 backgroundColor
属性可以更具体地控制某个小部件的背景颜色。
dart
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
backgroundColor: Colors.grey[200], // 设置 Scaffold 的背景颜色
appBar: AppBar(
title: Text('BackgroundColor 示例'),
backgroundColor: Colors.blue, // 设置 AppBar 的背景颜色
),
body: Center(
child: Container(
width: 200,
height: 200,
color: Colors.white, // 设置 Container 的背景颜色
child: Center(child: Text('Hello, world!')),
),
),
),
);
}
}
primary
:ThemeData(primaryColor: Colors.blue)
。backgroundColor
:Container(color: Colors.white)
,Scaffold(backgroundColor: Colors.grey[200])
。大白话 就是,小部件用backgroundColor,整个应用主题颜色采用primary,(关于创建切换theme主题才用的到)
我们社交app就一个模板,所以用不上,接下来我们放入 右侧的图标按钮以及下方的图标和文字,以下是代码:
import 'package:flutter/material.dart';
class IndexScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1E1E1E), // 设置背景颜色为 #1E1E1E
// appBar: AppBar(
// title: Text('Index Screen'),
// ),
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 16, top: 16, right: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Free Friend",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
Row(
children: [
DownloadButton(),
SizedBox(width: 16), // 添加间距
CustomIconButton(),
],
),
],
),
),
SizedBox(height: 16), // 添加间距
Padding(
padding: const EdgeInsets.only(left: 16),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Color(0xffe7568c), // 设置背景颜色为 0xffe7568c
),
child: Icon(
Icons.location_on,
size: 36,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
),
SizedBox(width: 10),
Text(
"America",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
],
),
),
// 其他内容可以继续添加在这里
Expanded(
child: Center(
child: Text('Welcome to the Index Screen'),
),
),
],
),
);
}
}
class DownloadButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton.icon(
onPressed: () {
// 处理下载逻辑
},
icon: Icon(
Icons.system_update_alt,
size: 30,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
label: Text(
"Download",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 26,
fontFamily: "PingFang SC",
fontWeight: FontWeight.w800,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xffe7568c), // 使用 backgroundColor 替代 primary
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(27),
),
padding: EdgeInsets.symmetric(horizontal: 17, vertical: 9),
minimumSize: Size(195, 54),
),
);
}
}
class CustomIconButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 54,
height: 54,
child: Stack(
children: [
Container(
width: 54,
height: 54,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff151313),
),
),
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Icon(
Icons.notifications,
size: 36,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
),
),
],
),
);
}
}
接着我们做下面的定位按钮以及文字,
如何将一个容器完全放置于左侧,使用 Padding 组件为 Row 添加左侧内边距 const EdgeInsets.only(left: 16),以确保整个容器放置在左侧, 以下是代码文件:
以下代码"America" 及其前面的图标 以及前面的图标 已经设置了容器在左侧,为什么还是显示在屏幕的中间
import 'package:flutter/material.dart';
class IndexScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Color(0xFF1E1E1E), // 设置背景颜色为 #1E1E1E
body: Column(
children: [
Padding(
padding: const EdgeInsets.only(left: 16, top: 16, right: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Free Friend",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
Row(
children: [
DownloadButton(),
SizedBox(width: 16), // 添加间距
CustomIconButton(),
],
),
],
),
),
SizedBox(height: 16), // 添加间距
Padding(
padding: const EdgeInsets.only(left: 16),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: Color(0xffe7568c), // 设置背景颜色为 0xffe7568c
),
child: Icon(
Icons.location_on,
size: 36,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
),
SizedBox(width: 10),
Text(
"America",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
],
),
),
Expanded(
child: Center(
child: Text('Welcome to the Index Screen'),
),
),
],
),
);
}
}
class DownloadButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton.icon(
onPressed: () {
// 处理下载逻辑
},
icon: Icon(
Icons.system_update_alt,
size: 30,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
label: Text(
"Download",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 26,
fontFamily: "PingFang SC",
fontWeight: FontWeight.w800,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: Color(0xffe7568c), // 使用 backgroundColor 替代 primary
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(27),
),
padding: EdgeInsets.symmetric(horizontal: 17, vertical: 9),
minimumSize: Size(195, 54),
),
);
}
}
class CustomIconButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 54,
height: 54,
child: Stack(
children: [
Container(
width: 54,
height: 54,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff151313),
),
),
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: Icon(
Icons.notifications,
size: 36,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
),
),
],
),
);
}
}
但是实际并没有到左侧,因为需要进行如下处理,可以将 CrossAxisAlignment.start 添加到 Column 和 Row 的交叉轴对齐属性中,在 Column 中添加了 crossAxisAlignment: CrossAxisAlignment.start 属性,以确保所有子元素在交叉轴上对齐到左侧。这应该能使 “America” 及其前面的图标对齐到左侧,而不是显示在屏幕的中间。
import 'package:flutter/material.dart';
class IndexScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF1E1E1E), // 设置背景颜色为 #1E1E1E
body: Column(
crossAxisAlignment: CrossAxisAlignment.start, // 添加这个属性
children: [
Padding(
padding: const EdgeInsets.only(left: 16, top: 16, right: 16),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
const Text(
"Free Friend",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
Row(
children: [
DownloadButton(),
const SizedBox(width: 16), // 添加间距
CustomIconButton(),
],
),
],
),
),
const SizedBox(height: 16), // 添加间距
Padding(
padding: const EdgeInsets.only(left: 16),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
color: const Color(0xffe7568c), // 设置背景颜色为 0xffe7568c
),
child: const Icon(
Icons.location_on,
size: 36,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
),
const SizedBox(width: 10),
const Text(
"America",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 32,
fontFamily: "SansSerif",
fontWeight: FontWeight.w700,
),
),
],
),
),
Expanded(
child: Center(
child: const Text('Welcome to the Index Screen'),
),
),
],
),
);
}
}
class DownloadButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ElevatedButton.icon(
onPressed: () {
// 处理下载逻辑
},
icon: const Icon(
Icons.system_update_alt,
size: 30,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
label: const Text(
"Download",
style: TextStyle(
color: Color(0xfff1f1f1),
fontSize: 26,
fontFamily: "PingFang SC",
fontWeight: FontWeight.w800,
),
),
style: ElevatedButton.styleFrom(
backgroundColor: const Color(0xffe7568c), // 使用 backgroundColor 替代 primary
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(27),
),
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 9),
minimumSize: const Size(195, 54),
),
);
}
}
class CustomIconButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
width: 54,
height: 54,
child: Stack(
children: [
Container(
width: 54,
height: 54,
decoration: const BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff151313),
),
),
Positioned.fill(
child: Align(
alignment: Alignment.center,
child: const Icon(
Icons.notifications,
size: 36,
color: Color(0xfff1f1f1), // 设置图标颜色为 0xfff1f1f1
),
),
),
],
),
);
}
}
显示效果
—— 晚点更新
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。