Stack布局
继续上篇文章弹性盒子布局进行学习,这一篇我们主要是探索Stack
层叠布局
Stack
层叠样式 与 Positioned配合使用
Stack
是多层布局,主轴方向是从内向外。
Positioned
小部件有left
、right
、top
、bottom
四个属性定位,参数是像素位置。
-
layout_demo.dart
文件添加如下代码
import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return StackDemo();
}
}
class StackDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.yellow,
alignment: const Alignment(0, -1),
child: Stack(
children: [
//Positioned 绝对定位
Positioned(
child: Container(
color: Colors.white,
width: 200,
height: 200,
child: const Icon(Icons.add),
),
),
Positioned(
child: Container(
color: Colors.red,
width: 100,
height: 100,
child: const Icon(Icons.search_off),
),
left: 0,
),
Positioned(
child: Container(
color: Colors.blue,
width: 50,
height: 50,
child: const Icon(Icons.search),
// margin: EdgeInsets.only(right: 20),
),
right: 0,
// right: 20,
),
],
),
);
}
}
运行效果
AspectRatio用来影响父部件宽高
AspectRatio
的设置影响的是父布局,当父布局同时有宽度和高度,设置宽高比失效
- 使用
AspectRatio
宽高比,只给Container
小部件设置height
,会按照比例自动生成高度
import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
color: Colors.yellow,
width: 300,
height: 300,
alignment: const Alignment(0, 0),
child: Container(
//属性:child
color: Colors.blue,
height: 150,
child: const AspectRatio(
aspectRatio: 1 / 1,
),
),
);
}
}
运行效果
- 给
Container
小部件同时设置width
、height
,再设置AspectRatio
宽高比将无效
import 'package:flutter/material.dart';
class LayoutDemo extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
color: Colors.yellow,
width: 300,
height: 300,
alignment: const Alignment(0, 0),
child: Container(
//属性:child
color: Colors.blue,
height: 150,
width: 200,
child: const AspectRatio(
aspectRatio: 1 / 1,
),
),
);
}
}
运行效果
Flutter的Widget状态管理
flutter
中小部件大都是无状态的
,如果小部件有变化,就需要改变其状态,下面自定义一个有状态的小部件
。
StatefulWidget
有状态小部件,用于对外提供接口,继承自State
用来管理状态;需实现build
方法访问数据,数据在state
中,通过setState
设置/改变数据。
有状态的Widget
,需要把渲染逻辑
和数据逻辑
分开,并且保留数据逻辑。
- 新建
state_mag_demo.dart
文件
import 'package:flutter/material.dart';
//渲染逻辑,仍然是不可变的!!
class StateManagerDemo extends StatefulWidget {
@override
// 创建数据管理对象
State<StatefulWidget> createState() => _SMDState();
}
//状态管理者,State<StateManagerDemo>表示用于管理StateManagerDemo
//_SMDState表示私有类,只在当前文件内可用
class _SMDState extends State<StateManagerDemo> {
int count = 0;
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Scaffold(
backgroundColor: Colors.grey[100],
appBar: AppBar(
title: const Text('StateDemo'),
),
body: Center(
// Chip气泡小部件
child: Chip(
label: Text('$count'),
),
),
// 添加悬浮按钮
floatingActionButton: FloatingActionButton(
child: const Icon(Icons.add),
onPressed: () {
//实时设置count数据,用于页面刷新。调用一次setState相当于调用一次build方法,因为flutter是增量渲染,所以只会执行Text('$count'),效率会很高
//setState影响的是build方法内所有与count相关的地方,可能会是多个
setState(() {
count += 1;
});
print("count = $count");
},
),
),
);
}
}
-
main.dart
文件中调用StateManagerDemo()
import 'package:flutter/material.dart';
import 'package:hello_flutter/state_mag_demo.dart';
void main() => runApp(App());
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return StateManagerDemo();
}
}
运行效果
搭建项目
Flutter
的基础组件
以及用法我们已经学完了,下面我们来搭建一个微信项目
,通过这个项目,我们在实战中学习网络多线程
等
- 新建一个flutter工程,名称为
wechat_demo
- 创建工程底部
BottomNavigationBar
<!-- main.dart文件 -->
import 'package:flutter/material.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: Scaffold(
bottomNavigationBar: BottomNavigationBar(
//BottomNavigationBarItem 三个的话,默认选中是蓝色,四个的话变成了白色,所以这里要加type属性修改样式
type: BottomNavigationBarType.fixed,
//BottomNavigationBarItem 选中颜色修改
fixedColor: Colors.green,
//currentIndex 修改选中的BottomNavigationBarItem 默认是0
currentIndex: _currentIndex,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.chat), label: '微信'),
BottomNavigationBarItem(icon: Icon(Icons.bookmark), label: '通讯录'),
BottomNavigationBarItem(icon: Icon(Icons.history), label: '发现'),
BottomNavigationBarItem(icon: Icon(Icons.person_outline), label: '我的'),
],
),
),
);
}
}
运行效果
- 新建根页面
root_page.dart
,并且把main.dart
文件中代码迁移过来
<!-- root_page.dart文件 -->
import 'package:flutter/material.dart';
class RootPage extends StatefulWidget {
@override
_RootPageState createState() => _RootPageState();
}
class _RootPageState extends State<RootPage> {
int _currentIndex = 0;
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: Scaffold(
bottomNavigationBar: BottomNavigationBar(
//BottomBar点击事件
onTap:(index) {
setState(() {
_currentIndex = index;
});
},
//BottomNavigationBarItem 三个的话,默认选中是蓝色,四个的话变成了白色,所以这里要加type属性修改样式
type: BottomNavigationBarType.fixed,
//BottomNavigationBarItem 选中颜色修改
fixedColor: Colors.green,
//currentIndex 修改选中的BottomNavigationBarItem 默认是0
currentIndex: _currentIndex,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.chat), label: '微信'),
BottomNavigationBarItem(icon: Icon(Icons.bookmark), label: '通讯录'),
BottomNavigationBarItem(icon: Icon(Icons.history), label: '发现'),
BottomNavigationBarItem(icon: Icon(Icons.person_outline), label: '我的'),
],
),
),
);
}
}
<!-- main.dart文件 -->
import 'package:flutter/material.dart';
import 'package:wechat_demo/root_page.dart';
void main() {
runApp(App());
}
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
return MaterialApp(
home: RootPage(),
);
}
}
运行效果
- 新建 微信 -
chat_page.dart
、通讯录 -friends_page.dart
、发现 -discover_page.dart
、我的 -mine_page.dart
页面
<!-- chat_page.dart文件 -->
import 'package:flutter/material.dart';
class ChatPage extends StatefulWidget {
@override
_ChatPageState createState() => _ChatPageState();
}
class _ChatPageState extends State<ChatPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('微信页面'),
),
body: const Center(
child: Text('微信页面'),
),
);
}
}
<!-- friends_page.dart文件 -->
import 'package:flutter/material.dart';
class FriendsPage extends StatefulWidget {
@override
_FriendsPageState createState() => _FriendsPageState();
}
class _FriendsPageState extends State<FriendsPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('通讯录'),
),
body: const Center(
child: Text('通讯录'),
),
);
}
}
<!-- discover_page.dart文件 -->
import 'package:flutter/material.dart';
class DiscoverPage extends StatefulWidget {
@override
_DiscoverPageState createState() => _DiscoverPageState();
}
class _DiscoverPageState extends State<DiscoverPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('发现页面'),
),
body: const Center(
child: Text('发现页面'),
),
);
}
}
<!-- mine_page.dart文件 -->
import 'package:flutter/material.dart';
class MinePage extends StatefulWidget {
@override
_MinePageState createState() => _MinePageState();
}
class _MinePageState extends State<MinePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('我的页面'),
),
body: const Center(
child: Text('我的页面'),
),
);
}
}
-
root_page.dart
中引入上面创建的四个页面
import 'package:flutter/material.dart';
import 'package:wechat_demo/chat_page.dart';
import 'package:wechat_demo/discover_page.dart';
import 'package:wechat_demo/friends_page.dart';
import 'package:wechat_demo/mine_page.dart';
class RootPage extends StatefulWidget {
@override
_RootPageState createState() => _RootPageState();
}
class _RootPageState extends State<RootPage> {
int _currentIndex = 0;
//配置四个页面
List <Widget> _pages = [ChatPage(), FriendsPage(), DiscoverPage(), MinePage()];
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: Scaffold(
// 选中BottomBar配置body页面
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
//BottomBar点击事件
onTap:(index) {
setState(() {
_currentIndex = index;
});
},
//BottomNavigationBarItem 三个的话,默认选中是蓝色,四个的话变成了白色,所以这里要加type属性修改样式
type: BottomNavigationBarType.fixed,
//BottomNavigationBarItem 选中颜色修改
fixedColor: Colors.green,
//currentIndex 修改选中的BottomNavigationBarItem 默认是0
currentIndex: _currentIndex,
items: const [
BottomNavigationBarItem(icon: Icon(Icons.chat), label: '微信'),
BottomNavigationBarItem(icon: Icon(Icons.bookmark), label: '通讯录'),
BottomNavigationBarItem(icon: Icon(Icons.history), label: '发现'),
BottomNavigationBarItem(icon: Icon(Icons.person_outline), label: '我的'),
],
),
),
);
}
}
运行效果
水波纹、标题头、选中字体大小属性配置
-
title属性
:用于安卓设备 退出后台顶部显示app名称 -
highlightColor属性
、splashColor属性
:用于取消水波纹效果 -
primarySwatch属性
:用于设置NaviBar
主题色
<!-- main.dart文件 -->
class App extends StatelessWidget {
@override
Widget build(BuildContext context) {
// TODO: implement build
// MaterialApp类似于iOS中 UIApplicationMain
return MaterialApp(
// title用于安卓设备 退出后台顶部显示app名称
title: 'WeChatDemo',
theme: ThemeData(
// 去掉水波纹效果
highlightColor: Color.fromRGBO(1, 0, 0, 0.0),
splashColor: Color.fromRGBO(1, 0, 0, 0.0),
// 设置NavigationBar主题色,全局有效
primarySwatch: Colors.grey,
),
home: RootPage(),
);
}
}
-
selectedFontSize属性
:用于设置BottomBar
选中字体大小
<!-- root_page.dart文件 -->
class _RootPageState extends State<RootPage> {
int _currentIndex = 0;
//配置四个页面
List <Widget> _pages = [ChatPage(), FriendsPage(), DiscoverPage(), MinePage()];
@override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
child: Scaffold(
body: _pages[_currentIndex],
bottomNavigationBar: BottomNavigationBar(
// 设置BottomBar选中字体大小
selectedFontSize: 22.0,
运行效果
本地资源文件
这里主要是学习Android
的资源配置,下面图中的label
用于展示工程名,icon
展示项目图标,ic.lanucher
不用添加.png
后缀
Android
里面的图片资源没有@2x
、@3x
、@4x
的概念,安卓里面是mipmap-hdpi
、mipmap-xhdpi
等类型。
其中xhdpi
等价于iOS中的@2x
图片资源,
xxhdpi
等价于@3x
,
xxxhdpi
等价于@4x
,
mdpi
等价于@1.5x
,
hdpi
等价于@1.0x
,
v21
等价于@0.75x
安卓icon图片引用
下面把AppIcon60x60@2x.png
资源放入mipmap-xhdpi
目录下,注意图片资源不能使用驼峰命名
,这里改成了app_icon.png
,而且图片资源不能拖入目录
,需要复制粘贴
到目录
安卓启动图片引用
安卓启动图片在launch_background.xml
文件中配置,需要把<item> <bitmap android:gravity="center" android:src="@mipmap/launch_image" /> </item>
注释放开,推荐把启动图片放入-hdpi
目录下,不需要添加.png
后缀
项目图片资源引用
-
把图片资源放入
flutter导入图片资源images
目录,直接把目录粘贴到flutter项目中
-
pubspec.yaml
文件中配置,该文件不止可以配置图片资源
,引入的三方库
也在这里配置。下面三行注释放开
注意⚠️:注释放开之后,assets
一定要与上面uses-material-design: true
左对齐,pubspec.yaml
文件对格式要求很严格
-
flutter
工程使用图片资源
BottomNavigationBarItem(
// 默认图标
icon: Image(
height: 20,
width: 20,
image: AssetImage('images/badge.png')
),
// 选中图标
activeIcon: Image(
height: 20,
width: 20,
image: AssetImage('images/badgeSelect.png')
),
label: '微信'),
解决 Gradle 卡住问题
那么在首次运行的时候, 你会发现卡在如下的地方了, 原因是Gradle
的Maven
仓库在国外......然后你就懂了.
Running Gradle task 'assembleDebug'
解决它比较简单的操作就是镜像
, 配置如下:
- 修改项目下的
build.gradle
文件
- 文件路径:
项目 -> Android -> build.gradle
- 修改内容: 找到
buildscript
和allprojects
, 将里边google()
和jcenter()
(新版本是 mavenCentral()) 注释掉, 添加阿里云的镜像
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
image.png
- 修改
flutter
安装目录中的flutter.gradle
文件
- 文件路径:
~/flutter/packages/flutter_tools/gradle/flutter.gradle
- 修改内容:
buildscript
加入阿里镜像
buildscript {
repositories {
//google()
//mavenCentral()
maven { url 'https://maven.aliyun.com/repository/google' }
maven { url 'https://maven.aliyun.com/repository/jcenter' }
maven { url 'http://maven.aliyun.com/nexus/content/groups/public' }
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.0'
}
}
网友评论