Flutter GridView Expandedable Tile - flutter

Hi, Everyone;
I need help on Fluter GridView
I want to build a simple gallery view but i haven't reached my goal yet
I have a urlImage List on simple image gridView. When select one of those image the selected image will expanded with some info Thats what I want to do.
i need help with this
Thank you.
flutter_staggered_grid_view
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return testWidget();
}
bool expanded = false;
var nodeSize = [
NodeSize(2, 3),
NodeSize(2, 3),
NodeSize(2, 2),
NodeSize(2, 2),
NodeSize(2, 2),
NodeSize(2, 2),
NodeSize(2, 2),
NodeSize(2, 3),
NodeSize(2, 3),
NodeSize(2, 3),
NodeSize(2, 3),
];
List<String> listImages = [
"https://images.unsplash.com/photo-1572537165377-627a37043464?ixid=MnwxMjA3fDB8MHxzZWFyY2h8NXx8cGl4ZWx8ZW58MHx8MHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1572204292164-b35ba943fca7?ixid=MnwxMjA3fDB8MHxzZWFyY2h8Nnx8cGl4ZWx8ZW58MHx8MHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1590254553792-7e91903c5357?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTB8fHBpeGVsfGVufDB8fDB8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1548586196-aa5803b77379?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTd8fHBpeGVsfGVufDB8fDB8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1572447454458-e68d82f828b3?ixid=MnwxMjA3fDB8MHxzZWFyY2h8ODd8fHBpeGVsfGVufDB8fDB8fA%3D%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1572204304559-b5f5380482c5?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTA4fHxwaXhlbHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1554516829-a3fce6ddbc6e?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTQzfHxwaXhlbHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1563642421748-5047b6585a4a?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTY2fHxwaXhlbHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
"https://images.unsplash.com/photo-1593439147804-c6c7656530ae?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MzUzfHxwaXhlbHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60",
];
Widget testWidget() {
var tiles = [
for (int i = 0; i < 9; i++) GridTile(nodeSize[i].x, nodeSize[i].y),
];
return Expanded(
child: SingleChildScrollView(
child: StaggeredGrid.count(
crossAxisCount: 4,
mainAxisSpacing: 8,
crossAxisSpacing: 8,
children: [
...tiles.mapIndexed((index, tile) {
return StaggeredGridTile.count(
crossAxisCellCount: tile.crossAxisCount.toInt(),
mainAxisCellCount: tile.mainAxisCount,
child: GestureDetector(
onTap: () async {
setState(() {
if (expanded) {
nodeSize[index].x = 4;
nodeSize[index].y = 4.2;
expanded = false;
} else {
nodeSize[index].x = 2;
nodeSize[index].y = 2;
expanded = true;
}
});
},
child: nodeSize[index].x == 2
? ClipRRect(
borderRadius: BorderRadius.all(Radius.circular(12)),
child: FadeInImage.memoryNetwork(
placeholder: kTransparentImage,
image: listImages[index],
fit: BoxFit.cover),
)
: PostRow(listImages[index]),
),
);
}),
],
),
),
);
}
}
class NodeSize {
NodeSize(this.x, this.y);
double x;
double y;
}
class GridTile {
const GridTile(this.crossAxisCount, this.mainAxisCount);
final double crossAxisCount;
final double mainAxisCount;
}
class PostRow extends StatefulWidget {
String imageURL;
PostRow(this.imageURL);
#override
State<PostRow> createState() => _PostRowState();
}
class _PostRowState extends State<PostRow> {
ApiManager apiManager = new ApiManager();
#override
Widget build(BuildContext context) {
return Container(
margin: EdgeInsets.only(left: 3.0.w, right: 3.0.w, bottom: 3.w),
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(10),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
height: 2.h,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
SizedBox(
width: 40.w,
child: FittedBox(
alignment: Alignment.centerLeft,
fit: BoxFit.scaleDown,
child: Text("UserName",
style: TextStyle(
fontSize: 13.sp,
color: Color(0xff272727),
fontWeight: FontWeight.w500)),
),
),
Spacer(),
],
),
SizedBox(height: 1.h),
ClipRRect(
borderRadius: BorderRadius.circular(10.0),
child: FadeInImage.assetNetwork(
placeholder: 'assets/images/placeholder.png',
imageErrorBuilder: (context, error, stackTrace) {
print('Error is $error , stack is $stackTrace');
return Image.asset(
'assets/images/placeholder.png',
);
},
image: widget.imageURL,
fit: BoxFit.fill,
fadeInDuration: const Duration(seconds: 1),
fadeOutDuration: const Duration(milliseconds: 1),
),
),
SizedBox(height: 1.h),
Padding(
padding: EdgeInsets.only(left: 3.w),
child: Row(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("Text Title here....."),
Row(
children: [
SvgPicture.asset(
"assets/svg/openeyeicon.svg",
),
SizedBox(width: 2.w),
Text("430", style: TextStyle(fontWeight: FontWeight.w500)),
],
),
SizedBox(width: 2.w),
Text(
"172",
style: TextStyle(fontWeight: FontWeight.w500),
),
],
),
),
SizedBox(height: 2.h),
Padding(
padding: EdgeInsets.only(left: 3.w),
child: Text(
"1 hour ago",
style: TextStyle(color: Colors.grey, fontSize: 9.sp),
),
),
],
),
);
}
}
This what I have right now;

