Is there any case possible using StreamBuilder for other widgets other than ListView and GridView...?
Let's say ChoiceChip? Why ChoiceChip doesn't have builder?
Yes. we can use any other widget with Stream
see official docs
StreamBuilder(
stream: bloc.allMovies,
builder: (context, AsyncSnapshot<ItemModel> snapshot) {
if (snapshot.hasData) {
return Text("data incoming");
} else if (snapshot.hasError) {
return Text(snapshot.error.toString());
}
return Center(child: CircularProgressIndicator());
},
)
Related
I have a little problem here where i have logged in with Google Auth using Firebase but everytime i tried to restart the app i expect the app will show the HomePage() without any problem, but i found that before it return, the app had like a bit seconds in LoginPage() before displaying HomePage(), is there any way to make it seamlessly
class AuthService extends StatelessWidget {
const AuthService({super.key});
#override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: false,
body: StreamBuilder(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
if (snapshot.hasData) {
return HomePage();
} else {
return LoginPage();
}
},
),
);
}
}
It is happening because for snapshot to reach snapshot.hasData state it takes time, and meanwhile else part is executed which is LoginPage().
How to overcome this?
Try to wrap within snapshot.connectionState == ConnectionState.active which means once stream is connected then check the condition else return CircularProgressIndicator
Code:
StreamBuilder(
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
return HomePage();
} else {
return LoginPage();
}
}
return const CircularProgressIndicator();
},
);
FutureBuilder examples in Flutter where it return a widget called CircularProgressIndicator or any other widget that acts as a placeholder during the waiting time of asynchronous call. I was wondering, what will happen to the CircularProgressIndicator widget after the FutureBuilder is done with it's async and "replaced" with another widget. Is it going to be disposed or destroyed?
Here's an example.
FutureBuilder<String>(
future: _value,
builder: (
BuildContext context,
AsyncSnapshot<String> snapshot,
) {
print(snapshot.connectionState);
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasError) {
return const Text('Error');
} else if (snapshot.hasData) {
return Text(snapshot.data);
} else {
return const Text('Empty data');
}
} else {
return Text('State: ${snapshot.connectionState}');
}
},
)
I just want to check the status of that placeholder widget.
I want to compound firestore datas. Which widget is useful for multiple data?
For instance, i have user datas and user post's datas. I want to show them in the same Card Widget, but their snapshots are different. How can i compound them ?
I write just like this, but it shows just 1 snapshot, i want to both futurebuilder and streambuilder snapshots:
note: i can't use user datas, in below it has final dataUser = snapshotUser.data;
but i can't use it, it gives an error
class HomePageBodyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) => StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collectionGroup('Posts').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView(
children: snapshot.data.docs.map((DocumentSnapshot docPost) {
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('Users')
.doc(docPost.reference.parent.parent.id)
.get(),
builder: (context, snapshotUser) {
if (!snapshotUser.hasData) {
return Center(child: CircularProgressIndicator());
}
return homePageCard(context, dataPost: docPost, dataUser: snapshotUser.data);
},
);
}).toList());
});
}
i solved it, like this:
class HomePageBodyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) => StreamBuilder<QuerySnapshot>(
stream: FirebaseFirestore.instance.collectionGroup('Posts').snapshots(),
builder: (context, AsyncSnapshot<QuerySnapshot> snapshot) {
if (snapshot.hasError) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (!snapshot.hasData) {
return Center(child: CircularProgressIndicator());
}
return ListView.builder(
itemCount: snapshot.data.docs.length,
itemBuilder: (context, index) {
final dataPost = snapshot.data.docs[index];
return FutureBuilder(
future: FirebaseFirestore.instance
.collection('Users')
.doc(dataPost.reference.parent.parent.id)
.get(),
builder: (context, snapshotUser) {
final dataUser = snapshotUser.data;
if (!snapshotUser.hasData) {
return Center(child: CircularProgressIndicator());
}
return homePageCard(context,
dataPost: dataPost, dataUser: dataUser);
},
);
});
});
}
Here's the code.
Widget build(BuildContext context) {
return StreamBuilder<List<Widget>>(
stream: _getMealsViewWidgets(weekNum),
builder: (BuildContext context, AsyncSnapshot<List<Widget>> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
if (snapshot.error != null) {
return Center(child: Text('Error occurred.'));
}
if (snapshot.connectionState == ConnectionState.done) {
return PageView(children: snapshot.data, controller: _pageController);
}
return Center(child: CircularProgressIndicator());
});
}
The PageView has fix 7 pages. I'd like to jump after a refresh to a specific page. The problem is because the PageView is a return of a StreamBuilder I can't call the pagecontroller.jumpPage method after the refresh. How can I jump to a specific page after return?
Have you tried using
WidgetsBinding.instance.addPostFrameCallback((_) {
// executes after build
})
?
Since you can only return widgets in FutureBuilder I was wondering if there is a way to extract data from those widgets to modify it?
For example, is there a way to get to the "snapshot.data.value" here?
if (snapshot.hasData) {
return Text("${snapshot.data.value}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
Here is my parent widget from which im trying to get snapshot.data.value:
Container(
child: FirstWidget(),
),
Container(
child: SecondWidget(),
),
Here is my child widget that returns following FutureBuilder:
#override
Widget build(BuildContext context) {
return FutureBuilder<Api>(
future: _apivalue,
builder: (context, snapshot) {
if (snapshot.hasData) {
Test(er: snapshot.data.er);
return Text("${snapshot.data.value}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return Text('');
},
);
}
}
Question is not clear but what i understand from your question is that you want to use the FutureBuilder data out side the widget. You can do that by storing the data inside a variable
var data; // Defined inside the state of widget as a local variable
if (snapshot.hasData) {
data = snapshot.data;
return Text("${snapshot.data.value}");
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}