How can I add splash screen I my flutter app? - android

I was going through various articles about adding splash screen to the app . I want to create splash screen through the splash screen package also other methods are welcome but I am not able to figure out where and how to put out the code for adding the splash screen I am a beginner in flutter and dart. I have attached the required code below:-
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
#override
void initState() {
super.initState();
getUserInfo();
}
Future getUserInfo() async {
await getUser();
setState(() {});
print(uid);
}
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Login',
home: (uid!=null && authSignedIn != false) ? FirstScreen() : LoginPage(),
);
}
}
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
bool authSignedIn;
String uid;
String name;
String imageUrl;
Future getUser() async {
// Initialize Firebase
await Firebase.initializeApp();
SharedPreferences prefs = await SharedPreferences.getInstance();
bool authSignedIn = prefs.getBool('auth') ?? false;
final User user = _auth.currentUser;
if (authSignedIn == true) {
if (user != null) {
uid = user.uid;
name = user.displayName;
imageUrl = user.photoURL;
}
}
}
Future<String> signInWithGoogle() async {
// Initialize Firebase
await Firebase.initializeApp();
final GoogleSignInAccount googleSignInAccount = await googleSignIn.signIn();
final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
final UserCredential userCredential = await _auth.signInWithCredential(credential);
final User user = userCredential.user;
if (user != null) {
// Checking if email and name is null
assert(user.uid != null);
assert(user.displayName != null);
assert(user.photoURL != null);
uid = user.uid;
name = user.displayName;
imageUrl = user.photoURL;
assert(!user.isAnonymous);
assert(await user.getIdToken() != null);
final User currentUser = _auth.currentUser;
assert(user.uid == currentUser.uid);
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('auth', true);
return 'Google sign in successful, User UID: ${user.uid}';
}
return null;
}
void signOutGoogle() async {
await googleSignIn.signOut();
await _auth.signOut();
SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setBool('auth', false);
uid = null;
name = null;
imageUrl = null;
print("User signed out of Google account");
}

There are two methods I know about splash screen the native one and the non native :
In this answer I will give you the non native solution without using a plugin :
Splash Screen is a view where you can do all what you want with flutter widgets :
You can create your view then add it in main.dart home: SplashScreen();
->Show that SplashScreen for (3,5 secs) and then do a pushReplacement navigation to your first view :
This an example of Splash Screen :
import 'dart:async';
import 'package:flutter/material.dart';
class SplashPage extends StatefulWidget {
#override
createState() => _SplashPageState();
}
class _SplashPageState extends State<SplashPage> {
#override
void initState() {
super.initState();
Timer(Duration(seconds: 5),
() => Navigator.pushReplacementNamed(context, "TabsRoute"));
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Container(
width: 144,
height: 144,
child: Image.asset("images/logo.png"),
),
),
Center(
child: Container(
child: Text(
"Company Name",
style: TextStyle(
fontSize: 28,
),
),
),
),
],
),
);
}
}
Implementation in main.dart :
import 'package:flutter/material.dart';
import 'package:base_project/pages/TabsPage.dart';
import 'package:base_project/pages/SplashPage.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
routes: {
'TabsRoute':(context)=>TabsPage(),
},
home: SplashPage(),
);
}
}
Full Application Example here on Github : https://github.com/HoussemTN/flutter_base_project

As stated in other comments there are two methods. The native and the non native, but I would recommend the native since the non native takes few split seconds to pop up and takes more if you're using the debug apk. Of course you don't want the user to look at that black screen even for a split second. The method is a little tricky cue you have to go through your config files.
I'll go with an example in one of my projects and I'm only showing the android one because I've never tried the IOS solution.
in your project folder tree you go to
your_project_name/android/app/src/main/res/
the folders inside the rectangular area are your workspace for this operation.
all the things you're going to edit are XML files and you only have to do few touches and you're done.
choose the image you want to see in the splash screen and make sure it's around 100 px give or take so that you can see it if it's too big it will be rendered but you'll see parts. And also make sure the name doesn't contain any special characters or capital letters or spaces just make it simple like splash_screen and don't add the picture format extension like *.png / *.jpeg just the name. Then put it in the drawable folder you have in your project. Then go to drawable-v21 and go to launch_background.xml like in the picture below and uncomment that commented section
You'll make two changes in this file. First change that ic_launcher to your picture/icon name, which in our case is splash_screen and add a line specifying the background color of the screen.
<item android:drawable="#color/teal" />
note: teal here is the name I chose for my color
The final result should look like this:
Now you only have one last thing to do which is defining that color in xml format which is why I mentioned before that we'll use the values folder as well.
Go to your values folder and create a new XML file called colors.xml and put inside it this XML code.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="teal">#009688</color>
</resources>
like this
of course you'll need to change the color name and the color hex value.
And VOILA!
I know this is probably a late answer and and a long one, if it doesn't help you right now maybe it'll help somebody in need in the future.