First, Make a model with nullable
class ImageItem{
String? imageName;
String? imageDesc;
String? imagePrice;
String? imageUrl;
ServiceItem(
this.imageName,
this.imageDesc,
this.imagePrice,
this.imageUrl
);
}
make a bool var to check click
bool isClick = false;
Make a List
static List<ImageItem> myList = [
ImageItem("Android", "Get amarseba Android app within big discount", "200", "https://images.unsplash.com/photo-1593439147804-c6c7656530ae?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MzUzfHxwaXhlbHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"),
ImageItem("Apple", "Hurry! Amarseba IOS app already launched! Take your ones", "300", "https://images.unsplash.com/photo-1563642421748-5047b6585a4a?ixid=MnwxMjA3fDB8MHxzZWFyY2h8MTY2fHxwaXhlbHxlbnwwfHwwfHw%3D&ixlib=rb-1.2.1&auto=format&fit=crop&w=500&q=60"),
];
Now it's time to view
GridView.count(
childAspectRatio: 1,
crossAxisCount: 2,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
children: myList.map((data) {
return InkWell(
onTap: (){
setState(() {
isClick = true;
});
},
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
isClick ? Text(data.imageDesc!,) : null,
Image.asset(data.ImageUrl!, width: !isClick ? 100 : double.infinity,), //I'll not use Expanded
heightSizedBox,
isClick ? Text(data.imageName!,) : null, //if null unexpected use dummy SizedBox or Container.
],
),
);
}).toList(),
)

Related

Flutter: pass data from one screen to another based on a list that I fetch from API

