How to change width of datacells dynamically in flutter DataTable? - flutter

I have found in this link a way to place data from JSON dynamically to DataTable() widget:
Dynamically display JSON data in data table layout in flutter
In that post he has ColumnWidths in the json but he doesn't show how he changes width of the individual datacell columns.
I have used that example for myself as well and I wonder how I can use the column widths from json as well to change width of individual data cells?
This is the json I am using:
[
{
"table-data": [
{
"table-label-data": "SL.´Customer´Balance Qty´Amount´Oldest / Recent ",
"table-row-list": [
{
"table-row-data": "1. ´ABD ´14 / 14.60´11,090´313 / 313"
},
{
"table-row-data": "1. ´ABD ´14 / 14.60´11,090´313 / 313"
}
],
"table-cell-widths": "40´168´96´96´108"
}
]
}
]
This is the model I am using:
import 'dart:ui';
class TableModel {
TableModel(this.labelData, this.rowData);
List<String> labelData;
List<List<String>> rowData;
factory TableModel.fromJson(Map<String, dynamic> json) {
return TableModel(
json['table-data'][0]["table-label-data"].split('´').toList(),
buildRowData(json),
);
}
}
List<List<String>> buildRowData(Map<String, dynamic> json) {
List<List<String>> rowDataCollection = [];
json['table-data'][0]["table-row-list"].forEach((rows) {
rowDataCollection.add(rows['table-row-data'].split('´').toList());
});
return rowDataCollection;
}
For the view as you can see i use a variable width inside SizedBox widget to change width, but it is now changing all widths but i want to change individual data cell widths based on json.
This is the view:
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:test_project/controllers/getters/get_test.dart';
import '../models/table_model.dart';
import '../models/test_model.dart';
class AppView2 extends StatefulWidget {
const AppView2({
Key? key,
}) : super(key: key);
#override
_AppViewState createState() => _AppViewState();
}
class _AppViewState extends State<AppView2> {
Future<void> generateList() async {
String responseBody =
await rootBundle.loadString("assets/tableJsonData.json");
var list = await json.decode(responseBody).cast<Map<String, dynamic>>();
return await list
.map<TableModel>((json) => TableModel.fromJson(json))
.toList();
}
#override
void initState() {
generateList();
super.initState();
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
appBar: AppBar(
title: Text('DataTable'),
),
body: FutureBuilder(
future: generateList(),
builder: (context, AsyncSnapshot snapShot) {
if (snapShot.data == null ||
snapShot.connectionState == ConnectionState.waiting ||
snapShot.hasError ||
snapShot.data.length == 0) {
return Container(
child: Center(child: CircularProgressIndicator()),
);
} else {
return ListView.builder(
shrinkWrap: true,
scrollDirection: Axis.vertical,
itemCount: snapShot.data.length,
itemBuilder: (BuildContext context, int index) {
final TableModel table = snapShot.data[index];
return SingleChildScrollView(
scrollDirection: Axis.horizontal,
child: DataTable(
columns: table.labelData.map<DataColumn>((e) {
var columnName = e;
return DataColumn(
label: Text(
columnName,
));
}).toList(),
rows: table.rowData.map<DataRow>((e) {
return DataRow(
cells: e.map<DataCell>((e) {
var dataCell = e;
dynamic width;
return DataCell(SizedBox(
width: width,
child: Text(
dataCell,
),
));
}).toList());
}).toList(),
),
);
});
}
},
)));
}
}

Related

Flutter - Autocomplete with displaying selected item information on screen