Related

flutter) The status of the icon can't be changed immediately (Edit)

I made it possible to toggle the heart icon in the post like Instagram.
And I implemented it so that user information is uploaded to the firestore when I toggle the icon.
There is no problem with the 'Like' and 'Unlike' function of 'Like Icon', but there is one other problem.
There is a problem that the color of the icon does not change immediately when toggling the icon in the post. I can check that this icon has changed when I go to a different screen and come back in.
The following is the code for this icon. (I edited this code)
class LikeToggleIcon extends StatefulWidget {
final String postKey;
final PostModel postModel;
const LikeToggleIcon(
{Key key,
this.postKey,
this.postModel,
this.fromSearch,
this.searchResults})
: super(key: key);
#override
State<LikeToggleIcon> createState() => _LikeToggleIconState();
}
class _LikeToggleIconState extends State<LikeToggleIcon> {
// bool _isLiked = false;
#override
Widget build(BuildContext context) {
//get userModel
UserModel userModel =
Provider.of<UserModelState>(context, listen: false).userModel;
return IconButton(
onPressed: () {
// setState(() {
postNetworkRepo.toggleLike(
widget.postModel.postKey, userModel.userKey);
// });
},
icon: Icon(
widget.postModel.numOfLikes.contains(userModel.userKey)
? Icons.favorite_outlined
: Icons.favorite_border_outlined,
size: 27,
color: Colors.redAccent,
),
);
//toggle method
class PostNetworkRepo with Transformers {
Future<void> toggleLike(String postKey, String userKey) async {
final DocumentReference postRef =
Firestore.instance.collection(COLLECTION_POSTS).document(postKey);
final DocumentSnapshot postSnapshot = await postRef.get();
//check Post collection
if (postSnapshot.exists) {
//check already contain userKey
//if no contain upload userKey, else delete userKey (toggle Like/Unlike)
if (postSnapshot.data[KEY_NUMOFLIKES].contains(userKey)) {
postRef.updateData({
KEY_NUMOFLIKES: FieldValue.arrayRemove([userKey])
});
} else {
postRef.updateData({
KEY_NUMOFLIKES: FieldValue.arrayUnion([userKey])
});
}
}
}
}
PostNetworkRepo postNetworkRepo = PostNetworkRepo();
//This is the part of detail post screen.
class DetailScreen extends StatefulWidget {
#override
_DetailScreenState createState() => _DetailScreenState();
}
class _DetailScreenState extends State<DetailScreen> {
#override
Widget build(BuildContext context) {
//get userModel
UserModel userModel =
Provider.of<UserModelState>(context, listen: false).userModel;
return Scaffold(
appBar: AppBar(
title: _postUser(),
actions: [
//toggle likeIcon
LikeToggleIcon(
postKey: widget.postKey,
postModel: widget.postModel,
),
],
),
I tried using setState() on the IconButton(), but the problem was not solved.
can I get help with this problem?
I believe you are using setState() to change value of variable that's inside the Widget and NOT the State of that widget.
You need to have variables that changes the Widget inside the state for it to be updated. Keeping it inside Widget won't change the Icon, unless the whole widget is recreated (like when you change the screen).
(correct me if I'm wrong. Providing full code of the widget could be more useful)

Flutter - Need help on a proper way to use splash screen + Login data with SharedPreferences checking

I am trying to display a Splash Screen with 3 seconds Timer while getting isLoggedIn value from SharedPreferences. The splash screen that I am using is just a Spinner.
The first time the app is installed, it went smoothly with splash screen running for 3 seconds, navigated into LoginPage and I input login credentials. Then the app straight navigated to the next page called /main which has 3 pages inside it (BottomNavigationBar) with /home as its default index.
Problem is: the next time I launch the app without re-installing it, it does not show any splash screen. It straight went into /main page. After that I instantly tried to move to another page by BottomNavigationBar. And then after 3 seconds (which I am sure is because of Timer), the screen automatically reinitiated and moved back into /home.
Here is my splash_screen_page.dart file:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_spinkit/flutter_spinkit.dart';
import 'package:shared_preferences/shared_preferences.dart';
class SplashScreenPage extends StatefulWidget {
const SplashScreenPage({Key? key}) : super(key: key);
#override
State<SplashScreenPage> createState() => _SplashScreenPageState();
}
class _SplashScreenPageState extends State<SplashScreenPage> {
bool isLoggedIn = false;
#override
void initState() {
super.initState();
Timer(Duration(seconds: 3), () {
_navigateUser();
});
}
void _navigateUser() async {
SharedPreferences prefs = await SharedPreferences.getInstance();
isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
if(isLoggedIn){
Navigator.pushReplacementNamed(context, "/main");
}else{
Navigator.pushReplacementNamed(context, "/login");
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: EdgeInsets.all(128),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
children: [
Container(
child:
// Image(image: AssetImage("assets/splashscreen.png")),
const SpinKitFoldingCube(
color: Colors.blue,
size: 50.0,
))
],
)
)
);
}
}
May be it can help
class _SplashScreenPageState extends State<SplashScreenPage> {
bool isLoggedIn = false;
#override
void initState() {
super.initState();
login().then((value) {
if(isLoggedIn){
Navigator.pushReplacementNamed(context, "/main");
}else{
Navigator.pushReplacementNamed(context, "/login");
}
});
login(){
int _jobsRemained = 2;
while (_jobsRemained > 0) {
if (!isLoggedIn){
SharedPreferences prefs = await SharedPreferences.getInstance();
isLoggedIn = prefs.getBool('isLoggedIn') ?? false;
_jobsRemained--;
}
Future.delayed(Duration(seconds: 3)).then((value) => {_jobsRemained--;});
}
}
}

How to store stream data and display new one along with old in a flutter list view?

I'm trying to display a comment stream from Reddit API. I"m using Streambuilder to stream contents as it arrives and displays it as list view thing is I can only view present stream content and this will disappear as new stream contents appear replacing the old ones. If I don't mention item count inside listview.builder prints contents infinitely still new stream appears.
is there a way to display contents along with previous contents in a scrollable fashion and automatically scroll down as a new stream message appears??
Assuming that the comment stream returns individual (and preferably unique) comments one at a time rather than as a list, what you need to do is store the incoming comments in a state object such as a list. When a new comment comes through the stream, you add it to the list and then trigger a widget rebuild.
What you are doing right now is replacing state with each new stream element rather than accumulating them. Using the code you provided, I have edited it to behave as an accumulator instead. Notice the List<Comment> comments = <Comment>[] object added to state. I have also removed the StreamBuilder since that isn't helpful for this use case.
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:draw/draw.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
home: RedditFlutter(),
debugShowCheckedModeBanner: false,
);
}
}
class RedditFlutter extends StatefulWidget {
RedditFlutter({Key key}) : super(key: key);
#override
_RedditFlutterState createState() => _RedditFlutterState();
}
class _RedditFlutterState extends State<RedditFlutter> {
var comments;
ScrollController _scrollController =
new ScrollController(initialScrollOffset: 50.0);
List<Comment> comments = <Comment>[];
StreamSubscription<Comment>? sub;
var msg = '';
Future<void> redditmain() async {
// Create the `Reddit` instance and authenticated
Reddit reddit = await Reddit.createScriptInstance(
clientId: 'clientid',
clientSecret: 'clientsecret',
userAgent: 'useragent',
username: 'username',
password: 'password', // Fake
);
// Listen to comment stream and accumulate new comments into comments list
sub = reddit.subreddit('cricket').stream.comments().listen((comment) {
if (comment != null) {
// Rebuild from state when a new comment is accumulated
setState(() {
comments.add(comment);
})
}
});
}
#override
void initState() {
// TODO: implement initState
redditmain();
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Reddit"),
centerTitle: true,
),
body: Center(
child: Container(
child: ListView.builder(
controller: _scrollController,
itemCount: comments.length,
itemBuilder: (context, index) {
final Comment comment = comments[index];
return Card(
child: ListTile(
leading: Image.asset('assets/criclogo.png'),
title: Text(comment.body),
trailing: Icon(Icons.more_vert),
),
);
},
),
);
),
);
}
#override
void dispose() {
sub?.cancel();
super.dispose();
}
}
Note that I have not tested this code so there may be (trivial) bugs. Still, conceptually, it should be fine.