I am building a Job Find app on flutter and I am facing some State Management problems. I have a screen where I show all of my job listings (job_list_screen.dart) and if the user press on a job the app loads this specific job with all the details(job_details_screen.dart).
enter image description here
enter image description here
As you can see, I have an apply button(the blue button) on both screens. When I press apply on the job_details_screen I send a put request on my database and it works fine. But, when I go back to my job_list_screen the button doesn't change even thought I wrapped it with a Consumer.
enter image description here
enter image description here
Here is all the code I wrote with the providers, the **screens **and the **widgets **I use.
The jobs provider:
First of all, this is how I fetch jobs from the API and I insert all my data in a List model:
`
/*
|--------------------------------------------------------------------------
| Fetch Jobs from database
|--------------------------------------------------------------------------
|
| 1. set the url for this function
| 2. GET the response from the server only if you are authenticated
| 3. Decode the
response.body: {
'listings': {
'data': (*Inside here, there are all the job list*)
}
}
| 4. For every job inside the data response
| add a new Job item in the List<Job>
| with the named variables from the current data.reposnse.job
*/
Future<List<Job>?> fetchJobs() async {
final key = await storage.read(key: 'auth');
final baseUrl = AppUrl.baseUrl;
try {
// 1.
var url = Uri.parse('$baseUrl/listings');
// 2.
var response = await http.get(
url,
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $key',
},
);
// print(key);
if (response.statusCode == 200 || response.statusCode == 201) {
// 3.
var jsonResponse = jsonDecode(response.body)['listings']['data'];
_jobs = [];
// 4.
for (var j in jsonResponse) {
Job job = Job(
id: j['id'],
title: j['title'],
employmentType: j['employmentType'],
major: j['major'],
city: j['city'],
companyName: j['companyName'],
experience: j['experience'],
date: j['date'],
views: j['views'],
description: j['description'],
benefits: j['benefits'],
requirements: j['requirements'],
hasApplied: j['hasApplied'],
hasViewed: j['hasViewed'],
);
_jobs.add(job);
notifyListeners();
}
notifyListeners();
return _jobs;
} else {
throw Exception('Problem loading jobs');
}
} catch (e) {
print(e);
}
}
`
This is the function that I call when the user presses the apply button:
`
/*
|--------------------------------------------------------------------------
| Apply for a job
|--------------------------------------------------------------------------
*/
Future<void> applyJob(String id) async {
final key = await storage.read(key: 'auth');
final baseUrl = AppUrl.baseUrl;
try {
var url = Uri.parse('$baseUrl/listings/$id/apply');
var response = await http.put(
url,
headers: {
'Accept': 'application/json',
'Authorization': 'Bearer $key',
},
);
if (response.statusCode == 200 || response.statusCode == 201) {
print(jsonDecode(response.body));
_hasApplied = jsonDecode(response.body)['hasApplied'];
notifyListeners();
} else {
print(jsonDecode(response.body));
notifyListeners();
}
} catch (e) {
print(e);
}
notifyListeners();
}
`
The job_card widget:
`
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:final_try/screens/job_details_screen.dart';
import '../models/job.dart';
import '../providers/jobs.dart';
import '../styles/colors.dart';
class JobCardBig extends StatefulWidget {
static const routeName = '/job-card-big';
#override
State<JobCardBig> createState() => _JobCardBigState();
}
class _JobCardBigState extends State<JobCardBig> {
#override
Widget build(BuildContext context) {
final job = Provider.of<Job>(context, listen: true);
return Container(
padding: EdgeInsets.all(10),
margin: EdgeInsets.only(bottom: 10),
width: double.infinity,
decoration: BoxDecoration(
border: Border.all(color: lightgrey, width: 1),
borderRadius: BorderRadius.circular(5.0),
boxShadow: [
BoxShadow(
color: lightgrey.withOpacity(.5),
spreadRadius: 1,
blurRadius: 2,
offset: Offset(0, 1), // changes position of shadow
),
],
color: white,
),
child: Column(children: [
Container(
child: Row(
children: [
Container(
height: 50,
width: 50,
alignment: Alignment.center,
decoration:
BoxDecoration(shape: BoxShape.circle, color: lightgrey),
),
SizedBox(
width: 10,
),
Expanded(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Flexible(
child: Container(
height: 70,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.spaceAround,
children: [
Text(
job.title.toString(),
style: TextStyle(
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
Text(
job.companyName.toString(),
style: TextStyle(
fontSize: 14,
color: lightgrey,
),
),
],
),
),
),
Container(
height: 70,
width: 50,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Icon(
Icons.remove_red_eye,
size: 14,
color: darkgrey,
),
SizedBox(
width: 5,
),
Text(
job.views == null
? job.views = '0'
: job.views.toString(),
style: TextStyle(
fontSize: 14,
color: darkgrey,
),
),
],
),
],
),
),
],
),
),
],
)),
SizedBox(
height: 5,
),
Divider(
thickness: 1,
),
SizedBox(
height: 5,
),
Container(
height: 80,
alignment: Alignment.bottomLeft,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Text(
'Είδος Απασχόλησης:',
),
SizedBox(
width: 5,
),
Text(
Provider.of<Jobs>(context, listen: false)
.jobTypeFormat(job.employmentType.toString()),
style: TextStyle(color: lightgrey),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text('Προϋπηρεσία:'),
SizedBox(
width: 5,
),
Flexible(
child: job.experience == null
? Text(
'Δεν απαιτείται',
style: TextStyle(color: lightgrey),
)
: job.experience! > 1
? Text(
'${job.experience.toString()} χρόνια',
style: TextStyle(color: lightgrey),
)
: Text(
'${job.experience.toString()} χρόνο',
style: TextStyle(color: lightgrey),
),
),
],
),
Row(
children: [
Text('Τοποθεσία:'),
SizedBox(
width: 5,
),
Text(
job.city.toString(),
style: TextStyle(color: lightgrey),
),
],
),
Row(
children: [
Text('Δημοσιεύθηκε:'),
SizedBox(
width: 5,
),
Text(
Provider.of<Jobs>(context, listen: false)
.dateFormat(job.date),
// job.date.toString(),
style: TextStyle(color: lightgrey),
),
],
),
],
),
),
Container(
margin: EdgeInsets.only(top: 20),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
child: Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
border: Border.all(color: darkgrey, width: 1),
borderRadius: BorderRadius.circular(5.0),
color: darkgrey,
),
child: Text(
'Περισσότερα',
style: TextStyle(color: white),
),
),
onTap: () {
Navigator.of(context)
.pushNamed(JobDetailsScreen.routeName, arguments: job.id)
.then((_) {
// Provider.of<Jobs>(context, listen: false).fetchJobs();
});
},
),
Container(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 5),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(5.0),
color: job.hasApplied == 1
? Color.fromARGB(255, 196, 76, 68)
: buttonColor,
),
child: Consumer<Job>(
builder: (context, job, child) {
return Text(
job.hasApplied == 1 ? 'Δεν ενδιαφέρομαι' : 'Αίτηση',
style: TextStyle(
color: white,
),
);
},
),
),
],
),
),
]),
);
}
}
`
The job_list_screen:
Here I load all my job_card widgets with ListView.builder
`
import 'package:provider/provider.dart';
import 'package:flutter/material.dart';
import '../styles/colors.dart';
import '../providers/jobs.dart';
import '../widgets/header_screen.dart';
import '../widgets/job_card_big.dart';
class JobListScreen extends StatefulWidget {
static const routeName = '/job-list-screen';
const JobListScreen({super.key});
#override
State<JobListScreen> createState() => _JobListScreenState();
}
class _JobListScreenState extends State<JobListScreen> {
final controller = ScrollController();
bool _firstLoading = true;
var _isLoading = false;
int page = 1;
final _formKey = GlobalKey<FormState>();
String? _searchText;
bool _isFiltered = false;
#override
void initState() {
controller.addListener(() {
if (controller.position.maxScrollExtent == controller.offset) {
fetch();
}
});
super.initState();
}
Future fetch() async {
if (!_isFiltered) {
setState(() {
_isLoading = true;
page++;
Provider.of<Jobs>(context, listen: false)
.fetchMore(page)
.then((_) => _isLoading = false);
});
}
}
#override
void didChangeDependencies() {
if (_firstLoading) {
Provider.of<Jobs>(context, listen: true).fetchJobs().then((_) {
setState(() {
_firstLoading = false;
});
});
}
super.didChangeDependencies();
}
void searchJob() {
if(_searchText == null || _searchText == ''){
setState(() {
_isFiltered = false;
});
}
else setState(() {
Provider.of<Jobs>(context, listen: false).filterJobs(_searchText!);
_isFiltered = true;
});
}
#override
Widget build(BuildContext context) {
final jobsData = Provider.of<Jobs>(context, listen: true);
var jobsList = jobsData.jobs;
var filteredList = jobsData.filteredJobs;
// var jobsListFiltered = jobsData.filteredJobs;
return Scaffold(
body: Stack(
children: [
Container(
height: MediaQuery.of(context).size.height,
padding: EdgeInsets.only(
top: 20,
right: 20,
left: 20,
),
child: Column(
children: [
HeaderScreen(title: 'Αγγελίες'),
Container(
child: Form(
key: _formKey,
child: Row(
children: [
Expanded(
child: Container(
child: TextFormField(
decoration: InputDecoration(
hintText: 'Enter some text',
),
onSaved: (value) {
_searchText = value;
},
),
),
),
Container(
margin: EdgeInsets.only(top: 10, bottom: 5),
height: 40,
width: 40,
child: ElevatedButton(
style: ButtonStyle(
foregroundColor:
MaterialStateProperty.all<Color>(white),
backgroundColor: MaterialStateProperty.all<Color>(
primaryColor),
),
child: Container(
child: Icon(Icons.search),
),
onPressed: () {
_formKey.currentState?.save();
searchJob();
},
),
),
],
),
),
),
SizedBox(
height: 10,
),
Divider(
thickness: 1,
),
SizedBox(
height: 10,
),
Expanded(
child: !_isFiltered
? Container(
child: !_firstLoading
? ListView.builder(
controller: controller,
itemCount: jobsList.length,
itemBuilder: (ctx, i) =>
ChangeNotifierProvider.value(
value: jobsList[i],
child: Column(
children: [
JobCardBig(),
],
),
),
)
: Center(
child: CircularProgressIndicator(),
),
)
: Container(
child: !_firstLoading
? ListView.builder(
controller: controller,
itemCount: filteredList.length,
itemBuilder: (ctx, i) =>
ChangeNotifierProvider.value(
value: filteredList[i],
child: Column(
children: [
JobCardBig(),
],
),
),
)
: Center(
child: CircularProgressIndicator(),
),
),
),
],
),
),
Positioned(
child: _isLoading
? Container(
width: double.infinity,
height: MediaQuery.of(context).size.height,
color: Color.fromARGB(52, 0, 0, 0),
child: Center(
child: CircularProgressIndicator(),
),
)
: Container(),
),
],
),
);
}
}
`
I tried to load my fetchJobs() function when the user exits the job_details_screen but even though it works, it is not the right solution. The reason why I say that this is not the right way, is because of this possible scenario:
If the user scrolls down a lot, and the app load 60 jobs, then if he presses on job 60, and he exit the job_details_screen, the app will load the first 15 jobs and the user will have to scroll down again. And that's not the user experience I want to provide.
I am searching for a solution that will update only the apply button and it will not need to recreate the whole list. Plus, with this solution the user will go back to the same scroll point he was when he entered the job_details_screen.
I hope I explained my problem properly. This is the first time I upload a question here and I would also like to mention that this is my first project on flutter so don't judge my code too harshly.
Thanks in advance!!