I'm trying to implement Autocomplete text, then display records related to selected item. For example, If I select 'IBM' from below example, display records related to IBM in a listview.
Autocomplete is working as expected but upon selecting the item list view is not generating. i.e. in onSelected(), widget buildPositions() should be corrected, any help would be highly appreciated.
import 'package:e2/Models/model_positions.dart';
import 'package:flutter/material.dart';
class ContractControl extends StatefulWidget {
const ContractControl({super.key});
#override
State<ContractControl> createState() => _ContractControlState();
}
class _ContractControlState extends State<ContractControl> {
List<dynamic> _selectedItems = [];
static const List<String> listItems = <String>['TCS', 'IBM', 'WIPRO'];
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text("Contract Control"),
centerTitle: true,
//automaticallyImplyLeading: false,
),
body: Autocomplete(optionsBuilder: (TextEditingValue textEditingValue) {
if (textEditingValue.text == '') {
return const Iterable<String>.empty();
}
return listItems.where((String item) {
return item.contains(textEditingValue.text.toUpperCase());
});
}, onSelected: (String item) {
buildPositions(item);
}));
}
## *****************need correction here ******************
Widget buildPositions(String item) {
return Container(
child: FutureBuilder<List<dynamic>>(
future: ModelsPositions().detailedContractControlData(item),
builder: (context, snapshot) {
if (snapshot.hasData) {
List<dynamic> positions = snapshot.data ?? [];
return ListView.builder(
itemCount: positions.length,
itemBuilder: (context, index) {
return Card(
child: Row(children: [
Checkbox(
value: _selectedItems.contains(positions[index]),
onChanged: (value) {
setState(() {
if (value == null) {
return null;
}
if (value) {
_selectedItems.add(positions[index]);
} else {
_selectedItems
.removeWhere((item) => item == positions[index]);
}
});
},
),
]));
},
);
} else if (snapshot.hasError) {
return Center(
child: Text('Failed to fetch Positions Summary'),
);
}
return Center(
child: CircularProgressIndicator(),
);
},
),
);
}
}

How to add List Item to FutureBuilder ListView without reloading the data from remote server? [Flutter]

I'm new in flutter, I'd like to know how to add an item list dynamically to ListView without reloading data in FutureBuilder.
When I add an item to the ListView, it duplicate the list and then added the item to that list.
The Following code, include Model clas called Job.
JobListView is a stateful widget that include the dynamic ListView.
import 'dart:convert';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart';
class Job {
#required
String company;
String description;
String employmentType;
int id;
String location;
String position;
List<String> skillsRequired;
Job(
this.company,
this.description,
this.employmentType,
this.id,
this.location,
this.position,
this.skillsRequired);
Job.fromJson(Map<String, dynamic> json) {
company = json['company'];
description = json['description'];
employmentType = json['employmentType'];
id = json['id'];
location = json['location'];
position = json['position'];
if (json['skillsRequired'] != null) {
skillsRequired = new List<String>();
json['skillsRequired'].forEach((v) {
skillsRequired.add(v);
});
}
}
}
class JobListView extends StatefulWidget {
#override
_JobListViewState createState() => _JobListViewState();
}
class _JobListViewState extends State<JobListView> {
List<Job> data = List<Job>();
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Job>>(
future: _getJob(),
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
return _listViewFormat(data);
} else if (snapshot.hasError) {
return Container();
}
return Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
},
) ,
floatingActionButton: (FloatingActionButton(child: Icon(Icons.add),onPressed: (){
setState(() {
var j = Job("CompanyX","Eng.5 position","Full-time",0,"Cairo","Senior",null);
data.add(j);
});
},)),
);
}
}
ListView _listViewFormat(List<Job> data) {
return ListView.builder(
itemCount: data.length,
itemBuilder: (context, index) {
return _tile(data[index].position, data[index].description, Icons.work);
});
}
ListTile _tile(String title, String subtitle, IconData iconData) {
return ListTile(
title: Text(title, style: TextStyle(fontSize: 20)),
subtitle: Text(
subtitle,
style: TextStyle(fontSize: 12),
),
leading: Icon(iconData),
trailing: Icon(Icons.arrow_right),
);
}
Future<List<Job>> _getJob() async {
String baseUrl = 'https://mock-json-service.glitch.me';
var response = await get(baseUrl);
if (response.statusCode == 200) {
List jsonResponse = json.decode(response.body);
return jsonResponse.map((job) => new Job.fromJson(job)).toList();
}
}
Check out this more explanation How to deal with unwanted widget build?
if future changes you will see changes
Move _getJob method inside initState like this:
class _JobListViewState extends State<JobListView> {
List<Job> data = List<Job>();
Future<List<Job>> getJobFuture;
#override
void initState() {
super.initState();
getJobFuture = _getJob();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: FutureBuilder<List<Job>>(
future: getJobFuture,
builder: (context, snapshot) {
if (snapshot.hasData) {
data = snapshot.data;
return _listViewFormat(data);
} else if (snapshot.hasError) {
return Container();
}
return Center(
child: Container(
width: 50,
height: 50,
child: CircularProgressIndicator(),
),
);
},
) ,
floatingActionButton: (FloatingActionButton(child: Icon(Icons.add),onPressed: (){
setState(() {
var j = Job("CompanyX","Eng.5 position","Full-time",0,"Cairo","Senior",null);
data.add(j);
});
},)),
);
}
}