Get app icons of installed apps in Flutter from device_apps plugin

I was figuring out how to display list of installed apps along with their names & icons. Code works well till displaying app names. Here is the right, working code:
import 'package:flutter/material.dart';
import 'package:device_apps/device_apps.dart';
import 'dart:async';
class FirstScreen extends StatefulWidget{
State<StatefulWidget> createState(){
return _FirstScreen();
}
}
class _FirstScreen extends State<FirstScreen>{
List<Application> apps;
void initState(){
super.initState();
}
Future<void> getApp() async{
List<Application> _apps = await DeviceApps.getInstalledApplications(onlyAppsWithLaunchIntent: true, includeAppIcons: true, includeSystemApps: true);
setState(() {
apps = _apps;
});
}
Widget build(BuildContext context) {
getApp();
return Container(
child: ListView.builder(
itemCount: apps.length,
itemBuilder: (context, index){
return ListTile(
title: Text(apps[index].appName),
);
},
)
);
}
}
but when I display app icon in ListTile by:
trailing: Icon(Image.memory(apps[index].icon))
it gives icon not defined error.
I even tried ApplicationWithIcon class which extends Application class & icon defined in it, but it returned Null Error
instead of writing
List<Application> apps
write
List apps
also, instead of writing
List<Application> _apps = await DeviceApps.getInstalledApplications(onlyAppsWithLaunchIntent: true, includeAppIcons: true, includeSystemApps: true);
write:
List _apps = await DeviceApps.getInstalledApplications(onlyAppsWithLaunchIntent: true, includeAppIcons: true, includeSystemApps: true);
finally, instead of
Icon(Image.memory(apps[index].icon))
write
Image.memory(apps[index] is ApplicationWithIcon ? app.icon : null)
That's because Icon widget receive a Icons widget and you're passing a Images
ej: Icon(Icons.home)
so just pass the image
trailing: Image.memory(apps[index].icon)
Update
you must delete the type and initialize the list:
List apps = [];
In your method delete type too
Future<void> getApp() async{
List _apps = await DeviceApps.getInstalledApplications(onlyAppsWithLaunchIntent: true,
includeAppIcons: true, includeSystemApps: true);
setState(() {
apps = _apps;
});
}