Flutter UI challenge

How to create this kind of UI in flutter. with expanded pageview??
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:movie_app/components/bottom_tabs.dart';
import 'package:movie_app/components/card_image.dart';
import 'package:movie_app/components/expandable_text.dart';
import 'package:movie_app/components/heading.dart';
import 'package:movie_app/constants.dart';
import 'package:movie_app/screens/card_details/components/card_details_cast.dart';
import 'package:movie_app/screens/card_details/components/card_details_photos.dart';
import 'package:movie_app/screens/card_details/components/card_details_reviews.dart';
import 'package:movie_app/screens/card_details/components/card_details_tabs.dart';
import '../../../components/my_text.dart';
import '../card_details.dart';
class Body extends StatefulWidget {
const Body({Key key}) : super(key: key);
#override
State<Body> createState() => _BodyState();
}
class _BodyState extends State<Body> {
PageController _tabsPageController;
int _selectedTab = 0;
#override
void initState() {
_tabsPageController = PageController();
super.initState();
}
#override
void dispose() {
_tabsPageController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return SingleChildScrollView(
child: Stack(
clipBehavior: Clip.none,
children: [
Image.network(
"https://static.wikia.nocookie.net/film-vault/images/c/c8/Furypost.jpg/revision/latest?cb=20171202094520",
height: 260,
fit: BoxFit.cover,
),
Positioned(
top: 100,
left: 180,
child: SvgPicture.asset(
"assets/icons/play icon.svg",
color: kwhitecolor,
height: 50,
),
),
Container(
margin: EdgeInsets.only(top: 200, left: 15, right: 15, bottom: 20),
child: Column(
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
const CardImage(
image:
"https://m.media-amazon.com/images/M/MV5BMjA4MDU0NTUyN15BMl5BanBnXkFtZTgwMzQxMzY4MjE#._V1_.jpg",
width: 120,
),
const SizedBox(width: 15),
// Text("data"),
Column(
// mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: const [
MyText(
"FURY",
fontSize: 22,
isBold: true,
color: Colors.black,
),
SizedBox(width: 2),
MyText(
"(2014)",
fontSize: 14,
isBold: true,
color: Colors.black,
),
],
),
const MyText(
"Action/Drama/War",
fontWeight: FontWeight.w600,
),
const SizedBox(height: 40),
Row(
children: [
const Icon(Icons.remove_red_eye_outlined,
color: klightgreyColor),
const SizedBox(width: 2),
const MyText("1.5M", isBold: true),
const SizedBox(width: 10),
SvgPicture.asset(
"assets/icons/comment.svg",
height: 21,
color: klightgreyColor,
),
const SizedBox(width: 4),
const MyText("1K", isBold: true),
const SizedBox(width: 10),
SvgPicture.asset(
"assets/icons/clock.svg",
height: 18,
color: klightgreyColor,
),
const SizedBox(width: 4),
const MyText("2h 30min", isBold: true),
],
),
],
),
],
),
const SizedBox(height: 30),
const Heading(
"STORYLINE",
fontSize: 18,
padding: 0,
lineColor: Color.fromARGB(255, 255, 68, 68),
// fontWeight: FontWeight.w800,
),
const SizedBox(height: 10),
const ExpandableText(
text:
"1945, the Allies are making their final push in the European theater. A battle-hardened Army sergeant nallier (Brad Pitt), leading a Sherman tank and a five-man crew, undertakes a deadly mission behind enemy lines. Hopelessly outnumbered, outgunned and saddled with an inexperienced soldier (Logan Lerman) in their midst, Wardaddy and his men face overwhelming odds as they move to strike at the heart of Nazi Germany.",
max: 4,
),
SizedBox(height: 10),
CardDetailsBottomTabs(
selectedTab: _selectedTab,
tabPressed: (num) {
_tabsPageController.animateToPage(num,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOutCubic);
},
),
// HERE I WANT TO USE EXPANDED WIDGET INSTEAD OF SIZEDBOX, BUT IT GIVES ME ERROR
SizedBox(
height: 300,
child: PageView(
controller: _tabsPageController,
onPageChanged: (num) {
setState(() {
_selectedTab = num;
});
},
children: const [
CardDetailsCast(),
CardDetailsPhoto(),
CardDetailsReview(),
],
),
),
],
),
),
],
),
);
}
}
this is all what I did so far, when I wrap pageview inside expanded widget it gives me error,
So is there any one who could find a way to wrap the pageview with expanded widget???
this is all what I did so far, when I wrap pageview inside expanded widget it gives me error,
So is there any one who could find a way to wrap the pageview with expanded widget???
this is all what I did so far, when I wrap pageview inside expanded widget it gives me error,
So is there any one who could find a way to wrap the pageview with expanded widget???
You can follow CustomScrollView with SliverAppBar. Example from SliverAppBar
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({Key? key}) : super(key: key);
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
bool _pinned = true;
bool _snap = false;
bool _floating = false;
// [SliverAppBar]s are typically used in [CustomScrollView.slivers], which in
// turn can be placed in a [Scaffold.body].
#override
Widget build(BuildContext context) {
return Scaffold(
body: CustomScrollView(
slivers: <Widget>[
SliverAppBar(
pinned: _pinned,
snap: _snap,
floating: _floating,
expandedHeight: 160.0,
flexibleSpace: const FlexibleSpaceBar(
title: Text('SliverAppBar'),
background: FlutterLogo(),
),
),
const SliverToBoxAdapter(
child: SizedBox(
height: 20,
child: Center(
child: Text('Scroll to see the SliverAppBar in effect.'),
),
),
),
SliverList(
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return Container(
color: index.isOdd ? Colors.white : Colors.black12,
height: 100.0,
child: Center(
child: Text('$index', textScaleFactor: 5),
),
);
},
childCount: 20,
),
),
],
),
bottomNavigationBar: BottomAppBar(
child: Padding(
padding: const EdgeInsets.all(8),
child: OverflowBar(
overflowAlignment: OverflowBarAlignment.center,
children: <Widget>[
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('pinned'),
Switch(
onChanged: (bool val) {
setState(() {
_pinned = val;
});
},
value: _pinned,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('snap'),
Switch(
onChanged: (bool val) {
setState(() {
_snap = val;
// Snapping only applies when the app bar is floating.
_floating = _floating || _snap;
});
},
value: _snap,
),
],
),
Row(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
const Text('floating'),
Switch(
onChanged: (bool val) {
setState(() {
_floating = val;
_snap = _snap && _floating;
});
},
value: _floating,
),
],
),
],
),
),
),
);
}
}

