flutter
flutter copied to clipboard
[two_dimensional_scrollables] change the width of columns without rebuilding the cells.
Use case
Can you provide a controller that allows me to change the width of columns without rebuilding the cells, but triggers a manual refresh of the cell layout?
I want to implement this feature
Proposal
I want to implement this feature
This doesn't sound like a feature request, but it could be an implementation or package issue. Could you please share a minimal sample code for this?
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:two_dimensional_scrollables/two_dimensional_scrollables.dart';
void main() {
runApp(const TableExampleApp());
}
/// A sample application that utilizes the TableView API.
class TableExampleApp extends StatelessWidget {
/// Creates an instance of the TableView example app.
const TableExampleApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Table Example',
theme: ThemeData(
useMaterial3: true,
),
home: const TableExample(),
);
}
}
/// The class containing the TableView for the sample application.
class TableExample extends StatefulWidget {
/// Creates a screen that demonstrates the TableView widget.
const TableExample({super.key});
@override
State<TableExample> createState() => _TableExampleState();
}
class _TableExampleState extends State<TableExample> {
late final ScrollController _verticalController = ScrollController();
int _rowCount = 20;
double threeColumnWidth = 50.0;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Table Example'),
),
body: Padding(
padding: const EdgeInsets.symmetric(horizontal: 50),
child: TableView.builder(
verticalDetails: ScrollableDetails.vertical(controller: _verticalController),
cellBuilder: _buildCell,
columnCount: 20,
columnBuilder: _buildColumnSpan,
rowCount: _rowCount,
rowBuilder: _buildRowSpan,
),
),
persistentFooterButtons: <Widget>[
Slider(
value: threeColumnWidth,
max: 500,
onChanged: (newValue) {
// change three column width
// need a controller to change column width and don't rebuild cells
setState(() {
threeColumnWidth = newValue;
});
},
),
],
);
}
TableViewCell _buildCell(BuildContext context, TableVicinity vicinity) {
return TableViewCell(
child: RepaintBoundary(
child: TableCell(vicinity: vicinity),
),
);
}
TableSpan _buildColumnSpan(int index) {
const TableSpanDecoration decoration = TableSpanDecoration(
border: TableSpanBorder(
trailing: BorderSide(),
),
);
if (index == 3) {
return TableSpan(
foregroundDecoration: decoration,
extent: FixedTableSpanExtent(threeColumnWidth),
onEnter: (_) => print('Entered column $index'),
);
}
return TableSpan(
foregroundDecoration: decoration,
extent: const FixedTableSpanExtent(100),
onEnter: (_) => print('Entered column $index'),
);
}
TableSpan _buildRowSpan(int index) {
final TableSpanDecoration decoration = TableSpanDecoration(
color: index.isEven ? Colors.purple[100] : null,
border: const TableSpanBorder(
trailing: BorderSide(
width: 3,
),
),
);
return TableSpan(
backgroundDecoration: decoration,
extent: const FixedTableSpanExtent(65),
cursor: SystemMouseCursors.click,
);
}
}
class TableCell extends StatefulWidget {
const TableCell({super.key, required this.vicinity});
final TableVicinity vicinity;
@override
State<TableCell> createState() => _TableCellState();
}
class _TableCellState extends State<TableCell> {
@override
Widget build(BuildContext context) {
print("build ${widget.vicinity}");
return Center(
child: Text('Tile c: ${widget.vicinity.column}, r: ${widget.vicinity.row}'),
);
}
@override
void didUpdateWidget(covariant TableCell oldWidget) {
// TODO: implement didUpdateWidget
super.didUpdateWidget(oldWidget);
return;
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
}
}
I want change column width and don't rebuild cells
I think this is working as intended since you refreshed whole TableView with setState call on Slider value changes; then cell widget will be refreshed as well. I'm not sure if there is a way to prevent cells from rebuilding.
More specifically, could you share what the use case this request needs? (to optimize performance or to implement something else?)
I need to to optimize performance, because when cell is other's widget like checkbox, image,when change column with real time, it gets really stuck.
when the table like this.
I think when change the column width(or row height), don't rebuild cells.
I dont know how to change column width(or row height) and not need refreshed TableView, please let me know if there is such a method. If there have a controller relayout cells, will improve performance. Also, can rewrite the layoutChildSequence function, animation effects can be achieved.
Thanks for the update. Marking this as a feature request with the use case above.
Hi @leavky, I am not sure I understand the request to resize without rebuilding, wouldn't the cells need to be rebuilt to reflect the new dimensions?
@Piinks ,when change the target's column width, not need rebuild other column's cell. when change column with real time, it gets really stuck. when change the target's column width, other column's cell just relayout, not need to rebuild.
just like this,
I have another question, i want eidt cell, but the cell's space is small, so i need a bigger cell to edit cell content. like this
But i found the child's drawing order is fixed, is there have a method that let target cell paint later. thanks!
I want 1-1 on the top of 1-2,
It seems that needs to be rebuilt too in the example you show because the text is getting shorter and needs to show an overflow effect.
As @Piinks says here:
Hi @leavky, I am not sure I understand the request to resize without rebuilding, wouldn't the cells need to be rebuilt to reflect the new dimensions?
The cells needs to be rebuilt due to this code:
final BoxConstraints cellConstraints = BoxConstraints.tightFor(
width: mergedColumnWidth ?? standardColumnWidth,
height: mergedRowHeight ?? standardRowHeight,
);
cell.layout(cellConstraints); // this line
You can find this in the table.dart line 754 (at the moment of writing this). As you can see, the cell constraints are calculated keeping in mind the column width and then the cell is layout.
EDIT: I think what you can do is (if you use a state management library like Riverpod) is create constant widgets for each cell, for example, following the video you added in your previous comment, in the tags column, you render a
ProviderScope(
overrides: [
tagsProvider.overrideWithValue(/*etc etc*/)
],
child: TagsColumn(),
)
widget
@tomasweigenast ,I tried it and it was the right way, thanks you. And the cell paint order can override in paint.
@tomasweigenast ,I tried it and it was the right way, thanks you. And the cell paint order can override in paint.
What did you do? Did you try using riverpod?
@leavky it sounds like your issue may have been resolved? Can we close this then?
@tomasweigenast ,I tried it and it was the right way, thanks you. And the cell paint order can override in paint.
What did you do? Did you try using riverpod?
yes, i use riverpod.
return TableViewCell(
child: ProviderScope(
overrides: [
tableVicinityIndexProvider.overrideWithValue((vicinity.xIndex, vicinity.yIndex)),
],
child: const TableCell(),
),
);
@leavky it sounds like your issue may have been resolved? Can we close this then?
yes, thank you.
This thread has been automatically locked since there has not been any recent activity after it was closed. If you are still experiencing a similar issue, please open a new bug, including the output of flutter doctor -v and a minimal reproduction of the issue.