How to Refresh the UI in ListView.Builder using flutter GetX when data is changed?

I'm refactoring my app to GetX state management for less boilerplate code.
I make the Controller and the API provider (code below).
But when I want to refresh the data (Manually too) it won't change.
home_page.dart
class HomeUI extends GetView<HomeController> {
...
GetX<HomeController>(
initState: (state) => Get.find<HomeController>().getAll(),
builder: (_) {
return _.goalList.length < 1 ||
_.goalList == null
? Center(
child: Column(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
CircularProgressIndicator(),
Text('0 goals found, please wait',
style: Theme.of(context)
.textTheme
.headline6
.copyWith(
color: kTextColor))
],
))
: ListView.builder(
itemBuilder: (context, index) {
GoalModel goalModel =
GoalModel.fromMap(
_.goalList[index]);
return ListTile(
title: Text(goalModel.text),
subtitle:
Text(goalModel.updated_at),
);
});
}
home_controller.dart
class HomeUI extends GetView<HomeController> {
...
class HomeController extends GetxController {
final MyRepository repository = MyRepository();
final _goalsList = RxList();
get goalList => this._goalsList.value;
set goalList(value) => this._goalsList.value = value;
getAll() {
repository.getAll().then((data) {
this.goalList = data;
update();
});
}
delete(id) {
repository.delete(id).then((message) {
this.goalList;
return message;
});
}
add(goal) {
repository.add(goal).then((data) {
this.goalList = data;
});
}
edit(editedItem, text, achievementDate) {
repository.edit(editedItem, text, achievementDate).then((data) {
this.goalList = data;
});
}
}
goals_repository.dart
class MyRepository {
final MyApiClient apiClient = MyApiClient();
getAll() {
return apiClient.getAll();
}
delete(id) {
return apiClient.deleteGoal(id);
}
edit(editedItem, text, achievementDate) {
return apiClient.updateGoal(editedItem, text, achievementDate);
}
add(goal) {
return apiClient.postGoal(goal);
}
}
api.dart (getAll() method)
getAll() async {
try {
var _token = await _sharedPrefsHelper.getTokenValue();
var response = await httpClient.get(baseUrl, headers: {
'Authorization': 'Bearer $_token',
});
if (response.statusCode == 200) {
print('json decode response is: ${json.decode(response.body)}');
return json.decode(response.body);
} else
print('erro -get');
} catch (error) {
print(error);
}
}
I followed this article to make the implementation:
getx_pattern
After updating manually your list, do:
this._goalsList.refresh()
After that your UI will be updated
Just Wrap the ListView.builder list with Obx or Getx. For widgets that are not in the list, you can wrap them individually with obx or getx.
Example:
Obx(() => ListView.builder(
physics: const NeverScrollableScrollPhysics(),
itemCount: item.length,
shrinkWrap: true,
itemBuilder: (BuildContext context, int index) {
return Card()...
},
),
),
Obs Getx variables are only observed within an Obx or Getx as stated above. You need to wrap them up. Just be careful not to use Obx / Getx when there are no variables observed inside, as it will generate an error.
This answer is for #mjablecnik's comment:
class Other extends StatelessWidget {
final Counter c = Get.find();
final _chars = 'AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz1234567890';
final Random _rnd = Random();
/* ---------------------------------------------------------------------------- */
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: Obx(() => ListView.builder(
scrollDirection: Axis.vertical,
padding: EdgeInsets.all(10),
itemCount: c.testList.length,
itemBuilder: (context, index) => Card(
color: Colors.amber[600],
child: Padding(
padding: const EdgeInsets.all(10),
child: Center(
child: Text('${c.testList[index]}'),
),
),
),
)),
),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: () => c.addToList(getRandomString(15)),
),
);
}
/* ---------------------------------------------------------------------------- */
// source: https://stackoverflow.com/questions/61919395/how-to-generate-random-string-in-dart
String getRandomString(int length) => String.fromCharCodes(Iterable.generate(
length, (_) => _chars.codeUnitAt(_rnd.nextInt(_chars.length))
)
);
}
Update 1:
Another little change I did was for the controller:
class Counter extends GetxController {
var count = 0.obs;
var testList = <String>['test1', 'test2'].obs;
/* ---------------------------------------------------------------------------- */
void incremenent() => count++;
/* ---------------------------------------------------------------------------- */
void addToList(String item) {
print('adding: $item');
testList.add(item);
}
}