How to hide the tab name by clicking seach in flutter

I'm still new in flutter, does anyone know how to make the search in the tab card like picture below:
I try to figure it out how to solve this problem but still be like this:
Here is My code that I try to solve, I'm using the custom card, the custom dialog :
class TabbedCard extends StatefulWidget {
final List<Tab> tabs;
final List<Widget> children;
final bool showDeleteBtn;
final bool showPrimaryBtn;
const TabbedCard(
{Key? key,
required this.tabs,
required this.children,
this.showDeleteBtn = false,
this.showPrimaryBtn = true})
: super(key: key);
#override
State<TabbedCard> createState() => _TabbedCardState();
}
class _TabbedCardState extends State<TabbedCard> with TickerProviderStateMixin {
#override
Widget build(BuildContext context) {
double _scrHeight = MediaQuery.of(context).size.height - 150;
// String searchText = "";
TextEditingController textController = new TextEditingController();
TabController _controller =
TabController(length: widget.tabs.length, vsync: this);
TabBar _tabBar = new TabBar(
isScrollable: true,
labelColor: kPrimaryColor,
unselectedLabelColor: kTextGray,
controller: _controller,
tabs: widget.tabs,
);
return Container(
constraints: BoxConstraints(minHeight: _scrHeight),
child: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.symmetric(
vertical: 1,
horizontal: 1,
),
decoration: BoxDecoration(
border: Border.all(
color: Colors.white,
),
color: Colors.white,
boxShadow: [
BoxShadow(
color: Colors.white.withOpacity(0.5),
spreadRadius: -4,
blurRadius: 35,
offset: const Offset(0, 9), // changes position of shadow
),
],
),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Align(
alignment: Alignment.topLeft,
child: Row(
children: [
AnimSearchBar(
width: 400,
textController: textController,
onSuffixTap: (value) {
setState(() {});
},
),
const SizedBox(width: 10),
_tabBar,
const SizedBox(width: 10),
],
)),
const SizedBox(height: 10),
Container(
height: 440,
child: TabBarView(
controller: _controller,
children: widget.children,
),
),
],
),
),
const SizedBox(height: 10),
],
),
),
);
}
}
Really appreciate if anyone can help me with this problem ^^
You can try this:
first create bool showSearchView = false, then create two widget like this:
_tabView() {
return Row(
children: [
Container(
color: Colors.red,
width: 100,
height: 40,
),
Container(
margin: EdgeInsets.symmetric(horizontal: 16),
color: Colors.red,
width: 100,
height: 40,
),
Container(
color: Colors.red,
width: 100,
height: 40,
),
],
);
}
and
_searchView() {
return TextField();
}
then, use it like this:
Row(
children: [
InkWell(
onTap: () {
setState(() {
showSearchView = !showSearchView;
});
},
child: Icon(showSearchView ? Icons.close : Icons.search),
),
Expanded(
child: showSearchView ? _searchView() : _tabView(),
),
],
),

How to fetch data (Text) from Website in Flutter / dart?

