I created a layout with two levels of tabs. The layout looks fine, but clicking on the second level (the Follower tab) tab, it doesn't work and it actives the Favourites tab.
I created a layout with two levels of tabs. The layout looks fine, but clicking on the second level (the Follower tab) tab, it doesn't work and it actives the Favourites tab.
new Container(
decoration: new BoxDecoration(color: Colors.pinkAccent),
child: new TabBar(
controller: _controller,
tabs: [
new Tab(
text: 'Favorites',
),
new Tab(
text: 'Follows',
),
],
),
),
new Expanded(
child: new TabBarView(
controller: _controller,
children: <Widget>[
new Container(
child: buildGrid(context, Posts),
),
new Container(
child: new Column(
children: <Widget>[
new Container(
decoration: new BoxDecoration(
color: Colors.grey),
child: new TabBar(
controller: tabController,
tabs: [
new Tab(
text: 'Follower',
),
new Tab(
text: 'Following',
),
],
),
),
new Expanded(
child: new TabBarView(
controller: tabController,
children: <Widget>[
new ListView.builder(
itemCount: followerList.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.only(
left: 10.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: <Widget>[
new Row(
children: <Widget>[
new HeroProfile(
followerList[
index]
[
"userID"]),
new Container(
padding:
new EdgeInsets
.only(
left:
10.0),
),
new Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: <
Widget>[
new Text(
followerList[
index]
[
'userName'],
style: new TextStyle(
fontFamily: 'Ubuntu',
letterSpacing: 0.5,
// fontWeight: FontWeight.bold,
fontSize: 13.0,
color: Colors.black),
),
new Container(
padding: new EdgeInsets
.only(
bottom:
5.0),
),
new Text(
followerList[
index]
[
'country'],
style: new TextStyle(
fontFamily: 'Ubuntu',
letterSpacing: 0.5,
// fontWeight: FontWeight.bold,
fontSize: 13.0,
color: Colors.lightBlue),
),
],
)
]),
new Divider(),
],
),
);
},
),
new ListView.builder(
itemCount: followerList.length,
itemBuilder: (context, index) {
return Container(
padding: EdgeInsets.only(
left: 10.0),
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: <Widget>[
new Row(
children: <Widget>[
new HeroProfile(
followerList[
index]
[
"userID"]),
new Container(
padding:
new EdgeInsets
.only(
left:
10.0),
),
new Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: <
Widget>[
new Text(
followerList[
index]
[
'userName'],
style: new TextStyle(
fontFamily: 'Ubuntu',
letterSpacing: 0.5,
fontSize: 13.0,
color: Colors.black),
),
new Container(
padding: new EdgeInsets
.only(
bottom:
5.0),
),
new Text(
followerList[
index]
[
'country'],
style: new TextStyle(
fontFamily: 'Ubuntu',
letterSpacing: 0.5,
fontSize: 13.0,
color: Colors.lightBlue),
),
],
)
]),
new Divider(),
],
),
);
},
),
])),
],
),
)
],
),
),
Related
I am reading json data that Contain some items (and Items have some categories I wanna show data on the basis of categories like using same widget again and again just have to change category name only Here What I have done so far it show all the items.
Also Added image for items.
Widget buildItems(List<[![Items]> items) => GridView.builder(
physics: const BouncingScrollPhysics(),
shrinkWrap: true,
scrollDirection: Axis.vertical,
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 2,
crossAxisSpacing: 4.0,
mainAxisSpacing: 20.0,
mainAxisExtent: 170,
),
//itemCount: items.length,
itemCount: itemCount,
itemBuilder: (context, index) {
final item = items[index];
int random = Random().nextInt(items.length);
print(random);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 15),
child: InkWell(
onTap: () => Navigator.of(context).push(MaterialPageRoute(
builder: (BuildContext context) =>
DetailScreen(item: item))),
// => Navigator.of(context).push(MaterialPageRoute(
// builder: (BuildContext context) =>
// ProductPage(product: product))),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(10),
boxShadow: const [
BoxShadow(
color: Colors.black38,
// spreadRadius: 5,
blurRadius: 7,
offset: Offset(0, 5.0)),
BoxShadow(color: Colors.white, offset: Offset(-1, 0)),
BoxShadow(color: Colors.white, offset: Offset(2, 0)),
]),
child: Column(
children: [
SizedBox(
child: ClipRRect(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(10),
topRight: Radius.circular(10)),
child: Image.network(
'$imageLink${item.imageUrl}',
fit: BoxFit.fill,
width: double.infinity,
height: 110,
),
),
),
SizedBox(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Container(
margin:
const EdgeInsets.only(left: 5, top: 10),
height: 40,
width: 40,
child: ClipRRect(
borderRadius: BorderRadius.circular(5),
child: Image.network(
'$iconLink${item.logo}',
fit: BoxFit.fill)),
),
Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.only(top: 5.0),
child: Container(
width: 120,
margin: const EdgeInsets.only(
top: 7, left: 5),
child: Flexible(
child: SizedBox(
child: Text('${item.name}',
overflow: TextOverflow.ellipsis,
style: Theme.of(context)
.textTheme
.bodyText1),
),
),
// Flexible(
// child: Text(
// product.name,
// style: const TextStyle(
// fontWeight: FontWeight.bold,
// color: Colors.black,
// fontSize: 14),
// ),
// ),
),
),
const SizedBox(
height: 2,
),
Padding(
padding: const EdgeInsets.only(left: 5.0),
child: Text('${item.subcategory}',
style: Theme.of(context)
.textTheme
.bodyText2!
.copyWith(
color: kButtonBackground)),
),
],
),
],
),
],
),
),
],
),
),
)
// ListTile(
// onTap: () => Navigator.of(context).push(MaterialPageRoute(
// builder: (BuildContext context) =>
// ProductPage(product: product))),
// title: Text(product.name),
// ),
);
},
);
//------------------------------ JSON SAMPLE
[ {
"name": "Item1",
"category": "Apple",
"subcategory": "Productivity",
"imageUrl": "Banner.jpg",
"logo": "logo.png",
"description": "falkr."
},
{
"name": "ABC",
"category": "Testing1",
"subcategory": "Productivity",
"imageUrl": "banner.jpg",
"logo": "System.png",
"description": "Testing."
}
]
//-------------------------------
https://i.stack.imgur.com/iX9Hh.png
#Talal, you have to filter the list based on the selected category, like below
List<Items> categorySpecificItems = allItems.where((item) => item.category == selectedCategory).toList()
Now pass the categorySpecificItems to buildItems on the change of selected category and use some state handling to render the UI.
Hope this works!
I am really confused as per what should I do, I am pretty bad with the layout of flutter.
I want to create boxes in the listview according to the number of strings (addresses) I have in another class - what is the best practice or approach for that?
Here Is the Image of the APP
import 'dart:async';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'package:geolocator/geolocator.dart';
import 'AddData.dart';
import 'package:donation_yoga/services/json_service.dart';
//import 'package:provider/provider.dart';
class Map extends StatefulWidget {
#override
State<StatefulWidget> createState() => _MapState();
}
class _MapState extends State<Map> {
/* Getting Live Location */
Completer<GoogleMapController> _controllerGoogleMap = Completer();
GoogleMapController newGoogleMapController;
Position currentPosition;
var geoLocator = Geolocator();
void locatePosition() async {
Position position = await Geolocator.getCurrentPosition(
desiredAccuracy: LocationAccuracy.best);
currentPosition = position;
LatLng latLngPos = LatLng(position.latitude, position.longitude);
CameraPosition cameraPosition =
CameraPosition(target: latLngPos, zoom: 15.0);
newGoogleMapController
.animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
}
static final CameraPosition _kGooglePlex = CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
zoom: 14.4746,
);
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(
children: <Widget>[
myLayoutWidget(),
_buildContainer(),
_createForm(context),
],
),
);
}
Widget myLayoutWidget() {
return Container(
child: GoogleMap(
mapType: MapType.normal,
myLocationButtonEnabled: true,
initialCameraPosition: _kGooglePlex,
myLocationEnabled: true,
zoomGesturesEnabled: true,
onMapCreated: (GoogleMapController controller) {
_controllerGoogleMap.complete(controller);
newGoogleMapController = controller;
locatePosition();
},
),
);
}
}
Widget _buildContainer() {
return Align(
alignment: Alignment.bottomLeft,
child: Container(
margin: EdgeInsets.symmetric(vertical: 20.0),
height: 150.0,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
SizedBox(width: 10.0),
Padding(
padding: const EdgeInsets.all(8.0),
child: _boxes(
"https://lh5.googleusercontent.com/p/AF1QipO3VPL9m-b355xWeg4MXmOQTauFAEkavSluTtJU=w225-h160-k-no",
40.738380,
-73.988426,
Centres.first),
),
SizedBox(width: 10.0),
Padding(
padding: const EdgeInsets.all(8.0),
child: _boxes(
"https://lh5.googleusercontent.com/p/AF1QipMKRN-1zTYMUVPrH-CcKzfTo6Nai7wdL7D8PMkt=w340-h160-k-no",
40.761421,
-73.981667,
Centres.second),
),
SizedBox(width: 10.0),
Padding(
padding: const EdgeInsets.all(8.0),
child: _boxes(
"https://images.unsplash.com/photo-1504940892017-d23b9053d5d4?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=500&q=60",
40.732128,
-73.999619,
Centres.third),
),
],
),
),
);
}
Widget _boxes(String _image, double lat, double long, String restaurantName) {
return GestureDetector(
onTap: () {},
child: Container(
child: new FittedBox(
child: Material(
color: Colors.white,
elevation: 14.0,
borderRadius: BorderRadius.circular(24.0),
shadowColor: Color(0x802196F3),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Container(
width: 180,
height: 200,
child: ClipRRect(
borderRadius: new BorderRadius.circular(24.0),
child: Image(
fit: BoxFit.fill,
image: NetworkImage(_image),
),
),
),
Container(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: myDetailsContainer1(restaurantName),
),
),
],
)),
),
),
);
}
Widget myDetailsContainer1(String restaurantName) {
return Column(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Padding(
padding: const EdgeInsets.only(left: 8.0),
child: Container(
child: Text(
restaurantName,
style: TextStyle(
color: Color(0xff6200ee),
fontSize: 24.0,
fontWeight: FontWeight.bold),
)),
),
SizedBox(height: 5.0),
Container(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: <Widget>[
Container(
child: Text(
"4.1",
style: TextStyle(
color: Colors.black54,
fontSize: 18.0,
),
)),
Container(
child: Icon(
FontAwesomeIcons.solidStar,
color: Colors.amber,
size: 15.0,
),
),
Container(
child: Icon(
FontAwesomeIcons.solidStar,
color: Colors.amber,
size: 15.0,
),
),
Container(
child: Icon(
FontAwesomeIcons.solidStar,
color: Colors.amber,
size: 15.0,
),
),
Container(
child: Icon(
FontAwesomeIcons.solidStar,
color: Colors.amber,
size: 15.0,
),
),
Container(
child: Icon(
FontAwesomeIcons.solidStarHalf,
color: Colors.amber,
size: 15.0,
),
),
Container(
child: Text(
"(946)",
style: TextStyle(
color: Colors.black54,
fontSize: 18.0,
),
)),
],
)),
SizedBox(height: 5.0),
Container(
child: Text(
"This is ",
style: TextStyle(
color: Colors.black54,
fontSize: 18.0,
),
)),
SizedBox(height: 5.0),
Container(
child: Text(
"Closed \u00B7 Opens 17:00 Thu",
style: TextStyle(
color: Colors.black54, fontSize: 18.0, fontWeight: FontWeight.bold),
)),
],
);
}
Widget _createForm(BuildContext context) {
return Align(
alignment: Alignment(-0.2, -1.0),
child: TextButton(
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => AddData()),
);
},
child: Text("Create")),
);
}
Here is my Other Class.
class Centres {
static const String first = 'This is our first location';
static const String second = 'This is our Second location';
static const String third = 'This is our Third locations';
}
The data in this class is gonna come from server.
You can use a ListView.builder to create a list of your boxes, just provide an item count that means how many widgets it will create and use the index to access each value you want to take from the lists of values.
I know i did not use you Centres class, unless you really need it to be a class, i find it easier to use a list with the values you need
class MyWidget extends StatelessWidget {
#override
Widget build(BuildContext context) {
final List<String> entries = <String>['A', 'B', 'C'];
final List<String> centres = [
'first location',
'second location',
'third location'
];
final List<double> latitudes = [40.732128, 40.732128, 40.732128];
final List<double> longitudes = [-73.999619, -73.999619, -73.999619];
return ListView.builder(
padding: const EdgeInsets.all(8),
itemCount: entries.length,
itemBuilder: (BuildContext context, int index) {
return _boxes(
entries[index],
latitudes[index],
longitudes[index],
centres[index],
);
});
}
}
You can use both ListView.builder() and PageView.builder(). in ListView you can stay in between two boxes but PageView only stays on one box. both have the itemCount and itemBuilder.
how can i put my list view into a expandable list view
body: RefreshIndicator(
onRefresh: getData,
key: _refresh,
child: loading
? Center(child: CircularProgressIndicator())
: ListView.builder(
itemCount: list.length,
itemBuilder: (context, i) {
final x = list[i];
debugPrint(x.toString());
return Container(
padding: EdgeInsets.all(20.0),
child: Row(
children: <Widget>[
Expanded(
first will be shown is the transaction ID and the vessel name and theres a arrow down that when you click it will display all the information in it
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'Transaction ID:\t' + x["transaction_id"],
style: TextStyle(
fontSize: 20.0,
fontWeight: FontWeight.bold),
),
Text('Vessel Name:\t' + x["vesselname"],
style: TextStyle(fontSize: 20.0)),
Text('Vessel Number:\t' + x["voyageno"],
style: TextStyle(fontSize: 20.0)),
Text('Ship Call #:\t' + x["scn"],
style: TextStyle(fontSize: 20.0)),
Text('Status:\t' + x["status"],
style: TextStyle(
fontSize: 20.0,
color: x["status"] == 'pending'
? Colors.red
: Colors.green)),
Divider()
],
),
),
],
),
);
},
),
));
}
}
You can use the Expandable Panel widget for that.
I have implemented a CustomScrollview in which i have the SliverGrid whereI'm successfully fetching the data from the server, but i need to provide the pagination over here, i need some assistance as how can acheive that whether by adding a button and incrementing the values or by adding an infinite scroll view and doing the pagination. But how to deal with the UI too is my problem here, so can any one assist me on this.
#override
Widget build(BuildContext context) {
print("Home");
return WillPopScope(
onWillPop: exitApp,
child: Scaffold(
appBar: AppBar(
leading: Image.asset('assets/images/ic_logo.png'),
actions: <Widget>[
Padding(
padding: const EdgeInsets.all(8.0),
child: FlatButton.icon(
onPressed: () {},
icon: Icon(Icons.location_on),
label: Text('Mysuru, India'),
textColor: Colors.white,
),
),
],
),
body: CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: SizedBox(
child: _search(),
),
),
SliverToBoxAdapter(
child: SizedBox(
child: FutureBuilder(
future: _getCat(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.data == null) {
return Center(
child: CircularProgressIndicator(),
);
} else {
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text('Categories'),
GestureDetector(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context) => CategoriesScreen()));
},
child: Text('VIEW ALL >', style: TextStyle(decoration: TextDecoration.underline, color: Colors.redAccent),),
)
],
),
),
Container(
height: 120,
child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
return Padding(
padding: const EdgeInsets.all(2.0),
child: InkWell(
onTap: () {
Navigator.push(context, MaterialPageRoute(builder: (context) => SubCategoriesScreen(snapshot.data[index].id,snapshot.data[index].title)));
},
child: Container(
width: 100,
child: ListTile(
title: Image.network(
snapshot.data[index].image,
height: 60,
width: 100,
),
subtitle: Container(
alignment: Alignment.topCenter,
child: Text(
snapshot.data[index].title,
style: TextStyle(fontSize: 10),
)),
),
),
),
);
// return Text(snapshot.data[index].id);
}),
),
],
);
}
},
),
),
),
SliverGrid(
gridDelegate: SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250.0,
mainAxisSpacing: 0.0,
crossAxisSpacing: 0.0,
childAspectRatio: 0.7,
),
delegate: SliverChildBuilderDelegate(
(BuildContext context, int index) {
return GestureDetector(
onTap: () {
print(data[index]['adid']);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ProductDetailsScreen(data[index]['adid'])));
},
child: Container(
margin: EdgeInsets.all(5),
decoration:
BoxDecoration(border: Border.all(color: Colors.grey)),
child: Padding(
padding: const EdgeInsets.all(10),
child: Column(
children: <Widget>[
Expanded(
flex: 5,
child: Align(
alignment: Alignment.center,
child: Image.network(
data[index]['adcoverimg'],
fit: BoxFit.cover,
),
),
),
SizedBox(
height: 10,
),
Expanded(
flex: 2,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Text(
'\u20B9' + data[index]['ads_price'],
style: TextStyle(fontWeight: FontWeight.bold),
),
Text(
data[index]['adname'],
style: TextStyle(fontWeight: FontWeight.w500),
maxLines: 1,
),
Text(
data[index]['addesc'],
maxLines: 1,
),
Row(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Icon(
Icons.location_on,
size: 18,
),
Text(data[index]['ads_location'])
],
)
],
),
)
],
),
),
),
);
},
childCount: data == null ? 0 : data.length,
),
),
],
),
),
);
}
And this is how I'm fetching the data from the server
Future<String> getProducts() async {
String url = Constant.productsUrl;
Map<String, String> headers = {'Content-Type': 'application/json'};
final response = await http.get(url, headers: headers);
setState(() {
var jsonResponse = json.decode(response.body);
data = jsonResponse['record'];
});
}
And this is my URL http://url.com/Web_Api/viewads/startindex/limit/cityname
On some devices, the maps display fine. However, some times, when I scroll to the very bottom and scroll up slowly, the map overlap App Bar instead of start disappearing from my view (as the other widgets).
I've tested it in more than 4 different devices and simulators, and nothing happens. However it does happen on my friend's smartphone, I don't know why. Have anyone ever saw this bug? [screenshot of the bug][1]
children: <Widget>[
Stack(
children: <Widget>[
Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.width,
child: GoogleMap(
onMapCreated: (mapController) {
_mapController = mapController;
try {
_addMarker();
} catch (e) {
print(e.toString());
_scaffoldKey.currentState.showSnackBar(
buildSnackBar('Request location error'));
}
},
markers: _markers,
mapType: MapType.normal,
scrollGesturesEnabled: false,
initialCameraPosition: CameraPosition(target: LatLng(_lead.latitude, _lead.longitude)),
)),
Column(
children: <Widget>[
Table(
columnWidths: {0: FlexColumnWidth(1), 1: FlexColumnWidth(1)},
children: [
_buildTableRow('Installation Address:',
_lead.installationAddressLineOne,
color: COLOR_LIGHT_GREY.withAlpha(150))
],
),
addDivider(),
Text(
'Roof Location',
style:
TextStyle(fontWeight: FontWeight.w600, color: Colors.red),
),
],
),
],
),
Container(
child: ButtonTheme(
height: 32,
minWidth: double.infinity,
shape:
RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
buttonColor: Colors.indigo,
padding: EdgeInsets.only(left: 10, right: 10),
child: RaisedButton(
child: Text(
'Route to lead',
style: TextStyle(color: Colors.white),
),
onPressed: () {
final url =
'https://www.google.com/maps/dir/?api=1&destination=${_lead.latitude},${_lead.longitude}';
launch(url);
},
),
),
)
],
);
[1]: https://i.stack.imgur.com/lAmL9.png