Related
Subject: PageView and GetX
I'm having trouble detaching the controls on a PageView widget from the HomeView module. I have a GlobalController with its respective GlobalBinding that are instantiated when opening the HomeView. I would like to take the setPage(int page) method to the GlobalController that would eventually make the HomeView's PageView change pages. I don't know how to get PageController from PageView to GlobalController in order to make it work. How should I proceed?
Something Like this?
am using pageview in onboarding
class Onboard{
final headTitle;
final secondarytitle;
final discription;
final pngimage;
Onboardslist(this.headTitle, this.secondarytitle, this.discription, this.pngimage);
}
then for the controller
class OnboardController extends GetxController{
var selectedPagexNumber = 0.obs;
bool get isLastPage => selectedPagexNumber.value == onBoardPages.length -1;
var pageControll = PageController();
forwardAct()
{
if(isLastPage) Get.offNamedUntil(signin, (route)=> false);
else pageControll.nextPage(duration: 300.milliseconds, curve: Curves.ease);
}
List<Onboardslist> onBoardPages =
[
Onboardslist("title",
"short description",
"long description",
imageString),
Onboardslist("title",
"short description",
"long description",
imageString),
Onboardslist("title",
"short description",
"long description",
imageString),
Onboardslist("title",
"short description",
"long description",
imageString)
];
}
then for the view i did was simply like this
class Onboarding extends StatelessWidget {
final yourController= OnboardController();
#override
Widget build(BuildContext context) {
SizeXGet().init(context);
return Scaffold(
backgroundColor: decent_white,
appBar: AppBarCustom(
title: 'Skip',
button: ()=>Get.offNamedUntil(signin,(route)=>false),
),
body: WillPopScope(
onWillPop: () async => false,
child: SafeArea(
child: Stack(
children: [
PageView.builder(
controller: yourController.pageControll,
onPageChanged: yourController.selectedPagexNumber,
itemCount: yourController.onBoardPages.length,
itemBuilder: (context, index)
=>Padding(
padding: const EdgeInsets.only(left: 10,right: 10),
child: Container(
child: SingleChildScrollView(
physics: BouncingScrollPhysics(),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
height: getHeight(150),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.only(left: 20,right: 20),
child: Text(yourController.onBoardPages[index].headTitle,
style: TextStyle(
color: darkish_color,
fontSize: getHeight(20),
fontFamily: 'Metropolis-SemiBold' ,
fontWeight: FontWeight.bold
),),
),
SizedBox(height: 15,),
Padding(
padding: const EdgeInsets.only(left: 50,right: 50),
child: Text(yourController.onBoardPages[index].secondarytitle,
style: TextStyle(
color: not_sopure_black,
fontSize: getHeight(26),
fontFamily: 'Metropolis-Bold' ,
fontWeight: FontWeight.bold
),
),
),
SizedBox(height: 15,),
Padding(
padding: const EdgeInsets.only(left: 40,right: 40),
child: Text(yourController.onBoardPages[index].discription,
style: TextStyle(
color: not_sopure_black,
fontSize: getHeight(15),
fontFamily: 'Metropolis-Regular' ,
),
),
),
],
),
),
SizedBox(height: 15,),
Image.asset(yourController.onBoardPages[index].pngimage),
],
),
),
),
),
),
],
),
),
),
bottomNavigationBar: BottomAppBar(
color: Colors.transparent,
elevation: 0,
child: Container(
height: 75,
width: MediaQuery.of(context).size.width,
child: Padding(
padding: const EdgeInsets.only(left: 25,right:25,),
child: Container(
width: MediaQuery.of(context).size.width,
child: Stack(
children: [
Align(
alignment: Alignment.centerLeft,
child: Container(
child: Row(
children: List.generate(yourController.onBoardPages.length,
(index)=>Obx(()=>
AnimatedContainer(
duration: Duration(milliseconds: 200),
margin: EdgeInsets.only(right: 5),
height: 10,
width: yourController.selectedPagexNumber.value == index ? 20 : 10,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(60),
color: yourController.selectedPagexNumber.value == index
? darkish_color
: not_sopure_black,),
),
)),
),
),
),
Align(
alignment: Alignment.centerRight,
child: Container(
width: 130,
height: 52,
child: RaisedButton(
elevation: 0,
onPressed: yourController.forwardAct,
splashColor: not_sopure_black,
color: darkish_color,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(100)
),
child: Obx(() =>
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(yourController.isLastPage ? 'Next' : 'Next',
style: TextStyle(
color: Colors.white,
fontFamily: 'Metropolis-Semibold',
fontSize: 16,
),
),
],
),
),
),
),
)
],
),
),
),
),
),
);
}
}
i'm new to flutter and now i'm working a project for my university project.
so i i already make an OnboardingScreen, but it cannot go to the previous page, i can make it go the next page with pagecontroller but i cannot make it go to previous page. i actually don't really know how to add the Text('Prev') because i already use align bottom right for the next.
if it isn't clear to you, may this photo helps
i want to make prev in bottom left
i also want to make the onboardingScreen only 1 time, i already search about the sharedpreference but i don't really know how to use it (i do accept any other method, as long my OnboardingScreen only 1 time)
here are the full code for my OnboardingScreen
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:movie_app_3/screens/home_screen.dart';
class Onboarding extends StatefulWidget {
#override
_OnboardingScreen createState() => _OnboardingScreen();
}
class _OnboardingScreen extends State<Onboarding> {
final int _numPages = 3;
final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
List<Widget> _buildPageIndicator() {
List<Widget> list = [];
for (int i = 0; i < _numPages; i++) {
list.add(i == _currentPage ? _indicator(true) : _indicator(false));
}
return list;
}
Widget _indicator(bool isActive) {
return AnimatedContainer(
duration: Duration(milliseconds: 150),
margin: EdgeInsets.symmetric(horizontal: 8.0),
height: 8.0,
width: isActive ? 24.0 : 16.0,
decoration: BoxDecoration(
color: isActive ? Colors.white : Color(0xFF7B51D3),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.1, 0.4, 0.7, 0.9],
colors: [
Colors.black,
Color(0xff112339),
Color(0xff112339),
Colors.black,
],
),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
},
child: Text(
'Skip',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
Container(
height: 600.0,
child: PageView(
physics: ClampingScrollPhysics(),
controller: _pageController,
onPageChanged: (int page) {
setState(() {
_currentPage = page;
});
},
children: <Widget>[
Padding(
padding: EdgeInsets.only(top:70.0,left: 40.0,right: 40.0,),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/Logo.png',
),
height: 120.0,
width: 120.0,
),
),
SizedBox(height: 50.0),
Text(
'Welcome',
style: TextStyle(
color: Colors.white,
fontSize: 21.0,
height: 1.5,
),
),
SizedBox(height: 30.0),
Text(
'Welcome to Moviez, the place where you will spend your time magically',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
height: 1.2,
fontFamily: 'Raleway',
),
),
],
),
),
Padding(
padding: EdgeInsets.only(top:70.0,left: 40.0,right: 40.0,),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/Logo.png',
),
height: 120.0,
width: 120.0,
),
),
SizedBox(height: 50.0),
Text(
'Purpose',
style: TextStyle(
color: Colors.white,
fontSize: 21.0,
height: 1.5,
),
),
SizedBox(height: 30.0),
Text(
'This App is for educational purposes only',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
height: 1.2,
),
),
],
),
),
Padding(
padding: EdgeInsets.only(top:70.0,left: 40.0,right: 40.0,),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Image(
image: AssetImage(
'assets/images/Logo.png',
),
height: 120.0,
width: 120.0,
),
),
SizedBox(height: 50.0),
Text(
'Creator',
style: TextStyle(
color: Colors.white,
fontSize: 21.0,
height: 1.5
),
),
SizedBox(height: 30.0),
Text(
'Adela, Caroline, Cordellya, David, Valentino',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
height: 1.2,
),
),
],
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPageIndicator(),
),
_currentPage != _numPages - 1
? Expanded(
child: Align(
alignment: FractionalOffset.bottomRight,
child: TextButton(
onPressed: () {
_pageController.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
SizedBox(width: 10.0),
Icon(
Icons.arrow_forward,
color: Colors.white,
size: 30.0,
),
],
),
),
),
)
: Text(''),
],
),
),
),
),
bottomSheet: _currentPage == _numPages - 1
? Container(
height: 100.0,
width: double.infinity,
color: Colors.white,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
},
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 30.0),
child: Text(
'Get started',
style: TextStyle(
color: Color(0xFF5B16D0),
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
)
: Text(''),
);
}
}
and here is the code for my main.dart
import 'package:flutter/material.dart';
import 'package:movie_app_3/widget/onboard.dart';
import 'package:shared_preferences/shared_preferences.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: Onboarding(),
);
}
}
You can copy paste run full code below
Question 1 : For Prev button, you can use Row and MainAxisAlignment.spaceBetween
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Align(
alignment: FractionalOffset.bottomLeft,
...
Align(
alignment: FractionalOffset.bottomRight,
...
Question 2: For Onboarding show only once, you can use initialRoute
bool seen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
seen = prefs.getBool("seen") ?? false;
print(seen.toString());
await prefs.setBool("seen", true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
...
initialRoute: seen == false ? "/onboarding" : "/home",
routes: {
'/home': (context) => HomeScreen(),
"/onboarding": (context) => Onboarding(),
},
);
}
}
working demo
full code
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Onboarding extends StatefulWidget {
#override
_OnboardingScreen createState() => _OnboardingScreen();
}
class _OnboardingScreen extends State<Onboarding> {
final int _numPages = 3;
final PageController _pageController = PageController(initialPage: 0);
int _currentPage = 0;
List<Widget> _buildPageIndicator() {
List<Widget> list = [];
for (int i = 0; i < _numPages; i++) {
list.add(i == _currentPage ? _indicator(true) : _indicator(false));
}
return list;
}
Widget _indicator(bool isActive) {
return AnimatedContainer(
duration: Duration(milliseconds: 150),
margin: EdgeInsets.symmetric(horizontal: 8.0),
height: 8.0,
width: isActive ? 24.0 : 16.0,
decoration: BoxDecoration(
color: isActive ? Colors.white : Color(0xFF7B51D3),
borderRadius: BorderRadius.all(Radius.circular(12)),
),
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: AnnotatedRegion<SystemUiOverlayStyle>(
value: SystemUiOverlayStyle.light,
child: Container(
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
stops: [0.1, 0.4, 0.7, 0.9],
colors: [
Colors.black,
Color(0xff112339),
Color(0xff112339),
Colors.black,
],
),
),
child: Padding(
padding: EdgeInsets.symmetric(vertical: 40.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
alignment: Alignment.centerRight,
child: TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
},
child: Text(
'Skip',
style: TextStyle(
color: Colors.white,
fontSize: 20.0,
),
),
),
),
Container(
height: 500.0,
child: PageView(
physics: ClampingScrollPhysics(),
controller: _pageController,
onPageChanged: (int page) {
setState(() {
_currentPage = page;
});
},
children: <Widget>[
Padding(
padding: EdgeInsets.only(
top: 70.0,
left: 40.0,
right: 40.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Image(
image: NetworkImage(
'https://picsum.photos/250?image=9',
),
height: 120.0,
width: 120.0,
),
),
SizedBox(height: 50.0),
Text(
'Welcome',
style: TextStyle(
color: Colors.white,
fontSize: 21.0,
height: 1.5,
),
),
SizedBox(height: 30.0),
Text(
'Welcome to Moviez, the place where you will spend your time magically',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
height: 1.2,
fontFamily: 'Raleway',
),
),
],
),
),
Padding(
padding: EdgeInsets.only(
top: 70.0,
left: 40.0,
right: 40.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Image(
image: NetworkImage(
'https://picsum.photos/250?image=10',
),
height: 120.0,
width: 120.0,
),
),
SizedBox(height: 50.0),
Text(
'Purpose',
style: TextStyle(
color: Colors.white,
fontSize: 21.0,
height: 1.5,
),
),
SizedBox(height: 30.0),
Text(
'This App is for educational purposes only',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
height: 1.2,
),
),
],
),
),
Padding(
padding: EdgeInsets.only(
top: 70.0,
left: 40.0,
right: 40.0,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Center(
child: Image(
image: NetworkImage(
'https://picsum.photos/250?image=11',
),
height: 120.0,
width: 120.0,
),
),
SizedBox(height: 50.0),
Text(
'Creator',
style: TextStyle(
color: Colors.white,
fontSize: 21.0,
height: 1.5),
),
SizedBox(height: 30.0),
Text(
'Adela, Caroline, Cordellya, David, Valentino',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
height: 1.2,
),
),
],
),
),
],
),
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: _buildPageIndicator(),
),
_currentPage != _numPages - 1
? Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Align(
alignment: FractionalOffset.bottomLeft,
child: TextButton(
onPressed: () {
_pageController.previousPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Icon(
Icons.arrow_back,
color: Colors.white,
size: 30.0,
),
SizedBox(width: 10.0),
Text(
'Prev',
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
],
),
),
),
Align(
alignment: FractionalOffset.bottomRight,
child: TextButton(
onPressed: () {
_pageController.nextPage(
duration: Duration(milliseconds: 500),
curve: Curves.ease,
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Text(
'Next',
style: TextStyle(
color: Colors.white,
fontSize: 22.0,
),
),
SizedBox(width: 10.0),
Icon(
Icons.arrow_forward,
color: Colors.white,
size: 30.0,
),
],
),
),
),
],
),
)
: Text(''),
],
),
),
),
),
bottomSheet: _currentPage == _numPages - 1
? Container(
height: 100.0,
width: double.infinity,
color: Colors.white,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => HomeScreen()),
);
},
child: Center(
child: Padding(
padding: EdgeInsets.only(bottom: 30.0),
child: Text(
'Get started',
style: TextStyle(
color: Color(0xFF5B16D0),
fontSize: 20.0,
fontWeight: FontWeight.bold,
),
),
),
),
),
)
: Text(''),
);
}
}
bool seen;
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
SharedPreferences prefs = await SharedPreferences.getInstance();
seen = prefs.getBool("seen") ?? false;
print(seen.toString());
await prefs.setBool("seen", true);
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
initialRoute: seen == false ? "/onboarding" : "/home",
routes: {
'/home': (context) => HomeScreen(),
"/onboarding": (context) => Onboarding(),
},
);
}
}
class HomeScreen extends StatefulWidget {
HomeScreen({Key key}) : super(key: key);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Home screen"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}
I have ListView builder adsList which contains LstTiles adTile contains the Card.
When I press the Card widget I expect an action and to navigate to another screen or just print in console, but nothing happens although I wrapped the card inside GestureDetector.
here is the code
class _AdTileState extends State<AdTile> {
#override
Widget build(BuildContext context) {
return Padding(
padding: EdgeInsets.only(top: 8),
child: GestureDetector(
onTap: (){
print('card pressed');
Navigator.push(context, new MaterialPageRoute(builder: (context) => AdView()));
},
child: Card(
margin: EdgeInsets.fromLTRB(20, 6, 20, 0),
child: ListTile(
trailing: Image.network(widget.adModel.adImage),
title: Text(widget.adModel.adName),
subtitle: Text(widget.adModel.location),
),
),
),
);
}
}
Here is the code inside AdList:
class _AdsListState extends State<AdsList> {
#override
Widget build(BuildContext context) {
final ads = Provider.of<List<AdModel>>(context);
return ListView.builder(
scrollDirection: Axis.vertical,
itemCount:(ads == null) ? 0 : ads.length,
itemBuilder: (context, index){
return
CustomAdTile(adModel: ads[index],);
});
}
}
And here is the code on the Page which show the ListView Builder:
Widget build(BuildContext context) {
return StreamProvider<List<Profile>>.value(
value: DatabaseService().profiles,
child: StreamProvider<List<AdModel>>.value(
value: DatabaseService().ads,
child: Directionality(
textDirection: TextDirection.rtl,
child: Scaffold(
appBar: AppBar(),
body: Column(
children: <Widget>[
Container(),
Row(),
Expanded(
child: AdsList()
),
],
),
Code for CustomAdTile:
class _CustomAdTileState extends State<CustomAdTile> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.adModel.adName,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14.0,
),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
Text(
widget.adModel.location,
style: const TextStyle(fontSize: 10.0),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 1.0)),
Text(
'${widget.adModel.category} views',
style: const TextStyle(fontSize: 10.0),
),
],
),
),
),
const Icon(
Icons.more_vert,
size: 16.0,
),
Container(
height: 80,
width: 80,
decoration: BoxDecoration(
image: DecorationImage(image: NetworkImage(widget.adModel.adImage),
fit: BoxFit.fill),
),
)
],
),
);
}
}
It looks like you are never using AdTile, you are using CustomAdTile. You need to add the onTap inside CustomAdTile.
Here is the updated code for CustomAdTile.
class _CustomAdTileState extends State<CustomAdTile> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.symmetric(vertical: 5.0),
child: InkWell(
///Add onTap here
onTap: () {
print('card pressed');
Navigator.push(
context, new MaterialPageRoute(builder: (context) => AdView()));
},
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Expanded(
flex: 3,
child: Padding(
padding: const EdgeInsets.fromLTRB(0.0, 0.0, 10.0, 0.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
widget.adModel.adName,
style: const TextStyle(
fontWeight: FontWeight.w500,
fontSize: 14.0,
),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 2.0)),
Text(
widget.adModel.location,
style: const TextStyle(fontSize: 10.0),
),
const Padding(padding: EdgeInsets.symmetric(vertical: 1.0)),
Text(
'${widget.adModel.category} views',
style: const TextStyle(fontSize: 10.0),
),
],
),
),
),
const Icon(
Icons.more_vert,
size: 16.0,
),
Container(
height: 80,
width: 80,
decoration: BoxDecoration(
image: DecorationImage(
image: NetworkImage(widget.adModel.adImage),
fit: BoxFit.fill),
),
)
],
),
),
);
}
}
I am a beginner of flutter.
I am developing a flutter app.
this is my flutter app screen.
I want to hide the marked part as blue when I tap the bookmark tab bar.
I have tried several methods, but I could not achieve my goal.
I really need your helps.
I attached my whole code.
import 'package:botanic_flutter/login_page.dart';
import 'package:botanic_flutter/main.dart';
import 'package:botanic_flutter/root_page.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:botanic_flutter/custom_color_scheme.dart';
import 'package:google_sign_in/google_sign_in.dart';
class AccountPage extends StatefulWidget {
final String userUid;
AccountPage(this.userUid);
#override
_AccountPageState createState() => _AccountPageState();
}
class _AccountPageState extends State<AccountPage>
with SingleTickerProviderStateMixin {
final GoogleSignIn _googleSignIn = GoogleSignIn();
final FirebaseAuth _Auth = FirebaseAuth.instance;
FirebaseUser _currentUser;
TabController _controller;
ScrollController _scrollController;
#override
void initState() {
super.initState();
_scrollController = ScrollController();
_controller = TabController(length: 2, vsync: this);
}
#override
void dispose() {
_controller.dispose();
_scrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
bottom: true,
child: DefaultTabController(
length: 2,
child: NestedScrollView(
controller: _scrollController,
headerSliverBuilder: (context, isScrolled) {
return <Widget>[
SliverList(
delegate: SliverChildListDelegate([
_detailedBody()
]),
),
SliverPersistentHeader(
pinned: true,
delegate: TabBarDelegate(
Column(
children: <Widget>[
TabBar(
unselectedLabelColor: Theme.of(context).colorScheme.greyColor,
labelColor: Theme.of(context).colorScheme.mainColor,
controller: _controller,
indicatorColor: Theme.of(context).colorScheme.mainColor,
tabs: [
Container(
height: 80,
padding: EdgeInsets.only(top: 10),
child: Tab(
icon: const Icon(Icons.home,
),
text: 'PLANTS',
),
),
Container(
height: 80,
padding: EdgeInsets.only(top: 10),
child: Tab(
icon: const Icon(Icons.bookmark_border,
),
text: 'BOOKMARK',
),
)
],
),
_bottomButtons(tabindi)
],
),
),
),
];
},
body: SizedBox(
height: MediaQuery.of(context).size.height,
child: TabBarView(
controller: _controller,
children: <Widget>[
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.0,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0),
itemCount: notes.length,
itemBuilder: (context, index) => Card(
child: Image.network(notes[index],
fit: BoxFit.cover,
),
),
),
GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
childAspectRatio: 1.0,
mainAxisSpacing: 1.0,
crossAxisSpacing: 1.0),
itemCount: notes.length,
itemBuilder: (context, index) => Card(
child: Image.network(notes[index],
fit: BoxFit.cover,
),
),
)
],
),
),
),
),
),
);
}
Widget _detailedBody() {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width * 3 / 4,
decoration: BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: NetworkImage(
'http://www.korea.kr/newsWeb/resources/attaches/2017.08/03/3737_cp.jpg'),
),
),
),
Container(
transform: Matrix4.translationValues(0.0, -41.0, 0.0),
child: Column(
children: <Widget>[
Stack(
alignment: Alignment.center,
children: <Widget>[
SizedBox(
width: 90.0,
height: 90.0,
child: CircleAvatar(
backgroundColor: Colors.white,
),
),
SizedBox(
width: 82.0,
height: 82.0,
child: CircleAvatar(
backgroundImage: NetworkImage(
'https://steemitimages.com/DQmS1gGYmG3vL6PKh46A2r6MHxieVETW7kQ9QLo7tdV5FV2/IMG_1426.JPG')),
),
Container(
width: 90.0,
height: 90.0,
alignment: Alignment.bottomRight,
child: Stack(
alignment: Alignment.center,
children: <Widget>[
SizedBox(
width: 28.0,
height: 28.0,
child: FloatingActionButton(
onPressed: null,
backgroundColor: Colors.white,
//child: Icon(Icons.add),
),
),
SizedBox(
width: 25.0,
height: 25.0,
child: FloatingActionButton(
onPressed: null,
backgroundColor:
Theme.of(context).colorScheme.mainColor,
child: Icon(Icons.add),
),
),
],
))
],
),
Padding(padding: EdgeInsets.all(5.0)),
Text(
'nickname',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 24.0),
),
Padding(padding: EdgeInsets.all(5.0)),
Text(
'introduce',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 15.0),
),
Padding(padding: EdgeInsets.all(9.0)),
FlatButton(
onPressed: () {
signOutWithGoogle().then((_) {
Navigator.popUntil(context, ModalRoute.withName('/'));
});
},
color: Theme.of(context).colorScheme.mainColor,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(5.0)),
child: Text('로그아웃'),
),
Padding(padding: EdgeInsets.all(9.0)),
Row(
mainAxisAlignment: MainAxisAlignment.spaceAround,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Column(
children: <Widget>[
Text(
'0',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16.0),
),
Text(
'식물수',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
],
),
Column(
children: <Widget>[
Text(
'0',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16.0),
),
Text(
'팔로워',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
],
),
Column(
children: <Widget>[
Text(
'0',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 16.0),
),
Text(
'팔로잉',
textAlign: TextAlign.center,
style: TextStyle(fontSize: 20.0),
),
],
)
],
)
],
),
),
],
);
}
var tabindi = 0;
Widget _bottomButtons(tabindi) {
print(tabindi);
return tabindi == 0
? Container(
child: Row(
children: <Widget>[
Padding(
padding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 15.0),
child: Icon(
Icons.clear_all,
color: Colors.grey,
),
),
Container(
width: MediaQuery.of(context).size.width/3*1.4,
child: DropdownButton<String>(
isExpanded: true,
items: <String>['Foo', 'Bar'].map((String value) {
return DropdownMenuItem<String>(
value: value,
child: Text(value),
);
}).toList(),
onChanged: (_) {},
),
),
Padding(
padding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 5.0),
child: Icon(
Icons.mode_edit,
color: Colors.grey,
),
),
Padding(
padding:
EdgeInsets.symmetric(vertical: 10.0, horizontal: 1.0),
child: Icon(
Icons.delete,
color: Colors.grey,
),
),
Padding(
padding: EdgeInsets.all(4.0),
),
Container(
height: 30,
width: MediaQuery.of(context).size.width/4.5,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.mainColor,
borderRadius: BorderRadius.all(Radius.circular(20)),
boxShadow: <BoxShadow>[
BoxShadow(
color: Colors.grey.shade200,
offset: Offset(2, 4),
blurRadius: 5,
spreadRadius: 2)
],
),
child: FlatButton(
child: Text(
"+식물등록",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 13,
color: Colors.white,
),
),
onPressed: () => {
},
),
),
],
),
)
:
Container();
}
List<String> notes = [
'https://steemitimages.com/DQmS1gGYmG3vL6PKh46A2r6MHxieVETW7kQ9QLo7tdV5FV2/IMG_1426.JPG',
'https://lh3.googleusercontent.com/proxy/BKvyuWq6b5apNOqvSw3VxB-QhezYHAoX1AptJdWPl-Ktq-Efm2gotbeXFtFlkr_ZPZmpEHc2BsKTC9oFQgzBimKsf5oRtTqOGdlO3MTfwiOT54E5m-lCtt6ANOMzmhNsYMGRp9Pg1NzjwMRUWNoWX0oJEFcnFvjOj2Rr4LtZpkXyiQFO',
'https://img1.daumcdn.net/thumb/R720x0.q80/?scode=mtistory2&fname=http%3A%2F%2Fcfile28.uf.tistory.com%2Fimage%2F2343174F58DBC14C2ECB8B',
'https://steemitimages.com/DQmS1gGYmG3vL6PKh46A2r6MHxieVETW7kQ9QLo7tdV5FV2/IMG_1426.JPG',
'https://lh3.googleusercontent.com/proxy/BKvyuWq6b5apNOqvSw3VxB-QhezYHAoX1AptJdWPl-Ktq-Efm2gotbeXFtFlkr_ZPZmpEHc2BsKTC9oFQgzBimKsf5oRtTqOGdlO3MTfwiOT54E5m-lCtt6ANOMzmhNsYMGRp9Pg1NzjwMRUWNoWX0oJEFcnFvjOj2Rr4LtZpkXyiQFO',
'https://img1.daumcdn.net/thumb/R720x0.q80/?scode=mtistory2&fname=http%3A%2F%2Fcfile28.uf.tistory.com%2Fimage%2F2343174F58DBC14C2ECB8B',
'https://steemitimages.com/DQmS1gGYmG3vL6PKh46A2r6MHxieVETW7kQ9QLo7tdV5FV2/IMG_1426.JPG',
'https://lh3.googleusercontent.com/proxy/BKvyuWq6b5apNOqvSw3VxB-QhezYHAoX1AptJdWPl-Ktq-Efm2gotbeXFtFlkr_ZPZmpEHc2BsKTC9oFQgzBimKsf5oRtTqOGdlO3MTfwiOT54E5m-lCtt6ANOMzmhNsYMGRp9Pg1NzjwMRUWNoWX0oJEFcnFvjOj2Rr4LtZpkXyiQFO',
'https://img1.daumcdn.net/thumb/R720x0.q80/?scode=mtistory2&fname=http%3A%2F%2Fcfile28.uf.tistory.com%2Fimage%2F2343174F58DBC14C2ECB8B',
];
Future<void> signOutWithGoogle() async {
// Sign out with firebase
await _Auth.signOut();
// Sign out with google
await _googleSignIn.signOut();
}
}
class TabBarDelegate extends SliverPersistentHeaderDelegate {
TabBarDelegate(this._tabBar);
final Column _tabBar;
#override
double get minExtent => 130.0;
#override
double get maxExtent => 130.0;
#override
Widget build(BuildContext context, double shrinkOffset,
bool overlapsContent) {
return Container(
color: Color(0xFFFAFAFA),
height: 130.0,
child: _tabBar
);
}
#override
bool shouldRebuild(covariant TabBarDelegate oldDelegate) {
return false;
}
}
I am looking forward your answers.
Thank you!
Use Offstage widget
Offstage(
offstage: _controller.index == 1,
child: _bottomButtons(tabindi)
),
Update when tap TabBar
TabBar(onTap: (_) => setState((){}));
I just want when I click on like button it's like only one post please help me how I can implement this functionality the like button Thank you.
import 'package:assort_project/preferences.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:firebase_database/firebase_database.dart';
import 'package:share/share.dart';
import 'browser.dart';
import 'home_screen.dart';
import 'package:timeago/timeago.dart' as timeago;
class NewsFeedPage extends StatefulWidget {
#override
_NewsFeeds createState() => _NewsFeeds();
}
class _NewsFeeds extends State<NewsFeedPage> {
String _id;
bool liked = false;
var date = new DateTime.fromMillisecondsSinceEpoch(1561092817 * 1000);
final GlobalKey<RefreshIndicatorState> _refreshIndicatorKey =
new GlobalKey<RefreshIndicatorState>();
void getData() {
FirebaseDatabase.instance
.reference()
.child("NewsFeed")
.once()
.then((DataSnapshot snapshot) {
Map<dynamic, dynamic> values = snapshot.value;
values.forEach((key, values) {
print(values["country"]);
});
});
}
#override
void initState() {
super.initState();
getCurrentUser();
}
#override
Widget build(BuildContext context) {
getData();
getCurrentUser();
print(getCurrentUser());
return new Scaffold(
appBar: new AppBar(
title: new Text('News Feed'),
),
drawer: new Drawer(
child: Container(
alignment: Alignment.center,
child: new Column(
children: <Widget>[
Container(
padding: EdgeInsets.only(bottom: 10, right: 5, top: 25),
alignment: Alignment.center,
color: Color(0xffF7F7F7),
child: Column(
children: <Widget>[
Image.asset(
'assets/images/defalut.png',
height: 100,
width: 100,
),
SizedBox(
height: 15.0,
),
Container(
alignment: Alignment.topRight,
child: Row(
// Replace with a Row for horizontal icon + text
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Icon(Icons.border_color),
SizedBox(
width: 10.0,
),
Text(
"Edit Profile",
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
),
],
),
)
],
),
),
Container(
padding: EdgeInsets.all(20),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
SizedBox(
height: 15.0,
),
Row(
// Replace with a Row for horizontal icon + text
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.radio),
SizedBox(
width: 10.0,
),
Text(
"News Feed",
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
)
],
),
SizedBox(
height: 15.0,
),
InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UserBirthBasisPage()),
);
},
child: Row(
// Replace with a Row for horizontal icon + text
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.settings),
SizedBox(
width: 10.0,
),
Text(
"Preferences",
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
)
],
),
),
SizedBox(
height: 15.0,
),
Row(
// Replace with a Row for horizontal icon + text
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.favorite_border),
SizedBox(
width: 10.0,
),
Text(
"Favorite",
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
)
],
),
SizedBox(
height: 15.0,
),
Row(
// Replace with a Row for horizontal icon + text
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.announcement),
SizedBox(
width: 10.0,
),
Text(
"About us",
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
)
],
),
SizedBox(
height: 15.0,
),
InkWell(
onTap: () {
Navigator.pushReplacement(
context,
MaterialPageRoute(
builder: (context) => new LoginScreen()),
);
},
child: Row(
// Replace with a Row for horizontal icon + text
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(Icons.exit_to_app),
SizedBox(
width: 10.0,
),
Text(
"Logout",
style: TextStyle(
color: Colors.black,
fontSize: 15.0,
),
)
],
),
),
],
),
),
],
)),
),
backgroundColor: Color(0xffF7F7F7),
body: StreamBuilder(
stream:
FirebaseDatabase.instance.reference().child("NewsFeed").onValue,
builder: (BuildContext context, AsyncSnapshot<Event> snapshot) {
if (snapshot.hasData) {
Map<dynamic, dynamic> map = snapshot.data.snapshot.value;
map.forEach((dynamic, v) => print(v["imageUrl"]));
return ListView.builder(
itemCount: map.values.toList().length,
itemBuilder: (context, index) {
return nameDropDownList1(
map,
index,
);
},
);
} else {
return Center(child: CircularProgressIndicator());
}
}));
}
Future<String> getCurrentUser() async {
FirebaseUser user = await FirebaseAuth.instance.currentUser();
_id = user.uid.toString();
return user.uid.toString();
}
Future<void> signOut() async {
return FirebaseAuth.instance.signOut();
}
void _likePressed() {
setState(() {
liked = !liked;
});
}
Widget nameDropDownList1(Map map, int index) {
return Column(mainAxisSize: MainAxisSize.min, children: <Widget>[
Flexible(
child: Card(
child: new InkWell(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ContactUsPage(
map.values.toList()[index]["articleUrl"])),
);
},
child: new Padding(
padding: const EdgeInsets.all(4.0),
child: new Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Flexible(
child: Container(
alignment: Alignment.topCenter,
width: double.infinity,
height: 250,
child: Image.network(
map.values.toList()[index]["imageUrl"],
width: double.infinity,
height: 300,
fit: BoxFit.cover,
),
),
fit: FlexFit.loose,
flex: 7,
),
SizedBox(
height: 5,
),
new Flexible(
child: Text(
map.values.toList()[index]["articleTitle"],
textAlign: TextAlign.left,
style: TextStyle(
fontSize: 16,
color: Colors.blue,
fontWeight: FontWeight.bold),
maxLines: 2,
),
flex: 2,
fit: FlexFit.loose,
),
SizedBox(
height: 10,
),
new Flexible(
child: Text(
map.values.toList()[index]["content"],
style: TextStyle(
fontSize: 15,
color: Colors.black54,
),
textAlign: TextAlign.left,
overflow: TextOverflow.ellipsis,
maxLines: 2,
),
flex: 2,
fit: FlexFit.loose,
),
SizedBox(
height: 15,
),
new Flexible(
child: Align(
alignment: Alignment.centerRight,
child: Text(
timeago.format(DateTime.fromMillisecondsSinceEpoch(
map.values.toList()[index]["timeStamp"] * 1000)),
style: TextStyle(
fontSize: 15,
color: Colors.black,
),
textAlign: TextAlign.right,
overflow: TextOverflow.ellipsis,
maxLines: 1,
),
),
flex: 1,
fit: FlexFit.loose,
),
Flexible(
child: new Row(
crossAxisAlignment: CrossAxisAlignment.end,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
IconButton(
icon: Icon(
liked ? Icons.favorite : Icons.favorite_border,
color: liked ? Colors.red : Colors.black,
),
onPressed: () {
}),
IconButton(
icon: Icon(
Icons.comment,
),
onPressed: () {}),
IconButton(
icon: Icon(
Icons.star_border,
),
onPressed: () {
FirebaseDatabase.instance
.reference()
.child('UserFavouritPoste')
.child(_id)
.push()
.set({
'newsFeedId': map.values.toList()[index]
["NewsFeedId"],
});
}),
IconButton(
icon: Icon(
Icons.share,
),
onPressed: () {
Share.share('check out ' +
map.values.toList()[index]["articleUrl"]);
}),
],
),
fit: FlexFit.loose,
flex: 2,
),
],
),
),
),
),
fit: FlexFit.loose,
flex: 1,
),
]);
}
}
I am stuck there Any help or advice will be greatly appreciated. Thanks in advance.
You need to separate the post into a separate widget. When you set change the liked property, that is the same property for all the cards you're building and thats why all the post gets liked. If you have each post as a separate widget, each post will hold a different state.
example:
return ListView.builder(
itemCount: map.values.toList().length,
itemBuilder: (context, index) {
return PostWidget();
},
);
Post Widget:
class PostWidget extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _PostWidgetState();
}
}
class _PostWidgetState extends State<PostWidget> {
bool _liked = false;
#override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
setState(() { _liked = !_liked; });
},
child: Container(
color: Colors.red,
),
);
}
}