So, I'm pretty new on Flutter (just about a week) and dart but I hope this Question is not toooooo stupid:
I'm trying to create an App for an existing Website (a forum). I dont want to use the flutter WebView, because I want to create an comepletly new Interface (The Website is not optimized for mobile View, that's why I'm builing this App).
The (german) Forum:
https://www.porsche-914.com/forum
I want to fetch the single forum topics as well as the posts itself including username, title and date and then map the text to a custom widget to display it. The Widget Part is no problem, it's already done but I cant figure out how to fetch that data from the website and how to store it.
I don't know, hope you can help me...
Thanks a lot for the taken time.
How the mapping should work:
fetched[index].title, fetched[index].text
Center(
child: NeumorphismPost(
title: fetched[index].title,
titleColor: Theme.of(context).cardColor,
textColor: Theme.of(context).cardColor,
text: fetched[index].text,
width: 370,
onTap: () {
_popupPage(context,
title: fetched[index].title,
child: Padding(
padding: const EdgeInsets.all(15.0),
child: Text(
fetched[index].text,
style: TextStyle(
color: Theme.of(context).cardColor,
fontSize: 18),
),
),
);
},
),
),
This is my custom Widget:
import 'package:flutter/material.dart';
class NeumorphismPost extends StatefulWidget {
final double width;
final double height;
final double borderRadius;
final String title;
final String text;
final Color titleColor;
final Color textColor;
final double titleSize;
final double textSize;
final Function onTap;
NeumorphismPost({
this.width = 185,
this.height = 185,
this.title = "Title",
this.text = "",
this.borderRadius = 20,
this.titleColor = const Color(0xFF424242),
this.textColor = const Color(0xFF424242),
this.titleSize = 22,
this.textSize = 18,
required this.onTap,
});
#override
State<NeumorphismPost> createState() => _NeumorphismPostState();
}
class _NeumorphismPostState extends State<NeumorphismPost> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
direction: Axis.vertical,
children: [
SingleChildScrollView(
child: SizedBox(
height: widget.height,
width: widget.width,
child: GestureDetector(
onTap: () {},
child: Scaffold(
backgroundColor: Colors.transparent,
body: SizedBox(
height: widget.height,
width: widget.width,
child: Center(
child: Container(
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius:
BorderRadius.circular(widget.borderRadius),
boxShadow: [
BoxShadow(
color: Theme.of(context).hintColor,
offset: const Offset(5, 5),
blurRadius: 15,
spreadRadius: 1,
),
BoxShadow(
color: Theme.of(context).backgroundColor,
offset: Offset(-5, -5),
blurRadius: 15,
spreadRadius: 1,
)
],
),
child: Wrap(
direction: Axis.horizontal,
children: [
SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Wrap(
direction: Axis.horizontal,
children: [
SizedBox(
height: widget.height / 3,
child: Wrap(
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets
.symmetric(
horizontal: 15,
vertical: 15),
child: Text(
widget.title,
textAlign:
TextAlign.center,
overflow:
TextOverflow.fade,
style: TextStyle(
fontSize:
widget.titleSize,
fontWeight:
FontWeight.bold,
color:
widget.titleColor,
),
),
),
],
),
],
),
),
],
),
Wrap(
direction: Axis.horizontal,
children: [
GestureDetector(
onTap: () {
widget.onTap();
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 5),
child: SizedBox(
height: widget.height / 1.38,
child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 15,
vertical: 15),
child: Text(
widget.text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: widget.textSize,
fontWeight:
FontWeight.normal,
color: widget.textColor,
),
),
),
),
),
),
],
),
],
),
),
),
],
),
),
),
),
),
),
),
),
],
),
);
}
}
From my point of view, you want to create a scraper. I checked the target website (https://www.porsche-914.com/forum), it can be scraped without any special technique (they don't have many Ajax calls (you may test by using Postman)). So it is a possible task. My suggestion flow is:
Load the raw HTML using any technique (http, dio, inappwebview ...)
Parse it using BeautifulSoup (https://pub.dev/packages/beautiful_soup_dart) (or any parser; it is just my favorite parser.)
Map it to your existing model.
Here is some example code. Hope it helps:
import 'package:http/http.dart' as http;
import 'package:beautiful_soup_dart/beautiful_soup.dart';
class TestParse {
excuteSample() async {
var url = Uri.parse('https://www.porsche-914.com/forum');
var response = await http.get(url);
BeautifulSoup bs = BeautifulSoup(response.body);
final allHeaderName = bs.findAll('td', attrs: {'class': 'oben'});
allHeaderName.forEach((element) {
print('the header: ${element.text}');
});
}
}
Here is the result:
The final result you need is a long story and long code. Hope this will give you a starting point.
UPDATE: I added the full demo code, using your requested code:
import 'package:beautiful_soup_dart/beautiful_soup.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() => runApp(const MaterialApp(home: MyApp()));
class MyApp extends StatefulWidget {
const MyApp({Key? key}) : super(key: key);
#override
State<MyApp> createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
final testparse = TestParse();
List<String> yourModelPleaseReplaceThis = [];
#override
void initState() {
super.initState();
excuteRequestAndParse();
}
excuteRequestAndParse() async {
final result =
await testparse.excuteSample(); //[1] i guess you missing this await
setState(() {
yourModelPleaseReplaceThis = result;
});
}
#override
Widget build(BuildContext context) {
return ListView.builder(
itemBuilder: (context, index) {
return Center(
child: NeumorphismPost(
title: yourModelPleaseReplaceThis[index],
titleColor: Theme.of(context).cardColor,
textColor: Theme.of(context).cardColor,
text: yourModelPleaseReplaceThis[index],
width: 370,
onTap: () {
//THIS CODE BELOW IS YOUR CODE....
},
),
);
},
itemCount: yourModelPleaseReplaceThis.length,
);
}
}
// BELOW IS TESTING CODE....
class TestParse {
Future<List<String>> excuteSample() async {
var url = Uri.parse('https://www.porsche-914.com/forum');
var response = await http.get(url);
BeautifulSoup bs = BeautifulSoup(response.body);
final allHeaderName = bs.findAll('td', attrs: {'class': 'oben'});
allHeaderName.forEach((element) {
print('the header: ${element.text}');
});
return Future.value(allHeaderName.map((e) => e.text).toList());
}
}
class NeumorphismPost extends StatefulWidget {
final double width;
final double height;
final double borderRadius;
final String title;
final String text;
final Color titleColor;
final Color textColor;
final double titleSize;
final double textSize;
final Function onTap;
NeumorphismPost({
this.width = 185,
this.height = 185,
this.title = "Title",
this.text = "",
this.borderRadius = 20,
this.titleColor = const Color(0xFF424242),
this.textColor = const Color(0xFF424242),
this.titleSize = 22,
this.textSize = 18,
required this.onTap,
});
#override
State<NeumorphismPost> createState() => _NeumorphismPostState();
}
class _NeumorphismPostState extends State<NeumorphismPost> {
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Wrap(
direction: Axis.vertical,
children: [
SingleChildScrollView(
child: SizedBox(
height: widget.height,
width: widget.width,
child: GestureDetector(
onTap: () {},
child: Scaffold(
backgroundColor: Colors.transparent,
body: SizedBox(
height: widget.height,
width: widget.width,
child: Center(
child: Container(
height: widget.height,
width: widget.width,
decoration: BoxDecoration(
color: Theme.of(context).backgroundColor,
borderRadius:
BorderRadius.circular(widget.borderRadius),
boxShadow: [
BoxShadow(
color: Theme.of(context).hintColor,
offset: const Offset(5, 5),
blurRadius: 15,
spreadRadius: 1,
),
BoxShadow(
color: Theme.of(context).backgroundColor,
offset: Offset(-5, -5),
blurRadius: 15,
spreadRadius: 1,
)
],
),
child: Wrap(
direction: Axis.horizontal,
children: [
SingleChildScrollView(
child: Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.spaceEvenly,
children: <Widget>[
Wrap(
direction: Axis.horizontal,
children: [
SizedBox(
height: widget.height / 3,
child: Wrap(
children: [
Column(
mainAxisAlignment:
MainAxisAlignment.start,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets
.symmetric(
horizontal: 15,
vertical: 15),
child: Text(
widget.title,
textAlign:
TextAlign.center,
overflow:
TextOverflow.fade,
style: TextStyle(
fontSize:
widget.titleSize,
fontWeight:
FontWeight.bold,
color:
widget.titleColor,
),
),
),
],
),
],
),
),
],
),
Wrap(
direction: Axis.horizontal,
children: [
GestureDetector(
onTap: () {
widget.onTap();
},
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 5),
child: SizedBox(
height: widget.height / 1.38,
child: Padding(
padding:
const EdgeInsets.symmetric(
horizontal: 15,
vertical: 15),
child: Text(
widget.text,
textAlign: TextAlign.center,
style: TextStyle(
fontSize: widget.textSize,
fontWeight:
FontWeight.normal,
color: widget.textColor,
),
),
),
),
),
),
],
),
],
),
),
),
],
),
),
),
),
),
),
),
),
],
),
);
}
}
This is the result:
Please note:
This list I created is for sample, so it is just a list of Strings. You should create a complete Model.