how to scroll through the two views combined in flutter

In the video and picture below, the horizontal and vertical widgets are arranged in order.
If you scroll through this, each widget will move separately, just like a video.
I want to make this move at once.
please enter the videoLink
https://firebasestorage.googleapis.com/v0/b/coody-f21eb.appspot.com/o/%E1%84%92%E1%85%AA%E1%84%86%E1%85%A7%E1%86%AB%20%E1%84%80%E1%85%B5%E1%84%85%E1%85%A9%E1%86%A8%202020-09-28%20%E1%84%8B%E1%85%A9%E1%84%8C%E1%85%A5%E1%86%AB%208.06.33.mov?alt=media&token=8a9d3fd0-1256-4d92-9a57-
please enter Imglink
https://firebasestorage.googleapis.com/v0/b/coody-f21eb.appspot.com/o/KakaoTalk_Photo_2020-09-28-08-15-13.jpeg?alt=media&token=77cd7fba-5b62-4d68-b760-8
import 'package:flutter/material.dart';
import 'element_homepage/contents_carousel.dart';
import 'element_homepage/gridView_of_homepage.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:cloud_firestore/cloud_firestore.dart';
import 'product_detail.dart';
class HomeScreen extends StatefulWidget {
var stopTrigger = 1;
var unchanging ;
List<bool>bool_list_each_GridSell =[];
List<String> styleList = [];
var tf_copy = [];
final FirebaseUser user;
HomeScreen(this.user);
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
void initState() {
super.initState();
if(widget.stopTrigger == 1){
setState(() {
widget.unchanging = Firestore.instance.collection("uploaded_product").snapshots();
});
}
}
#override
Widget build(BuildContext context) {
return Container(
child: Scaffold(
appBar: AppBar(title:Text("logo --- rec --- menu")),
body: _bodyBuilder()
),
);
}
Widget _bodyBuilder() {
return Column(
children: [
ContentsCarousel(),
_gridBuilder()
],
);
}
Widget _gridBuilder() {
return Expanded(
child: StreamBuilder <QuerySnapshot>(
stream: _commentStream(),
builder: (BuildContext context, AsyncSnapshot snapshot){
if(!snapshot.hasData){
return Center(child: CircularProgressIndicator());
}
var items = snapshot.data?.documents ??[];
var fF = items.where((doc)=> doc['style'] == "오피스룩").toList();
var sF = items.where((doc)=> doc['style'] == "로맨틱").toList();
var tF = items.where((doc)=> doc['style'] == "캐주얼").toList();
fF.addAll(sF);
fF.addAll(tF);
widget.tf_copy.addAll(fF);
if(widget.stopTrigger == 2 ){
fF.shuffle();
widget.unchanging = fF;
}
return GridView.builder(
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 3,
childAspectRatio: 0.6,
mainAxisSpacing: 2.0,
crossAxisSpacing: 2.0,),
itemCount: fF.length,
itemBuilder: (BuildContext context, int index) {
for(var i=0; i<fF.length; i++){
widget.bool_list_each_GridSell.add(false);
}
return _buildListItem(context,widget.unchanging[index]);
}
);
},
),
);
}
Widget _buildListItem(context, document) {
return
InkWell(
onTap: (){
Navigator.push(context, MaterialPageRoute(builder: (context){
return ProductDetail(widget.user, document);
}));
},
child: Image.network(
document['thumbnail_img'],
fit : BoxFit.cover)
);
}
Stream<QuerySnapshot> _commentStream() {
widget.stopTrigger +=1;
if(widget.stopTrigger == 2 ){
return widget.unchanging;
}
}
}
I see you're attempting to achieve a behavior where a scroll on the GridView results in a scroll on the whole screen.
As the ContentsCarousel() and _gridBuilder() are in a Column, this behaviour cannot be achieved.
What I would suggest is wrapping your Column with a SingleChildScrollView widget.

