问题描述
希望大家今天过得不错。我还有另一个过去几天来一直困扰的问题。我试图将这些数据上传到我的Firestore实例,但是我的发布按钮似乎从未触发过。我试图从它调用的方法中打印一条语句,但是我似乎也无法使它起作用。我正在尝试创建一个社交媒体应用,我们将不胜感激。
我的主要目标是让发布按钮在upload.dart中执行。
我还包括了home.dart,因为这两个类在性能上是相互联系的。
upload.dart
import 'dart:io';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:Flutter/material.dart';
import 'package:Flutter_svg/Flutter_svg.dart';
import 'package:Fluttermedia/models/user.dart';
import 'package:Fluttermedia/pages/home.dart';
import 'package:Fluttermedia/widgets/progress.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
import 'package:image/image.dart' as Im;
import 'package:uuid/uuid.dart';
class Upload extends StatefulWidget {
final User currentUser;
Upload({this.currentUser});
@override
_UploadState createState() => _UploadState();
}
class _UploadState extends State<Upload> {
TextEditingController locationController = TextEditingController();
TextEditingController captionController = TextEditingController();
File file;
bool isuploading = false;
String postId = Uuid().v4();
handleChooseFromgallery() async{
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
this.file = file;
});
}
handleTakePhoto() async {
Navigator.pop(context);
File file = await ImagePicker.pickImage(source: ImageSource.camera,maxHeight: 675,maxWidth: 960);
setState(() {
this.file = file;
});
}
selectimage(parentContext){
return showDialog(
context: parentContext,builder: (context) {
return simpledialog(
title: Text("Create Post"),children: <Widget>[
simpledialogOption(
child: Text("Photo With Camera"),onpressed: handleTakePhoto,),simpledialogOption(
child: Text("Image from gallery"),onpressed: handleChooseFromgallery,simpledialogOption(
child: Text("Cancel"),onpressed: () => Navigator.pop(context),],);
}
);
}
Container buildSplashScreen(){
return Container(
color: Theme.of(context).accentColor.withOpacity(0.6),child: Column(
mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[
SvgPicture.asset('assets/images/upload.svg',height: 260.0,Padding(
padding: EdgeInsets.only(top:20.0),child: RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8.0),child: Text(
"Upload Image",style: TextStyle(
color: Colors.white,fontSize: 22.0,color: Colors.deepOrange,onpressed: () => selectimage(context),)
],);
}
clearImage(){
setState(() {
file = null;
});
}
//This compresses images for firebase
compressImage() async{
final tempDir = await getTemporaryDirectory();
final path = tempDir.path;
Im.Image imageFile = Im.decodeImage(file.readAsBytesSync());
final compressedImageFile = File('$path/img_$postId.jpg')..writeAsBytesSync(Im.encodeJpg(imageFile,quality: 85));
setState(() {
file = compressedImageFile;
});
}
Future<String> uploadImage(imageFile) async{
StorageUploadTask uploadTask = storageRef.child("post_$postId.jpg").putFile(imageFile);
StorageTaskSnapshot storageSnap = await uploadTask.onComplete;
String downloadUrl = await storageSnap.ref.getDownloadURL();
return downloadUrl;
}
//upload new info to firestore that creates a new collection
createPostInFirestore({String mediaUrl,String location,String description}){
postsRef.document(widget.currentUser.id)
.collection("userPosts")
.document(postId)
.setData({
"postId": postId,"ownerId": widget.currentUser.id,"username": widget.currentUser.username,"mediaUrl": mediaUrl,"description": description,"location": location,"timestamp": timeStamp,"likes":{}
});
}
//Getting the info from the caption,location and pic
handleSubmit() async{
setState(() {
isuploading = true;
});
await compressImage();
String mediaUrl = await uploadImage(file);
createPostInFirestore(
mediaUrl: mediaUrl,location: locationController.text,description: captionController.text,);
captionController.clear();
locationController.clear();
setState(() {
file = null;
isuploading = false;
});
}
Scaffold buildUploadForm(){
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.white70,leading: IconButton(
icon: Icon(Icons.arrow_back,color: Colors.black,onpressed: clearImage,title: Text(
"Caption Post",style: TextStyle(color: Colors.black),actions: <Widget>[
FlatButton(
onpressed: () => isuploading ? null : () => handleSubmit(),child: Text(
"Post",style: TextStyle(
color: Colors.blueAccent,fontWeight: FontWeight.bold,fontSize: 20.0,body: ListView(
children: <Widget>[
isuploading ? linearProgress(context):Text(""),Container(
height: 220.0,width: MediaQuery.of(context).size.width*0.8,child: Center(
child: AspectRatio(
aspectRatio: 16/9,child: Container(
decoration: Boxdecoration(
image: decorationImage(
fit: BoxFit.cover,image: FileImage(file),)
),Padding(
padding: EdgeInsets.only(top:10),ListTile(
leading: CircleAvatar(
backgroundImage: CachednetworkImageProvider(widget.currentUser.photoUrl),title: Container(
width: 250.0,child: TextField(
controller: captionController,decoration: Inputdecoration(
hintText: "Write a Caption...",border: InputBorder.none,Divider(),ListTile(
leading: Icon(Icons.pin_drop,color: Colors.orange,size: 35.0),child: TextField(
controller: locationController,decoration: Inputdecoration(
hintText: "Where was this photo taken",Container(
width: 200.0,height: 100.0,alignment: Alignment.center,child: RaisedButton.icon(
label: Text(
"Use Current Location",style: TextStyle(color: Colors.white),shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(30.0),color: Colors.blue,onpressed: () => print("Get user location"),icon: Icon(
Icons.my_location,color: Colors.white,);
}
@override
Widget build(BuildContext context) {
return file == null ? buildSplashScreen() : buildUploadForm();
}
}
home.dart
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_storage/firebase_storage.dart';
import 'package:Flutter/cupertino.dart';
import 'package:Flutter/material.dart';
import 'package:Fluttermedia/models/user.dart';
import 'package:Fluttermedia/pages/activity_Feed.dart';
import 'package:Fluttermedia/pages/create_account.dart';
import 'package:Fluttermedia/pages/profile.dart';
import 'package:Fluttermedia/pages/search.dart';
import 'package:Fluttermedia/pages/upload.dart';
import 'package:google_sign_in/google_sign_in.dart';
final GoogleSignIn googleSignIn = GoogleSignIn();
final StorageReference storageRef = FirebaseStorage.instance.ref();
final usersRef = Firestore.instance.collection('users');
final postsRef = Firestore.instance.collection('posts');
final DateTime timeStamp = DateTime.Now();
User currentUser;
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
bool isAuth = false;
PageController pageController;
int pageIndex = 0;
@override
void initState() {
super.initState();
pageController = PageController();
// Detects if user signs in
googleSignIn.onCurrentUserChanged.listen((account) {
handleSignIn(account);
},onError: (err){
print('Error sigining in: $err');
});
//Reauthenticate user when app is opened
googleSignIn.signInSilently(suppressErrors: false)
.then((account) =>
handleSignIn(account)).catchError((err){
print('Error signing in on retry: $err');
});
}
@override
Widget build(BuildContext context) {
return isAuth ? buildAuthScreen() : buildUnAuthScreen();
}
@override
void dispose(){
pageController.dispose();
super.dispose();
}
//Helper Functions
//The sign in section of the code
handleSignIn(GoogleSignInAccount account){
if(account != null){
createuserInFirestore();
setState(() {
isAuth = true;
});
}else{
setState(() {
isAuth = false;
});
}
}
login(){
googleSignIn.signIn();
}
logout(){
googleSignIn.signOut();
}
onPageChanged(int pageIndex){
setState(() {
this.pageIndex = pageIndex;
});
}
createuserInFirestore() async{
// 1) Check if user exists in users collection in database (According to id)
final GoogleSignInAccount user = googleSignIn.currentUser;
DocumentSnapshot doc = await usersRef.document(user.id).get();
if(!doc.exists){
// 2) If the user doesn't exist,take them to create account page
final username = await Navigator.push(context,MaterialPageRoute(builder: (context) => CreateAccount()));
// 3) get username from create account,use it to make new user document in users collection
usersRef.document(user.id).setData({
"id":user.id,"username":username,"photoUrl": user.photoUrl,"email":user.email,"displayName": user.displayName,"bio":"","timeStamp": timeStamp,});
doc = await usersRef.document(user.id).get();
}
currentUser = User.fromDocument(doc);
//print(currentUser);
//print(currentUser.username);
}
onTap(int pageIndex){
//This what you would use to animate in between the different screens
pageController.animatetoPage(
pageIndex,duration: Duration(milliseconds: 300),curve: Curves.easeInOut
);
}
//UI Code
Widget buildAuthScreen() {
return Scaffold(
body: PageView(
children: <Widget>[
//Timeline(),RaisedButton(
child: Text('logout'),onpressed: logout,ActivityFeed(),Upload(currentUser: currentUser),Search(),Profile(),controller: pageController,onPageChanged: onPageChanged,physics: NeverScrollableScrollPhysics(),bottomNavigationBar: CupertinoTabBar(
currentIndex: pageIndex,onTap: onTap,activeColor: Theme.of(context).primaryColor,items: [
BottomNavigationBarItem(icon: Icon(Icons.whatshot),BottomNavigationBarItem(icon: Icon(Icons.notifications_active),BottomNavigationBarItem(icon: Icon(Icons.photo_camera,size: 34.0,BottomNavigationBarItem(icon: Icon(Icons.search),BottomNavigationBarItem(icon: Icon(Icons.account_circle),);
/*return RaisedButton(
child: Text('logout'),);*/
}
Scaffold buildUnAuthScreen() {
return Scaffold(
body: Container(
width: MediaQuery.of(context).size.width,height: MediaQuery.of(context).size.height,decoration: Boxdecoration(
gradient: LinearGradient(
begin: Alignment.topRight,end: Alignment.bottomLeft,colors: [
Theme.of(context).primaryColor,Theme.of(context).accentColor,]
)
),child: Column(
mainAxisAlignment: MainAxisAlignment.center,crossAxisAlignment: CrossAxisAlignment.center,children: <Widget>[
Text('FlutterMedia',style: TextStyle(
fontFamily: "Signatra",fontSize: 90.0,color: Colors.white
),GestureDetector(
onTap:() => login(),child: Container(
width: 260,height: 60,decoration: Boxdecoration(
image: decorationImage(
image: Assetimage('assets/images/google_signin_button.png'),fit: BoxFit.cover,)
],);
}
}
解决方法
onPressed: () => isUploading ? null : () => handleSubmit(),
好吧,这是您的问题。您本应具有一个三级条件,当onPressed
为假时,会使handleSubmit
调用isUploading
。相反,您已经将onPressed
做成了一个返回函数的函数。
为了更清楚地说明这一点,让我们将此函数分解为适当的非lambda函数和if / else块:
onPressed: () {
if (isUploading) {
return null;
} else {
return () {
handleUpload();
}
}
}
因此请考虑按下按钮时会发生什么。它调用外部函数,该函数检查isUploading
。如果为true,则该函数返回null;如果为false,则返回另一个函数,如果调用该函数,则调用handleUpload
。因此,这种播放方式是onPressed
永远不会为null(有时只会返回null),并且永远不会调用handleUpload
(因为返回的内部函数不会再被调用为自身)。
删除外部lambda,它将起作用:
onPressed: isUploading ? null : () => handleSubmit(),