How to Get the Number of Pages in Pageview to be used in a line indicator in Flutter?

May i ask for help on how to get the number of pages inside a pageview,
similar to listview you can get the number of list via listview.length, but for pageview there is no pageview.length property that i can use,
i tried using pageview.builder but i couldnt initiate the data as a list showig an issue that i need to initiate it as an initializers?,
please help me figure it out
i need the data inside the pageview to be used inside the _lineprogressindicator, to show how many are the questionaires inside to make an indicator
here is my code
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:survey/content/thankyou.dart';
import 'package:survey/widgets/animations.dart';
import 'package:survey/widgets/buttonstyle.dart';
import 'package:survey/widgets/widgetlist.dart';
class questionaires extends StatefulWidget {
#override
_questionairesState createState() => _questionairesState();
}
class _questionairesState extends State<questionaires> {
TextStyle conqueststyle = TextStyle(
fontSize: 15, fontWeight: FontWeight.bold, color: Colors.indigo);
TextStyle questionstyle = TextStyle(
fontSize: 17,
fontWeight: FontWeight.bold,
);
String titletop = 'Post Visit Patient Satisfaction';
String q1 = "Sample Question HERE";
String q2 = "Sample Question HERE";
String q3 = "Sample Question HERE";
String q4 = "Sample Question HERE";
int percentagenum = 0;
int _currValue = 1;
bool _loading;
double _progress;
final _texteditingcontroller = TextEditingController();
final _pageController = PageController(initialPage: 0, keepPage: true);
var _currentpage = 0;
List answernumbers = ["5", "4", "3", "2", "1"];
List currentselectedvalue = [];
List usingCollection1 = [
"Excellent",
"Very Good",
"Good",
"Fair",
"Poor",
];
#override
void dispose() {
super.dispose();
_texteditingcontroller.dispose();
_loading = false;
_progress = 0.0;
percentagenum = 0;
_currValue = 0;
usingTimes1 = '';
usingTimes = '';
usingTimes2 = '';
}
void initState() {
super.initState();
usingTimes1 = '';
usingTimes = '';
usingTimes2 = '';
_loading = false;
_progress = 0.0;
percentagenum = 0;
_texteditingcontroller.clear();
_currValue = 0;
}
void pageChanged(int index) {
setState(() {
_currentpage = index;
});
}
void _selectedanswers(data1, data2) {
if (_progress.toStringAsFixed(1) == '1.0') {
print(data1);
print(data2);
_texteditingcontroller.text;
}
}
void _updateProgress() {
setState(() {
_progress += 0.25;
percentagenum += 25;
if (_progress.toStringAsFixed(1) == '1.0') {
_loading = false;
_progress = 0;
percentagenum = 0;
Navigator.push(context, FadeRoute(page: thankyou()));
return;
}
});
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Colors.white,
resizeToAvoidBottomPadding: false,
body: Padding(
padding: EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Container(
width: 100,
height: 60,
child: Image.asset(imgtit),
),
Stack(
children: <Widget>[
Container(
child: Text(
titletop,
style: conqueststyle,
maxLines: 1,
),
),
_buildPageView(),
_lineprogressindicator()
],
)
],
),
),
),
);
}
_buildPageView() {
return Container(
height: MediaQuery.of(context).size.height / 1.25,
child: PageView(
controller: _pageController,
onPageChanged: (index) {
pageChanged(index);
},
children: <Widget>[
_emojiquestions(q1),
_selectedutton(q2),
_numberrating(q3),
_textboxquestion(q4),
],
));
}
_lineprogressindicator() {
return Positioned(
left: 0.0,
right: 0.0,
bottom: 0.0,
child: Column(
children: <Widget>[
RaisedButton(
shape: RoundedRectangleBorder(
borderRadius: new BorderRadius.circular(50.0),
),
color: Colors.indigo,
onPressed: () {
_pageController.nextPage(
duration: kTabScrollDuration, curve: Curves.ease);
_loading = !_loading;
_updateProgress();
},
child: Icon(
Icons.check,
color: Colors.white,
size: 50,
),
),
SizedBox(
height: 10,
),
Text('%$percentagenum'),
LinearProgressIndicator(
value: _progress,
),
],
),
);
}
_emojiquestions(String quest1) {
final using = usingCollection1[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 1',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest1),
maxLines: 5,
style: conqueststyle,
),
Expanded(
child: Center(
child: Container(
height: 300,
child: ListView.separated(
separatorBuilder: (context, index) => SizedBox(height: 10),
itemCount: usingCollection1.length,
itemBuilder: (context, index) => GestureDetector(
onTapUp: (index) {
_selectedanswers(index, null);
},
child: Card(
color: usingTimes == usingCollection1[index]
? Colors.blue.withAlpha(100)
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
SizedBox(
height: 50,
width: 70,
child: Image.asset(emojiimage[index]),
),
Text(usingCollection1[index])
],
),
Divider(
height: index < usingCollection1.length ? 1.0 : 0.0,
),
],
),
),
),
)),
),
)
],
);
}
_selectedutton(String quest1) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 1',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest1),
maxLines: 5,
style: conqueststyle,
),
Expanded(
child: Center(
child: Container(
height: 300,
child: Column(
children: List.generate(usingCollection1.length, (int index) {
final using = usingCollection1[index];
return GestureDetector(
onTap: () {
setState(() {
_currValue = index;
_selectedanswers(index, null);
usingTimes = using.identifier;
});
},
child: Card(
color: usingTimes == using.identifier
? Colors.blue.withAlpha(100)
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
),
child: Column(
children: <Widget>[
Row(
children: <Widget>[
Radio(
value: index,
groupValue: _currValue,
onChanged: (val) =>
setState(() => _currValue = val),
),
Text(using.displayContent)
],
),
Divider(
height:
index < usingCollection1.length ? 1.0 : 0.0,
),
],
),
));
}),
),
),
),
)
],
);
}
_numberrating(quest) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 2',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest),
maxLines: 5,
style: conqueststyle,
),
Text("**5 is the highest"),
Container(
height: MediaQuery.of(context).size.height / 12.0,
width: MediaQuery.of(context).size.width,
child: ListView.builder(
physics: NeverScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
itemCount: usingCollection1.length,
itemBuilder: (context, index) {
final using = usingCollection1[index];
return GestureDetector(
onTapUp: (index) {
setState(() {
_selectedanswers(null, index);
usingTimes = using.identifier;
});
},
child: Card(
color: usingTimes == using.identifier
? Colors.blue.withAlpha(100)
: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0),
side: BorderSide(color: Colors.indigoAccent)),
child: Column(
children: <Widget>[
SizedBox(
height: 50,
width: 50,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
answernumbers[index],
textAlign: TextAlign.center,
style: conqueststyle,
),
],
)),
),
],
),
),
);
},
),
)
],
);
}
_textboxquestion(quest) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Text(
'Question 2',
style: conqueststyle,
textAlign: TextAlign.right,
),
SizedBox(
height: 20,
),
TextField(
decoration: InputDecoration.collapsed(hintText: quest),
maxLines: 5,
style: conqueststyle,
),
TextFormField(
decoration: InputDecoration(
hintText: "Your FeedBack Here",
border: OutlineInputBorder(),
),
controller: _texteditingcontroller,
maxLines: 7,
style: conqueststyle,
)
],
);
}
}
For your case were the number of elements is known beforehand, I would suggest that you store your pages in a local variable and then call length on it. A small snippet would look something like this:
class MyState extends State<MyWidget> {
List<Widget> _pages = [
Container(color: Colors.blue,),
Container(color: Colors.amber,),
];
#override
Widget build(BuildContext context) {
return MyComplexWidgetTree(
child: PageView(
controller: PageController(),
children: _pages,
),
);
}
void _myMethodThatRequiresNumberOfPages() {
int numberOfPages = pages.length;
}
}