Sign up and signin with google and firebase not redirecting to destined page

Am working on a project that I was suppose to finished by next week latest, but am facing issue of not redirecting to destined page in flutter google and firebase sign up/sign in.
Here's my dependencies version:
google_sign_in: ^4.0.14
cloud_firestore: ^0.12.11
fluttertoast: ^3.1.3
shared_preferences: ^0.4.3
Here's my login code logic.
import 'package:shared_preferences/shared_preferences.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:google_sign_in/google_sign_in.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'home.dart';
class Login extends StatefulWidget {
#override
_LoginState createState() => _LoginState();
}
class _LoginState extends State<Login> {
final GoogleSignIn googleSignIn = new GoogleSignIn();
final FirebaseAuth firebaseAuth = FirebaseAuth.instance;
SharedPreferences preferences;
bool loading = false;
bool isLogedin = false;
#override
void initState() {
super.initState();
issignedIn();
}
void issignedIn() async {
setState(() {
loading = true;
});
preferences = await SharedPreferences.getInstance();
isLogedin = await googleSignIn.isSignedIn();
if (isLogedin) {
Navigator.pushReplacement(
context, MaterialPageRoute(builder: (context) => HomePage()));
}
setState(() {
loading = false;
});
}
Future handleSignIn() async {
preferences = await SharedPreferences.getInstance();
setState(() {
loading = true;
});
GoogleSignInAccount googleUser = await googleSignIn.signIn();
GoogleSignInAuthentication googleSignInAuthentication =
await googleUser.authentication;
AuthCredential credential = GoogleAuthProvider.getCredential(
idToken: googleSignInAuthentication.idToken,
accessToken: googleSignInAuthentication.accessToken);
FirebaseUser firebaseUser =
(await firebaseAuth.signInWithCredential(credential));
if (firebaseUser != null) {
final QuerySnapshot result = await Firestore.instance
.collection("users")
.where("id", isEqualTo: firebaseUser.uid)
.getDocuments();
final List<DocumentSnapshot> documents = result.documents;
if (documents.length == 0) {
//Insert the user to our collection
Firestore.instance
.collection("users")
.document(firebaseUser.uid)
.setData({
"id": firebaseUser.uid,
"username": firebaseUser.displayName,
"email": firebaseUser.email,
"profilePicture": firebaseUser.photoUrl
});
await preferences.setString("id", firebaseUser.uid);
await preferences.setString("username", firebaseUser.displayName);
await preferences.setString("email", firebaseUser.email);
await preferences.setString("photoUrl", firebaseUser.displayName);
} else {
await preferences.setString("id", documents[0]['id']);
await preferences.setString("username", documents[0]['username']);
await preferences.setString("email", documents[0]['email']);
await preferences.setString("photoUrl", documents[0]['photoUrl']);
}
Fluttertoast.showToast(msg: "Logged in successfully");
setState(() {
loading = false;
});
} else {}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: new AppBar(
elevation: 0.0,
backgroundColor: Colors.red,
centerTitle: true,
title: Text(
"Login",
style: TextStyle(fontWeight: FontWeight.bold),
),
),
body: Stack(
children: <Widget>[
Center(
child: FlatButton(
color: Colors.red,
onPressed: () {
handleSignIn();
},
child: Text(
"Sign in/ Sign up with google",
style: TextStyle(color: Colors.white),
),
),
),
Visibility(
visible: loading ?? true,
child: Container(
alignment: Alignment.center,
color: Colors.white.withOpacity(0.9),
child: Center(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.red),
),
),
),
)
],
),
);
}
}
It keeps loading like forever. May be am not doing something right. A help with the code is highly appreciated.
Please, help out.
enter image description here
Just check quickly that the build.gradle file edits were made in the correct file as there are two of them and i've seen that mistake often. Also there is a problem with some android x devices as covered here that could cause this.
1) check the indentation of imports at the head of the page and make sure you have included import 'package:flutter/material.dart';.
2) ~line 50 ish: FirebaseUser firebaseUser =(await firebaseAuth.signInWithCredential(credential));
you may want to try replacing with: FirebaseUser firebaseUser = (await firebaseAuth.signInWithCredential(credential)).user;
3) ... will run a test later if i have time ( ゚ヮ゚)
Later => with the change above, this code does work for me. I loaded it into one of my firebase projects and it logs me in. It does not redirect to home as you have not called issignedIn() in the button flow. You could add it in after Fluttertoast.showToast(msg: "Logged in successfully"); replacing setState((){...}); but i would recommend changing this function to a onAuthStateChange method if you are comfortable using listeners. If you still cant get it working, post the content of you build.gradle files and the pubspec.yaml and any errors from the debug console.
and just as a note: adding try, catch logic or then.error with asynchronous functions is recommended, especially when using networks here. I see people ignore it for prototyping but it can really help with Firebase custom error states
I made this video showing how to get firebase auth setup with flutter. It's a bit of a different code structure than what you posted but I think more flexible if you were interested in refactoring. https://youtu.be/iTYD13w6Duo

Categories

Resources