How to add list view builder inside another list view builder?

This is my list view widget. There are two list view builders, one inside another. I added shrinkWrap property and physics property. Nothing is rendered.I have another doubt when to use list view, single child scroll view and custom scroll view.
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: AppBar(
title: Text("Listviews"),
backgroundColor: Colors.blue,
),
body: ListView.builder(
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
if (data[index]["type"] == "single") {
var innerData = data[index]["data"];
return Container(
child: ListView.builder(
shrinkWrap: true,
itemCount: innerData == null ? 0 : innerData.length,
itemBuilder: (BuildContext context, int index) {
String title = innerData[index]["title"];
return Text("$title");
},
),
);
}
},
),
);
}
This is the output screen
This is my json response:
[
{
"type": "single",
"data": [
{
"title": "Fresh Vegetables"
},
{
"title": "Fresh Fruits"
},
{
"title": "Cuts and Sprouts"
},
{
"title": "Exotic Center"
}
]
}
]
I want to do like the flipkart home page. I want to build widgets based on the response. What is the widgets should I use?
Use physics property inside listViewBuilder
shrinkWrap: true,
physics: ClampingScrollPhysics(), /// listView scrolls
I some how copy pasted your code and made some modifications and it worked for me just check the code i have modified :
I have loaded your json locally mentioned below:
[
{
"type": "single",
"data": [
{
"title": "Fresh Vegetables"
},
{
"title": "Fresh Fruits"
},
{
"title": "Cuts and Sprouts"
},
{
"title": "Exotic Center"
}
]
}
]
According to you json class i have created a model class where you can access the specific object from the listview using this model class :
// To parse this JSON data, do
//
// final data = dataFromJson(jsonString);
import 'dart:convert';
List<Data> dataFromJson(String str) => List<Data>.from(json.decode(str).map((x) => Data.fromJson(x)));
String dataToJson(List<Data> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));
class Data {
String type;
List<Datum> data;
Data({
this.type,
this.data,
});
factory Data.fromJson(Map<String, dynamic> json) => Data(
type: json["type"],
data: List<Datum>.from(json["data"].map((x) => Datum.fromJson(x))),
);
Map<String, dynamic> toJson() => {
"type": type,
"data": List<dynamic>.from(data.map((x) => x.toJson())),
};
}
class Datum {
String title;
Datum({
this.title,
});
factory Datum.fromJson(Map<String, dynamic> json) => Datum(
title: json["title"],
);
Map<String, dynamic> toJson() => {
"title": title,
};
}
And just check the main file where i have made the changes :
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sample_testing_project/models.dart';
main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Data> data = List();
bool _isLoading = false;
#override
void initState() {
// TODO: implement initState
super.initState();
loadYourData();
}
Future<String> loadFromAssets() async {
return await rootBundle.loadString('json/parse.json');
}
loadYourData() async {
setState(() {
_isLoading = true;
});
// Loading your json locally you can make an api call, when you get the response just pass it to the productListFromJson method
String jsonString = await loadFromAssets();
final datamodel = dataFromJson(jsonString);
data = datamodel;
setState(() {
_isLoading = false;
});
}
#override
Widget build(BuildContext context) {
return MaterialApp(
home: new Scaffold(
appBar: AppBar(
title: Text("Listviews"),
backgroundColor: Colors.blue,
),
body: ListView.builder(
shrinkWrap: true,
itemCount: data == null ? 0 : data.length,
itemBuilder: (BuildContext context, int index) {
if (data[index].type == "single") {
var innerData = data[index].data;
return Container(
child: ListView.builder(
shrinkWrap: true,
itemCount: innerData == null ? 0 : innerData.length,
itemBuilder: (BuildContext context, int index) {
String title = innerData[index].title;
return Container(
width: MediaQuery.of(context).size.width,
child: Card(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text("$title"),
),
),
);
},
),
);
}
},
),
),
);
}
}