1. Finstagram
- 24.8.11 created
1.1. 创建项目
localhost:flutter chenchangqing$ flutter create finstagram
Creating project finstagram...
Running "flutter pub get" in finstagram... 4.5s
Wrote 127 files.
All done!
In order to run your application, type:
$ cd finstagram
$ flutter run
Your application code is in finstagram/lib/main.dart.
1.2. 初始化路由
1.2.1. 新建注册页面
新建pages/register_page.dart
:
import 'package:flutter/material.dart';
class RegisterPage extends StatefulWidget {
const RegisterPage({Key? key}) : super(key: key);
@override
State<RegisterPage> createState() => _RegisterPageState();
}
class _RegisterPageState extends State<RegisterPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.red,
),
);
}
}
1.2.2. 新建登录页面
新建pages/login_page.dart
:
import 'package:flutter/material.dart';
class LoginPage extends StatefulWidget {
const LoginPage({Key? key}) : super(key: key);
@override
State<LoginPage> createState() => _LoginPageState();
}
class _LoginPageState extends State<LoginPage> {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Container(
color: Colors.green,
),
);
}
}
1.2.3. 初始化路由
修改main.dart
:
initialRoute: 'login',
routes: {
'register': (context) => RegisterPage(),
'login': (context) => LoginPage()
},
1.3. 登录标题/按钮
1.3.1. 新增属性
login_page.dart
新增属性:
double? _deviceHeight, _deviceWidth;
修改build
方法,初始化_deviceHeight, _deviceWidth
:
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
...
1.3.2. 新增标题/按钮组件
login_page.dart
新增方法:
Widget _titleWidget() {
return const Text(
"Finstagram",
style: TextStyle(
color: Colors.black, fontSize: 25, fontWeight: FontWeight.w500),
);
}
Widget _loginButton() {
return MaterialButton(
onPressed: () {},
minWidth: _deviceWidth! * 0.70,
height: _deviceHeight! * 0.06,
color: Colors.red,
child: const Text(
"Login",
style: TextStyle(
color: Colors.white, fontSize: 25, fontWeight: FontWeight.w600),
),
);
}
修改build
方法:
Container(
padding: EdgeInsets.symmetric(horizontal: _deviceWidth! * 0.05),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [_titleWidget(), _loginButton()],
),
),
)
1.4. 新增Form输入
1.4.1. 增加属性
login_page.dart
增加loginFormKey和
_email、
_password`属性:
final GlobalKey<FormState> _loginFormKey = GlobalKey<FormState>();
String? _email, _password;
1.4.2. 增加邮箱输入
login_page.dart
增加方法_emailTextField
:
Widget _emailTextField() {
return TextFormField(
decoration: const InputDecoration(hintText: "Email..."),
onSaved: (_value) {
setState(() {
_email = _value;
});
},
validator: (_value) {
bool _result = _value!.contains(RegExp(
r"^[a-zA-Z0-9.!#$%&`*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9](?:[a-zA-Z0-9]{0,61}[a-zA-Z0-9])?)*$"));
_result ? null : "Please enter a valid email";
},
);
}
1.4.3. 增加密码输入
login_page.dart
增加方法_passwordTextField
:
Widget _passwordTextField() {
return TextFormField(
obscureText: true,
decoration: const InputDecoration(hintText: "Password..."),
onSaved: (_value) {
setState(() {
_password = _value;
});
},
validator: (_value) => _value!.length > 6
? null
: "Please enter a password greater than 6 characters.",
);
}
1.4.4. 增加Form
login_page.dart
增加方法_loginForm
:
Widget _loginForm() {
return Container(
height: _deviceHeight! * 0.20,
child: Form(
key: _loginFormKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [_emailTextField(), _passwordTextField()],
),
),
);
}
1.4.5. 修改build
children: [_titleWidget(), _loginForm(), _loginButton()],
1.4.6. 当前UI
1.5. 登录事件
1.5.1. 修正邮箱正则
参考:https: //gist.github.com/cgkio/7268045
validator: (_value) {
bool _result = _value!.contains(RegExp(
r"^[_A-Za-z0-9-+]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$"));
return _result ? null : "Please enter a valid email";
}
1.5.2. Form校验
login_page.dart
新增_loginUser
方法:
void _loginUser() {
if (_loginFormKey.currentState!.validate()) {}
}
login_page.dart
修改_loginButton
方法:
onPressed: () {
_loginUser();
}
1.6. 注册按钮
1.6.1. 增加注册手势
login_page.dart
增加_registerPageLink
方法:
Widget _registerPageLink() {
return GestureDetector(
onTap: () => Navigator.pushNamed(context, "register"),
child: const Text(
"Don`t have an account?",
style: TextStyle(
color: Colors.blue, fontSize: 15, fontWeight: FontWeight.w200),
),
);
}
1.6.2. 修改build方法
children: [
_titleWidget(),
_loginForm(),
_loginButton(),
_registerPageLink()
]
1.7. 注册页面标题和按钮
1.7.1. 增加宽高属性
register_page.dart
新增属性:
double? _deviceHeight, _deviceWidth;
1.7.2. 注册标题
register_page.dart
新增方法:
Widget _titleWidget() {
return const Text(
"Finstagram",
style: TextStyle(fontSize: 25, fontWeight: FontWeight.w600),
);
}
1.7.3. 注册按钮
register_page.dart
新增方法:
Widget _registerButton() {
return MaterialButton(
onPressed: () {},
minWidth: _deviceWidth! * 0.50,
height: _deviceHeight! * 0.05,
color: Colors.red,
child: const Text(
"Register",
style: TextStyle(
color: Colors.white, fontSize: 20, fontWeight: FontWeight.w400),
),
);
}
1.7.4. build
register_page.dart
修改build
:
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Scaffold(
body: SafeArea(
child: Container(
padding: EdgeInsets.symmetric(horizontal: _deviceWidth! * 0.05),
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceAround,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [_titleWidget(), _registerButton()],
),
),
),
),
);
}
1.8. 注册表单
1.8.1. 新增GlobalKey
register_page.dart
新增GlobalKey
属性:
final GlobalKey<FormState> _registerFormKey = GlobalKey<FormState>();
1.8.2. 新增name/email/password
register_page.dart
新增_name
、_email
、_password
属性:
String? _name, _email, _password;
1.8.3. 增加form
register_page.dart
新增form:
Widget _registrationForm() {
return Container(
height: _deviceHeight! * 0.30,
child: Form(
key: _registerFormKey,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: [_nameTextField(), _emailTextField(), _passwordTextField()],
),
),
);
}
Widget _nameTextField() {
return TextFormField(
decoration: const InputDecoration(hintText: "Name..."),
validator: (_value) => _value!.length > 0 ? null : "Please enter a name.",
onSaved: (_value) {
setState(() {
_name = _value;
});
},
);
}
Widget _emailTextField() {
return TextFormField(
decoration: const InputDecoration(hintText: "Email..."),
onSaved: (_value) {
setState(() {
_email = _value;
});
},
validator: (_value) {
bool _result = _value!.contains(RegExp(
r"^[_A-Za-z0-9-+]+(.[_A-Za-z0-9-]+)*@[A-Za-z0-9-]+(.[A-Za-z0-9]+)*(.[A-Za-z]{2,})$"));
return _result ? null : "Please enter a valid email";
},
);
}
Widget _passwordTextField() {
return TextFormField(
obscureText: true,
decoration: const InputDecoration(hintText: "Password..."),
onSaved: (_value) {
setState(() {
_password = _value;
});
},
validator: (_value) => _value!.length > 6
? null
: "Please enter a password greater than 6 characters.",
);
}
1.8.4. 修改build
register_page.dart
修改build
:
children: [
_titleWidget(),
_registrationForm(),
_registerButton()
]
1.9. 头像选择
1.9.1. 网络图片地址
1.9.2. 引入file_picker
因为这里使用file_picker
的时候,无法正常运行iOS模拟器,所以先注释掉
#file_picker: "6.0.0"
1.9.3. 增加import和_image属性
register_page.dart
增加import
和_image
属性
import 'dart:io';
// import 'package:file_picker/file_picker.dart';
class _RegisterPageState extends State<RegisterPage> {
...
File? _image;
...
1.9.4. 增加图片组件
register_page.dart
增加_profileImageWidget
方法:
Widget _profileImageWidget() {
var _imageProvider = _image != null
? FileImage(_image!)
: const NetworkImage("https://i.pravatar.cc/300");
return GestureDetector(
onTap: () {
// FilePicker.platform.pickFiles(type: FileType.image).then((_result) {
// setState(() {
// _image = File(_result!.files.first.path!);
// });
// });
},
child: Container(
height: _deviceHeight! * 0.15,
width: _deviceHeight! * 0.15,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover, image: _imageProvider as ImageProvider)),
),
);
}
1.10. 点击注册
1.10.1. 增加注册方法
register_page.dart
增加注册方法:
void _registerUser() {
if (_registerFormKey.currentState!.validate() && _image != null) {
_registerFormKey.currentState!.save();
}
}
1.10.2. 增加点击事件
register_page.dart
修改_registerButton
:
onPressed: () {
_registerUser();
}
1.11. 增加首页
1.11.1. 新增pages/home_page.dart
import 'package:flutter/material.dart';
class HomePage extends StatefulWidget {
const HomePage({Key? key}) : super(key: key);
@override
State<HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Finstagrams"),
actions: [
GestureDetector(
onTap: () {},
child: const Icon(Icons.add_a_photo),
),
Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8.0),
child: GestureDetector(
onTap: () {},
child: const Icon(Icons.logout),
),
)
],
),
);
}
}
1.11.2. 修改main.dart
import 'package:finstagram/pages/home_page.dart';
...
initialRoute: 'home',
routes: {
'register': (context) => RegisterPage(),
'login': (context) => LoginPage(),
'home': (context) => HomePage()
},
home: const Scaffold(),
);
}
}
1.12. 增加Tabbar
1.12.1. 底部Tabbar
home_page.dart
增加_bottomNavigationBar
方法:
Widget _bottomNavigationBar() {
return BottomNavigationBar(
currentIndex: _currentPage,
onTap: (_index) {
setState(() {
_currentPage = _index;
});
},
items: const [
BottomNavigationBarItem(label: 'Feed', icon: Icon(Icons.feed)),
BottomNavigationBarItem(
label: 'Profile', icon: Icon(Icons.account_box))
]);
}
1.12.2. 增加属性
home_page.dart
增加_currentPage
和_pages
:
int _currentPage = 0;
final List<Widget> _pages = [
Container(
color: Colors.green,
),
Container(
color: Colors.blue,
)
];
1.12.3. 修改build方法
home_page.dart
修改build
方法:
Widget build(BuildContext context) {
...
bottomNavigationBar: _bottomNavigationBar(),
body: _pages[_currentPage],
);
}
1.12.4. 当前UI
1.13. 增加FeedPage和ProfilePage
1.13.1. 增加FeedPage
新增pages/feed_page.dart
:
import 'package:flutter/material.dart';
class FeedPage extends StatefulWidget {
const FeedPage({Key? key}) : super(key: key);
@override
State<FeedPage> createState() => _FeedPageState();
}
class _FeedPageState extends State<FeedPage> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.purple,
);
}
}
1.13.2. 增加ProfilePage
新增pages/profile_page.dart
:
import 'package:flutter/material.dart';
class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key);
@override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
@override
Widget build(BuildContext context) {
return Container(
color: Colors.orange,
);
}
}
1.13.3. 修改HomePage
import 'package:finstagram/pages/feed_page.dart';
import 'package:finstagram/pages/profile_page.dart';
...
final List<Widget> _pages = [FeedPage(), ProfilePage()];
...
1.14. 创建firebase项目
1.14.1. 创建firebase项目
打开 https://firebase.com,进入控制台,创建项目。
1.14.2. 依赖firebase
firebase_core: "1.11.0"
firebase_auth: "3.3.5"
firebase_analytics: "9.0.5"
cloud_firestore: "3.1.6"
firebase_storage: "10.2.5"
get_it: "7.2.0"
1.15. 注册iOS应用
1.15.1. 打开iOS注册
1.15.2. 找到iOS bundleId
打开finder:
双击.workspace
,等到xcode打开:
复制bundleId
:
1.15.3. 填写bundleId
1.15.4. 下载配置文件
1.15.5. 点击下一步
然后,一直点击“下一步”,直到进入控制台。
1.15.6. 修改iOS系统版本
- 检查Podfile中
# platform :ios, '11.0'
,如果低于11,需要修改为10或11。 - 同时需要点击
.workspace
进入iOS项目修改target
和项目的iOS版本。
1.15.7. 运行flutter项目
因为需要下载firebase
sdk,需要长时间等待。
1.15.8. 解决问题
遇到pod install失败问题
- 检查命令行是否可以访问外网
- 检查cocoapods版本是否最新,当前最新是1.15.2
注释后才可以编译:
// FIRTransactionOptions *options = [[FIRTransactionOptions alloc] init]; // options.maxAttempts = maxAttempts.integerValue; // // [firestore runTransactionWithOptions:options // block:transactionRunBlock // completion:transactionCompleteBlock];
1.16. 新增FirebaseService
1.16.1. 新建services/firebase_service.dart:
// import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:firebase_auth/firebase_auth.dart';
// import 'package:firebase_storage/firebase_storage.dart';
class FirebaseService {
// FirebaseAuth _auth = FirebaseAuth.instance;
// FirebaseStorage _storage = FirebaseStorage.instance;
// FirebaseFirestore _db = FirebaseFirestore.instance;
FirebaseService();
}
由于依赖存在问题,暂时先注释。
1.16.2. 修改main.dart:
import 'package:finstagram/services/firebase_service.dart';
...
// import 'package:firebase_core/firebase_core.dart';
import 'package:get_it/get_it.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
// await Firebase.initializeApp();
GetIt.instance.registerSingleton<FirebaseService>(FirebaseService());
runApp(const MyApp());
}
1.17. 登录
1.17.1. 新增FirebaseService
新增services/firebase_service.dart
,真实实现一注释,firebase集成有问题。
// import 'package:cloud_firestore/cloud_firestore.dart';
// import 'package:firebase_auth/firebase_auth.dart';
// import 'package:firebase_storage/firebase_storage.dart';
final String USER_COLLECTION = 'users';
class FirebaseService {
// FirebaseAuth _auth = FirebaseAuth.instance;
// FirebaseStorage _storage = FirebaseStorage.instance;
// FirebaseFirestore _db = FirebaseFirestore.instance;
Map? currentUser;
FirebaseService();
// Future<bool> loginUser(
// {required String email, required String password}) async {
// try {
// UserCredential _userCredential = await _auth.signInWithEmailAndPassword(
// email: email, password: password);
// if (_userCredential.user != null) {
// currentUser = await getUserData(uid: _userCredential.user!.uid);
// return true;
// } else {
// return false;
// }
// } catch (e) {
// print(e);
// return false;
// }
// }
// Future<Map> getUserData({required String uid}) async {
// DocumentSnapshot _doc =
// await _db.collection(USER_COLLECTION).doc(uid).get();
// return _doc.data() as Map;
// }
Future<bool> loginUser(
{required String email, required String password}) async {
return Future.delayed(const Duration(seconds: 1), () {
return true;
});
}
Future<Map> getUserData({required String uid}) async {
return Future.delayed(const Duration(seconds: 1), () {
return {"": ""};
});
}
}
1.17.2. 修改login_page.dart,新增import:
import 'package:finstagram/services/firebase_service.dart';
...
import 'package:get_it/get_it.dart';
1.17.3. 修改login_Page.dart,增加_firebaseService属性:
FirebaseService? _firebaseService;
...
@override
void initState() {
super.initState();
_firebaseService = GetIt.instance.get<FirebaseService>();
}
1.17.4. 修改login_Page.dart,_loginUser:
void _loginUser() async {
if (_loginFormKey.currentState!.validate()) {
_loginFormKey.currentState!.save();
bool _result = await _firebaseService!
.loginUser(email: _email!, password: _password!);
if (_result) Navigator.popAndPushNamed(context, "home");
}
}
1.17.5. 修改main.dart
initialRoute: 'login',
1.18. 注册
1.18.1. 新增注册方法
firebase_service.dart
新增registerUser
方法:
// import 'package:path/path.dart' as p;
// Future<bool> registerUser(
// {required String name,
// required String email,
// required String password,
// required File image}) async {
// try {
// UserCredential _userCredential = await _auth
// .createUserWithEmailAndPassword(email: email, password: password);
// String _userId = _userCredential.user!.uid;
// String _fileName = Timestamp.now().millisecondsSinceEpoch.toString() +
// p.extension(image.path);
// UploadTask _task =
// _storage.ref('images/$_userId/$_fileName').putFile(image);
// return _task.then((_snapshot) async {
// String _downloadURL = await _snapshot.ref.getDownloadURL();
// await _db
// .collection(USER_COLLECTION)
// .doc(_userId)
// .set({"name": name, "email": email, "image": _downloadURL});
// });
// } catch (e) {
// print(e);
// return false;
// }
// }
Future<bool> registerUser(
{required String name,
required String email,
required String password}) async {
return Future.delayed(const Duration(seconds: 1), () {
return true;
});
}
1.18.2. 增加FirebaseService属性
register_page.dart
新增_firebaseService
:
import 'package:finstagram/services/firebase_service.dart';
...
import 'package:get_it/get_it.dart';
FirebaseService? _firebaseService;
@override
void initState() {
super.initState();
_firebaseService = GetIt.instance.get<FirebaseService>();
}
register_page.dart
修改_registerUser
:
void _registerUser() async {
// if (_registerFormKey.currentState!.validate() && _image != null) {
if (_registerFormKey.currentState!.validate()) {
// 图片选择暂时忽略
_registerFormKey.currentState!.save();
var _result = await _firebaseService!
.registerUser(name: _name!, email: _email!, password: _password!);
if (_result) Navigator.pop(context);
}
}
1.19. 发布图片
1.19.1. 增加上传图片方法
修改firebase_service.dart
,新增postImage
方法:
import 'dart:io';
...
final String POSTS_COLLECTION = 'posts';
...
// Future<bool> postImage(File _image) async {
// try {
// String _userId = _auth.currentUser!.uid;
// String _fileName = Timestamp.now().millisecondsSinceEpoch.toString() +
// p.extension(_image.path);
// UploadTask _task =
// _storage.ref('images/$_userId/$_fileName').putFile(_image);
// return _task.then((_snapshot) async {
// String _downloadURL = await _snapshot.ref.getDownloadURL();
// await _db.collection(POSTS_COLLECTION).add({
// "useId": _userId,
// "timestamp": Timestamp.now(),
// "image": _downloadURL
// });
// return true;
// });
// } catch (e) {
// print(e);
// return false;
// }
// }
Future<bool> postImage(File _image) async {
return Future.delayed(const Duration(seconds: 1), () {
return true;
});
}
1.19.2. 增加FirebaseService属性
修改home_page.dart
增加_firebaseService
属性:
// import 'package:file_picker/file_picker.dart';
...
import 'package:finstagram/services/firebase_service.dart';
...
import 'package:get_it/get_it.dart';
FirebaseService? _firebaseService;
@override
void initState() {
super.initState();
_firebaseService = GetIt.instance.get<FirebaseService>();
}
1.19.3. 调用发布图片
修改home_page.dart
新增_postImage
:
// void _postImage() async {
// FilePickerResult? _result =
// await FilePicker.platform.pickFiles(type: FileType.image);
// File _image = File(_result!.files.first.path!);
// await _firebaseService!.postImage(_image);
// }
void _postImage() async {}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Finstagrams"),
actions: [
GestureDetector(
onTap: () {
_postImage();// add
},
...
}
1.20. 照片流
1.20.1. 查询照片流
修改firebase_service.dart
,新增getLastestPosts
方法:
// Stream<QuerySnapshot> getLastestPosts() {
// return _db
// .collection(POSTS_COLLECTION)
// .orderBy('timestamp', descending: true)
// .snapshots();
// }
Stream<List<String>> getLastestPosts() {
// https://blog.csdn.net/mqdxiaoxiao/article/details/102570225
return Stream<List<String>>.fromFutures([
Future.delayed(Duration(seconds: 1), () {
return [
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg"
];
})
]);
}
1.20.2. 显示照片流
修改feed_page.dart
:
// import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:finstagram/services/firebase_service.dart';
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
class FeedPage extends StatefulWidget {
const FeedPage({Key? key}) : super(key: key);
@override
State<FeedPage> createState() => _FeedPageState();
}
class _FeedPageState extends State<FeedPage> {
double? _deviceHeight, _deviceWidth;
FirebaseService? _firebaseService;
@override
void initState() {
super.initState();
_firebaseService = GetIt.instance.get<FirebaseService>();
}
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Container(
height: _deviceHeight!,
width: _deviceWidth!,
child: _postsListView(),
);
}
// Widget _postsListView() {
// return StreamBuilder<QuerySnapshot>(
// stream: _firebaseService!.getLastestPosts(),
// builder: (BuildContext _context, AsyncSnapshot _snapshot) {
// if (_snapshot.hasData) {
// List _posts = _snapshot.data!.docs.map((e) => e.data()).toList();
// print(_posts);
// return ListView.builder(
// itemCount: _posts.length,
// itemBuilder: (BuildContext context, int index) {
// Map _post = _posts[index];
// return Container(
// height: _deviceHeight! * 0.30,
// margin: EdgeInsets.symmetric(
// vertical: _deviceHeight! * 0.01,
// horizontal: _deviceWidth! * 0.05),
// decoration: BoxDecoration(
// image: DecorationImage(
// fit: BoxFit.cover,
// image: NetworkImage(_post["image"]))),
// );
// });
// } else {
// return const Center(
// child: CircularProgressIndicator(),
// );
// }
// },
// );
// }
Widget _postsListView() {
return StreamBuilder<List<String>>(
stream: _firebaseService!.getLastestPosts(),
builder: (BuildContext _context, AsyncSnapshot _snapshot) {
if (_snapshot.hasData) {
print(_snapshot.data);
List<String> _posts = _snapshot.data!;
print(_posts);
return ListView.builder(
itemCount: _posts.length,
itemBuilder: (BuildContext context, int index) {
return Container(
height: _deviceHeight! * 0.30,
margin: EdgeInsets.symmetric(
vertical: _deviceHeight! * 0.01,
horizontal: _deviceWidth! * 0.05),
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_posts[index]))),
);
});
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
);
}
}
1.21. 显示头像
1.21.1. 修改firebase_service.dart,头像写死下
// Map? currentUser
Map? currentUser = {
"image":
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg"
};
1.21.2. 修改profile_page.dart:
import 'package:flutter/material.dart';
import 'package:get_it/get_it.dart';
import '../services/firebase_service.dart';
class ProfilePage extends StatefulWidget {
const ProfilePage({Key? key}) : super(key: key);
@override
State<ProfilePage> createState() => _ProfilePageState();
}
class _ProfilePageState extends State<ProfilePage> {
double? _deviceHeight, _deviceWidth;
FirebaseService? _firebaseService;
@override
void initState() {
super.initState();
_firebaseService = GetIt.instance.get<FirebaseService>();
}
@override
Widget build(BuildContext context) {
_deviceHeight = MediaQuery.of(context).size.height;
_deviceWidth = MediaQuery.of(context).size.width;
return Container(
padding: EdgeInsets.symmetric(
horizontal: _deviceWidth! * 0.05, vertical: _deviceHeight! * 0.02),
child: Column(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [_profileImage()],
),
);
}
Widget _profileImage() {
return Container(
margin: EdgeInsets.only(bottom: _deviceHeight! * 0.02),
height: _deviceHeight! * 0.15,
width: _deviceHeight! * 0.15,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(100),
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_firebaseService!.currentUser!["image"]))),
);
}
}
1.22. 自己发布的照片
1.22.1. 查询用户发布的照片
修改firebase_service.dart
// Stream<QuerySnapshot> getPostsForUser() {
// String _userID = _auth.currentUser!.uid;
// return _db
// .collection(POSTS_COLLECTION)
// .where('userId', isEqualTo: _userID)
// .snapshots();
// }
Stream<List<String>> getPostsForUser() {
return Stream<List<String>>.fromFutures([
Future.delayed(Duration(seconds: 1), () {
return [
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg",
"https://marketplace.canva.cn/EAGE6DsWb24/1/0/1600w/canva-cFjPThAyvu8.jpg"
];
})
]);
}
1.22.2. 显示用户发布的照片
修改profile_page.dart
:
Widget build(BuildContext context) {
...
children: [_profileImage(), _postsGridView()],
// Widget _postsGridView() {
// return Expanded(
// child: StreamBuilder<QuerySnapshot>(
// stream: _firebaseService!.getPostsForUser(),
// builder: (context, snapshot) {
// if (snapshot.hasData) {
// List _posts = snapshot.data!.docs.map((e) => e.data()).toList();
// return GridView.builder(
// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
// crossAxisCount: 2, mainAxisSpacing: 2, crossAxisSpacing: 2),
// itemCount: _posts.length,
// itemBuilder: (context, index) {
// Map _post = _posts[index];
// return Container(
// decoration: BoxDecoration(
// image: DecorationImage(
// fit: BoxFit.cover,
// image: NetworkImage(_post["image"]))),
// );
// });
// } else {
// return const Center(
// child: CircularProgressIndicator(),
// );
// }
// },
// ));
// }
Widget _postsGridView() {
return Expanded(
child: StreamBuilder<List<String>>(
stream: _firebaseService!.getPostsForUser(),
builder: (context, snapshot) {
if (snapshot.hasData) {
List _posts = snapshot.data!;
return GridView.builder(
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2, mainAxisSpacing: 2, crossAxisSpacing: 2),
itemCount: _posts.length,
itemBuilder: (context, index) {
return Container(
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.cover,
image: NetworkImage(_posts[index]))),
);
});
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
));
}
1.23. 登出
1.23.1. 增加登出方法
修改firebase_service.dart
,增加logout
:
// Future<void> logout() async {
// await _auth.signOut();
// }
Future<void> logout() async {
return Future.delayed(const Duration(seconds: 1), () {});
}
1.23.2. 调用登出方法
修改home_page.dart
:
Widget build(BuildContext context) {
...
onTap: () async {
await _firebaseService!.logout();
Navigator.popAndPushNamed(context, 'login');
}
}
1.24. 源码
https://gitee.com/learnany/flutter/blob/master/finstagram.zip