A Flutter chart display method with slidable and mergeable cells
By creating data models and using basic components in Flutter, the high calculation line of basic components, setting a form framework, and drawing the header and unit view view, solving the problem that the existing Flutter components cannot support complex chart display requirements, and realized sliding, merger and fixed fixed Function.
Patent Information
- Application Number
- CN202411253745.9
- Authority / Receiving Office
- CN · China
- Patent Type
- Patents(China)
- Current Assignee / Owner
- Filing Date
- 2024-09-09
- Publication Date
- 2025-01-24
- Estimated Expiration
- 2044-09-09
AI Technical Summary
The basic components of existing Flutter cannot support cell merging, horizontal and vertical sliding viewing, table header fixation, view cell content and other display requirements.
By obtaining all the parameters of the target table, create a data model, and use the basic components provided by Flutter to calculate the height, build an overall framework, draw a header view, a single view, and a merger unit view, nested SinglechildScrollView component to achieve sliding and linkage Effect.
The functions of supporting cell merger, horizontal longitudinal sliding viewing, fixing of the header, and viewing cell content meet the needs of complex chart display. The usage is simple and practical.
Smart Images

Figure CN118780255B_ABST
Abstract
Description
Technical Field
[0001] The present invention relates to the field of chart drawing, and specifically provides a Flutter chart display method with slidable and mergable cells. Background Art
[0002] In the development of Flutter mobile terminals, if you want to display chart data, Flutter provides the original component Table. By setting children (row and column data), columWidths (width of each column), defaultColumnWidth (default column width), textDirection (reading order), defaultVerticalAligment (alignment), and textBaseline (horizontal line for text alignment), you can achieve simple chart data display.
[0003] However, in the development of Flutter mobile applications (Android, iOS), there are usually requirements for chart display that supports cell merging, horizontal and vertical sliding viewing, fixed headers, and viewing cell contents. The original component Table has certain limitations in actual applications and cannot meet the above requirements. Summary of the invention
[0004] In order to overcome the above defects, the present invention is proposed to solve the problem that the basic components of the existing Flutter cannot support display requirements such as cell merging, horizontal and vertical sliding viewing, table header fixing, and viewing cell contents.
[0005] The present invention proposes a Flutter chart display method with slidable and merging cells, comprising the following steps:
[0006] Obtain all parameters of the target table and create a data model required for drawing a chart. The first row of data in the target table is defined as a header, and the second row and below of the target table are defined as content.
[0007] Calculate the height tempHeight of each row in the target table and store the height of each row in a height set Map;
[0008] Build the overall framework of the target table according to the height collection Map, define two SingleChildScrollView components, namely the header SingleChildScrollView component and the content SingleChildScrollView component, and create two ScrollControllers, namely headerScrollController and tableScrollController, respectively. The headerScrollController is used to monitor and control the header SingleChildScrollView, and the tableScrollController is used to monitor and control the content SingleChildScrollView.
[0009] Draw the header view of the target table, the single-row view of the content in the target table, and the merged cell view of the target table respectively, nest the drawn header view in the header SingleChildScrollView component, and nest all the single-row views of the content in the drawn target table in the content SingleChildScrollView component;
[0010] Use the Column component to fill the drawn header view, single row view and merged cell view in sequence in the overall frame of the target table.
[0011] Furthermore, the data model includes a default column width defaultColumnWidth, a special column width {n1:m1,n2:m2,...}, a data source for each row, and a data source for merged cells, wherein:
[0012] n1:m1 means that the width of the n1th column in the target table is m1, and n2:m2 means that the width of the n2th column in the target table is m2;
[0013] The data source of the row includes all row instance objects of the target table, each row instance object includes all cell instance objects in the row, and each cell instance object includes the text content, text style and background color in the cell;
[0014] The data source of the merged cell includes all the merged cell instance objects of the target table, each of which includes the upper left horizontal index value, upper left vertical index value, lower right horizontal index value, lower right vertical index value of the merged cell in the target table and the text content of the merged cell.
[0015] Further, the calculation of the height tempHeight of each row in the target table includes sequentially performing the following steps for each row in the target table:
[0016] Calculate the height of each cell in the current row;
[0017] Initially define the height tempHeight of the current row as 0, and compare it with the height of each cell in the current row in turn;
[0018] If the cell height is greater than tempHeight, assign the value of the cell height to tempHeight. If the cell height is not greater than tempHeight, retain the current tempHeight.
[0019] Further, the calculation of the height of each cell in the current row includes sequentially performing the following steps on each cell in the current row:
[0020] Get the text content of the current cell;
[0021] Use the TextPainter component to calculate the text height based on the text content, text display style, maximum cell width, and maximum number of text lines to get the current cell height.
[0022] Further, drawing the table header view includes performing the following steps for the row where the table header is located:
[0023] Get the current row instance object and the height of the current row;
[0024] Draw all cell views in the current row;
[0025] Put all cell views in a Row component, and use the Row component to display all cell views in the row in sequence horizontally.
[0026] Further, drawing a single-row view of the content in the target table includes sequentially performing the following steps for each row of the content in the target table:
[0027] Get the current row instance object, the row number of the current row, and the height of the current row;
[0028] Draw all cell views in the current row;
[0029] Put all cell views in a Row component, and use the Row component to display all cell views in the row in sequence horizontally.
[0030] Further, drawing all the cell views in the current row includes sequentially performing the following steps for each cell in the current row:
[0031] Get the current cell instance object, the row number of the current cell, the column number of the current cell, and the height of the row where the current cell is located;
[0032] Get the current cell width and height according to the row and column number of the current cell;
[0033] Call the obtained parameters to draw the cell, use the GestureDetector component to set the click event of the current cell, use the Container component to set the display style of the current cell, and use the Text component to display the text content of the current cell.
[0034] Further, drawing the merged cell view includes sequentially performing the following steps for each merged cell in the target table:
[0035] Get the current merged cell instance object;
[0036] Define the upper left corner coordinates (startX, starty) and lower right corner coordinates (endX, endY) of the current merged cell;
[0037] Traverse all columns from 0 to the horizontal index value of the upper left corner of the merged cell, calculate the sum of all column widths as startX, traverse all columns from 0 to the horizontal index value of the lower right corner of the merged cell, and calculate the sum of all column widths as endX;
[0038] Traverse all rows from 0 to the vertical index value of the upper left corner of the merged cell, calculate the sum of all row heights as startY, traverse all rows from 0 to the vertical index value of the lower right corner of the merged cell, and calculate the sum of all row heights as endY;
[0039] Calculate the difference between startX and endX to get the width of the current merged cell, and calculate the difference between startY and endY to get the height of the current merged cell;
[0040] Use the Stack component to draw the current merged cell, use the Container component to set the display style of the current merged cell, and use the Text component to display the text content of the current merged cell.
[0041] Working principle and beneficial effects of the present invention:
[0042] In the technical solution of the present invention, a data model is first created according to the parameters of the target table, and subsequent drawing is performed based on the data model. Then, the basic components provided by Flutter are used to build the overall framework by calculating the row height, draw the header view of the target table, the single-line view of the content in the target table, and the merged cell view of the target table, and fill all views into the framework. At the same time, the header of the table and the content of the table are nested in two SingleChildScrollView components respectively, and two scorllControllers are used for monitoring to realize the linkage between the header and the content. Finally, the functions of supporting cell merging, horizontal and vertical sliding viewing, header fixing, and viewing cell content are realized, which is simple to use and highly practical. BRIEF DESCRIPTION OF THE DRAWINGS
[0043] The disclosure of the present invention will become more easily understood with reference to the accompanying drawings. It is easy for those skilled in the art to understand that these drawings are only for illustrative purposes and are not intended to limit the scope of protection of the present invention. In addition, similar numbers in the figures are used to represent similar components, among which:
[0044] Figure 1 This is a schematic flow chart of the main steps of a Flutter chart display method for sliding and merging cells in the present invention;
[0045] Figure 2 It is a schematic diagram of the overall framework of the table in the present invention;
[0046] Figure 3 is a schematic diagram of the data class in the merged cell in the present invention;
[0047] Figure 4 It is a table schematic diagram of an implementation method of calculating row height in the present invention;
[0048] Figure 5 It is a schematic diagram of a table wrapped by the SingleChildScrollView component in the present invention;
[0049] Figure 6 is a schematic diagram of the cell drawing process in the present invention;
[0050] Figure 7 It is a schematic diagram of the process of drawing merged cells in the present invention. DETAILED DESCRIPTION
[0051] Some embodiments of the present invention are described below with reference to the accompanying drawings. It should be understood by those skilled in the art that these embodiments are only used to explain the technical principles of the present invention and are not intended to limit the protection scope of the present invention.
[0052] In the present invention, the original Flutter components are used, and a separate component is encapsulated through the proposed icon display method to simply and efficiently implement a table layout that can slide and merge cells on Flutter. Among them, the basic components used in the present invention are as follows:
[0053] 1. Use the TextPainter component provided by Flutter to calculate the height required to display the text content by setting the text content, text style (size, bold, and other attributes), maximum width of text display, maximum number of lines, and other information.
[0054] 2. Use the ScrollController component and SingleChildScrollView component provided by Flutter to control and monitor the sliding of table contents.
[0055] 3. Use the Stack component provided by Flutter to position each row in the entire table, each cell in its row, and each cell to be merged in the entire table.
[0056] Figure 1 This is a schematic diagram of the main steps of a Flutter chart display method for sliding and merging cells in the present invention. Figure 1 As shown, a Flutter chart display method for sliding and merging cells in this embodiment mainly includes the following steps.
[0057] Step 1: Data Preparation
[0058] Take the table that needs to be displayed through Flutter as the target table, obtain all the parameters of the target table, and create the data model required for drawing the chart according to the obtained parameters. This data model is for the convenience of subsequent direct calls.
[0059] Figure 2 It is a schematic diagram of the overall framework of the table in the present invention. Figure 2 As shown, the overall framework of the table consists of a header and rows. The header can be regarded as a special row. Specifically, the first row of data in the target table is defined as the header, and the second row and the following data (row 1, row 2, row 3) of the target table are defined as the content. The custom TableRowData class corresponds to the rows in the table. A row consists of multiple cells, and the custom CellData class corresponds to the cells in the table.
[0060] Furthermore, the data model in this embodiment is the data required to realize the drawing of the target table, which specifically includes:
[0061] (1) The default width of each column: defaultColumnWidth.
[0062] (2) Special column widths: stored in a set {n1:m1,n2:m2,…}, where n1:m1 means that the width of the n1th column in the target table is m1, and n2:m2 means that the width of the n2th column in the target table is m2. For example, {2:120.0,4:80.0} sets the width of the second column to 120.0 and the width of the fourth column to 80.0.
[0063] (3) Data source of the row:
[0064] The data source of a row is an array TableRowDatas. The data source of a row includes all row instance objects of the target table. Each row instance object includes all cell instance objects in the row. Each cell instance object includes the text content, text style (font size, font weight) and background color of the cell.
[0065] Example of a data source for a row:
[0066] [TableRowData(cells:[CellData(title:Cell 1,backColor:Colors.white),CellData(title:Cell 2,backColor:Colors.white)]),TableRowData(cells:[CellData(title:Cell 3,backColor:Colors.white),CellData(title:Cell 4,backColor:Colors.white)])];
[0067] Among them, TableRowData is the row data class in the target table, CellData is the cell data class in the corresponding row, title is the text content in the cell, and backColor is the background color of the cell.
[0068] In this embodiment, a "class" is a blueprint or template that defines the properties and behaviors of an object. A class is an abstract concept used to describe the common characteristics of a class of things. An "object" is an instance of a class. It is an actual individual with the properties and behaviors defined by the class. An object is a specific instantiation of a class.
[0069] (4) Data source of merged cells:
[0070] The data source of the merged cell is an array GroupCells. The data source of the merged cell includes all the merged cell instance objects of the target table. Each merged cell instance object includes the upper left horizontal index value, upper left vertical index value, lower right horizontal index value, lower right vertical index value of the merged cell in the target table and the text content of the merged cell.
[0071] Example of a data source for merged cells:
[0072] [GroupCell(leftTopX:1,leftTopY:1,rightBottomX:3,right
[0073] BottomY:3,title:Merged Cell 1),GroupCell(leftTopX:4,leftTopY:4,rightBottomX:7,rightBottomY:7,title:Merged Cell 2)].
[0074] Among them, GroupCell is the merged cell data class in the target table, leftTopX is the horizontal index value of the upper left corner, leftTopY is the vertical index value of the upper left corner, rightBottomX is the horizontal index value of the lower right corner, rightBottomY is the vertical index value of the lower right corner, and title is the text content in the merged cell.
[0075] Figure 3 Schematic diagram of the data class in the merged cell in the present invention. Figure 3 As shown in the figure, to merge the red cells into one cell, you need to know the upper left corner horizontal index value (1), the upper left corner vertical index value (1), the lower right corner horizontal index value (3), and the lower right corner vertical index value (3) of the merged cell. Use these four positions and the Stack component to draw the merged cells.
[0076] (5) Callback for clicking a cell: cellClick(int row, int column). Clicking a cell will result in this callback. The target table can know which cell was clicked and the caller can perform corresponding processing.
[0077] cellClick: (row, column) {
[0078] showToast('Clicked the cell in row ${row} and column ${column}');
[0079] },
[0080] (6) Callback for clicking a merged cell: cellClick(GroupCell). Clicking a merged cell will use this callback. When calling the target table, you can know which merged cell was clicked, and the caller can perform corresponding processing.
[0081] groupCellClick: (groupCell) {
[0082] showToast('Which merged cell was clicked');
[0083] },
[0084] In this embodiment, the callback of a cell click is a parameter passed in by calling the table component, and the callback of a merged cell click is also a parameter passed in by calling the table component.
[0085] Step 2: Calculate row height
[0086] Calculate the height tempHeight of each row in the target table and store the height of each row in a height set Map. The final result is in the following format: {0:80.0,1:130.0,2:95.7}.
[0087] First, the height of the text in the cell is calculated through the TextPainter component based on the text content, text style (font size, weight), maximum cell width, and maximum number of lines. The maximum cell width comes from columWidths and defaultColumnWidth. By getting the column where the cell is located, if columWidths contains the column, the width of the column is used. If it does not contain the column, the default width defaultColumnWidth is used. The maximum number of lines is currently set to infinity, that is, maxLines is passed in null. This is implemented through the following code:
[0088] double getTextContextSizeHeight(String text, TextStyle textStyle,double maxWidth, int maxLines) {
[0089] TextPainter textPainter = TextPainter(
[0090] locale: WidgetsBinding.instance.window.locale,
[0091] maxLines: null,
[0092] textDirection: TextDirection.ltr,
[0093] text: TextSpan(text: text, style: textStyle));
[0094] textPainter.layout(maxWidth: maxWidth);
[0095] return textPainter.height;
[0096] }
[0097] Then, traverse the row data source of the target table, and then traverse each cell in each row. Through the text content title of the cell, call the above method to calculate the text height in the cell to get the height of the cell. Initially define the row height tempHeight as 0.0. After calculating the height of a cell in the row, compare the cell height with tempHeight. If the cell height is greater than tempHeight, assign the cell height to tempHeight. If the cell height is not greater than tempHeight, retain the current tempHeight. After all cells in the row are traversed, the final tempHeight is the height of the row. This is implemented using the following code:
[0098] Map<int, double> rowHeights = {};
[0099] int rowIndex = 0;
[0100] for (var row in tableRowData) {
[0101] double height = 0.0;
[0102] int columnIndex = 0;
[0103] for (var cell in row.cells) {
[0104] double maxWidth = columnWidths.containsKey(columnIndex)
[0105] ?columnWidths[columnIndex]
[0106] : defaultColumnWidth;
[0107] double tempHeight = getTextContextSizeHeight(
[0108] cell.title,
[0109] cell.textStyle,
[0110] maxWidth, 100);
[0112] height = tempHeight > height ? tempHeight : height;
[0113] columnIndex++;
[0114] }
[0115] rowHeights.addAll({rowIndex: height + 30});
[0116] rowIndex++;
[0117] }
[0118] Figure 4 : is a schematic diagram of a table for calculating a row height in the present invention. Figure 4 As shown, you can see that the height of the second row is determined by the first cell in the row, and the height of the third row is determined by the second cell in the row. Use the basic component Stack to draw rows in sequence. When drawing a row, use the Stack component to draw each cell in the row.
[0119] Step 3: Build the overall framework of the table.
[0120] Build the overall framework of the target table based on the height collection Map, where the parameter Map passed in<int,double> rowHeights is the result of the row height calculated in the previous step, in a format such as {0:80.0,1:130.0,2:95.7}.
[0121] Figure 5 : is a schematic diagram of a table wrapped by the SingleChildScrollView component in the present invention. Figure 5As shown, define two SingleChildScrollView components, namely the header SingleChildScrollView component and the content SingleChildScrollView component. At the same time, create two ScrollControllers, namely headerScrollController and tableScrollController. The headerScrollController is used to monitor and control the header SingleChildScrollView, and the tableScrollController is used to monitor and control the content SingleChildScrollView. This is implemented in the following code:
[0122] Widget customerTable(Map<int, double> rowHeights) {
[0123] ScrollController tableScrollController = ScrollController();
[0124] ScrollController headerScrollController = ScrollController();
[0125] tableScrollController.addListener(() {
[0126] if(tableScrollController.offset < 0){
[0127] tableScrollController.jumpTo(0);
[0128] }
[0129] headerScrollController.jumpTo(tableScrollController.offset);
[0130] });
[0131] List <widget>rows = [
[0132] Column(
[0133] crossAxisAlignment: CrossAxisAlignment.start,
[0134] children:tableRowData.map((e)=>getRowData(e,tableRowData.indexOf(e), false, rowHeights)).toList(), ) ];
[0137] for (var element in groupCells) {
[0138] rows.add(groupCellWidget(element, false, rowHeights));
[0139] }
[0140] return Column(
[0141] children: [
[0142] headerWidget(headerScrollController, rowHeights),
[0143] Expanded(child: Container(
[0144] child: Stack(
[0145] children: [
[0146] ListView(
[0147] padding: EdgeInsets.zero,
[0148] children: [
[0149] Stack(
[0150] children: [
[0151] SingleChildScrollView(
[0152] controller: tableScrollController,
[0153] scrollDirection: Axis.horizontal,
[0154] child: Stack(
[0155] children: rows,
[0156] ),
[0157] ),
[0158] getFixedWidget(rowHeights),
[0159] ], )
[0161] ],
[0162] ),
[0163] ],
[0164] ),
[0165] ),),
[0166] ], );
[0168] }
[0169] The view elements of the row are generated by traversing the data source tableRowData of the row and stored in an array rows. The process of generating the row view is implemented in the code block getRowData. rows is to create the view of each row by traversing the data source of the target table row. And the data source groupCells of the cells that need to be merged is traversed to create the merged cell view.
[0170] Among them, tableScrollController is associated with SingleChildScrollVie:, which is the controller of the horizontal sliding component of the chart and is used to monitor the sliding sideways displacement. HeaderScrollController is associated with SingleChildScrollView of the header and is the controller of the horizontal sliding component of the header and is used to control the sideways displacement, so as to achieve the synchronous sliding of the header and the content in the horizontal direction and the effect of fixing the header when the content slides vertically.
[0171] Step 4: Draw the header view of the target table, the single-row view of the content in the target table, and the merged cell view of the target table respectively.
[0172] (1) A single-line view that draws content
[0173] First, pass in the following parameters of the row currently being drawn: row instance object rowData (rowData is a parameter name, that is, the row data instance that needs to be passed in when calling this method), the row number rowIndex, and the row height data rowHeights (tempHeight is a temporary variable for calculating the current row height, and the height of each row will eventually be stored in a global variable rowHeights)
[0174] Then iterate over all the cell instance objects in the row and draw the cell views. All the obtained cell views are placed in a Row component. The Row component can display multiple views in sequence in the horizontal direction. This is achieved through the following code:
[0175] Widget getRowWidget(TableRowData rowData, int rowIndex, bool fixed,
[0176] Map<int, double> rowHeights) {
[0177] return rowIndex == 0 ? Container() : Row(
[0178] children:rowData.cells.map((e)=>getCell(e,rowIndex,rowData.cells.indexOf(e), fixed, rowHeights)).toList(), );
[0180] }
[0181] All single-row views of the content in the drawn target table are nested in the content SingleChildScrollView component.
[0182] Furthermore, the above process of drawing cells is implemented in getCell.
[0183] Specifically, to draw a cell view, you need to first pass in the following parameters of the cell that is currently drawing: the cell instance object cellData, the row number rowIndex of the cell, the column number columnIndex of the cell, and the row height data rowHeights of the row where the cell is located. The process of calling the obtained parameters to draw the cell and generate a single row view in the content is implemented in the getRowWidget code block. The specific code is as follows:
[0184] Widget getCell(CellData cellData, int rowIndex, int columnIndex,bool fixed,Map<int, double> rowHeights) {
[0185] double? width = columnWidths.containsKey(columnIndex)
[0186] ?columnWidths[columnIndex]
[0187] : defaultColumnWidth;
[0188] double? height = rowHeights.containsKey(rowIndex)
[0189] ? rowHeights[rowIndex]
[0190] :defaultRowHeight;
[0191] bool empty = (fixed == false && columnIndex < fixColumn) ? true :false;
[0192] return GestureDetector(
[0193] onTap: cellClick(rowIndex,columnIndex),
[0194] / / Here onTap: is the cell click event. When clicking, the callback of the clicked cell is implemented, that is, cellClick. The returned parameters are the row (rowIndex) and column (columnIndex) of the cell.
[0195] child: Container(
[0196] height: height,
[0197] width: width,
[0198] alignment: Alignment.center,
[0199] padding: const EdgeInsets.all(5),
[0200] decoration: BoxDecoration(
[0201] color: rowIndex == 0 ? F7_COLOR : WHITE_COLOR,
[0202] border: empty
[0203] ? null
[0204] : Border(
[0205] top: const BorderSide(width: 1, color: EC_COLOR),
[0206] right: const BorderSide(width: 1, color: EC_COLOR),
[0207] bottom:BorderSide(width: 1, color: EC_COLOR),
[0208] left: BorderSide(width: columnIndex == 0 ? 1 : 0,color: EC_COLOR))),
[0209] child: Text(
[0210] empty ? '' : cellData.title,
[0211] maxLines: maxLines,
[0212] overflow: TextOverflow.ellipsis,
[0213] style: rowIndex == 0 ? FIRST_BOLD_15_TEXT_STYLE : FIRST_14_TEXT_STYLE,
[0214] textAlign: TextAlign.center,
[0215] ),
[0216] ), );
[0218] }
[0219] Figure 6 Schematic diagram of the cell drawing process in the present invention. Figure 6 As shown, by obtaining the cell width and height, use the GestureDetector clickable component to set the click event of the current cell, use the Container component to set the current cell display style, such as cell borders, rounded corners, etc., and use the Text component to display the text content of the current cell.
[0220] (2) Draw the header view
[0221] The table header can be understood as a fixed non-sliding row in the vertical direction. Compared with the single-row view in the target table content, the table header needs to be placed in a SingleChildScrollView component. Therefore, the process of drawing the table header is the same as that of the previous single-row view, which is also generated in getRowData. Then put the generated table header view in a SingleChildScrollView component (that is, the table header SingleChildScrollView component defined in the previous process), and the drawing of the table header is completed.
[0222] First, pass in the following parameters: the row instance object rowData of the table header, the headerScrollController component, and the row height data rowHeights of the table header. Then traverse all the cell instance objects of the table header and draw the cell view. Drawing the cell view here is the same as the above steps. All the cell views are placed in a Row component. The Row component can display multiple views in sequence in the horizontal direction. This is implemented in the following code:
[0223] Widget headerWidget(ScrollController sc1, Map<int, double> rowHeights) {
[0224] return Stack(
[0225] children: [
[0226] SingleChildScrollView(
[0227] controller: sc1,
[0228] scrollDirection: Axis.horizontal,
[0229] child:getHeaderRowData(tableRowData[0],0,false, rowHeights),),
[0230] getCell(tableRowData[0].cells.first,0,0,true,rowHeights),
[0231] ], );
[0233] }
[0234] (3) Draw the merged cell view
[0235] Traverse the data source groupCells of the merged cells of the target table and draw all the cells that need to be merged. The drawing process is implemented in groupCellWidget. The specific code is as follows:
[0236] for (var element in groupCells) {
[0237] rows.add(groupCellWidget(element, false, rowHeights));
[0238] }
[0239] First, pass in the following parameters of the merged cell that is currently drawing: the merged cell data class cell (in the method of drawing merged cells, cell is a parameter name, that is, the merged cell instance object to be drawn is passed in), the row height data rowHeights of all rows in the target table (tempHeight is a temporary variable for calculating the height of the current row, and the height of each row will eventually be stored in a global variable rowHeights), and then execute the following steps using the passed in parameters.
[0240] Define four variables, namely startX, startY, endX, and endY, with initial values of 0.0. These four variables are used to determine the upper left corner coordinates (starting point coordinates), lower right corner coordinates (end point coordinates), width, and height of the current merged cell.
[0241] Traverse all columns from 0 to the horizontal index value of the upper left corner of the merged cell, calculate the sum of all column widths as startX, traverse all columns from 0 to the horizontal index value of the lower right corner of the merged cell, and calculate the sum of all column widths as endX;
[0242] Traverse all rows from 0 to the vertical index value of the upper left corner of the merged cell, calculate the sum of all row heights as startY, traverse all rows from 0 to the vertical index value of the lower right corner of the merged cell, and calculate the sum of all row heights as endY;
[0243] Figure 7 Schematic diagram of the process of drawing merged cells in the present invention. Figure 7 As shown, the above process obtains the starting coordinates (startX, startY), end coordinates (endX, endY), width endX - startX, and height endY - startY of the merged cell. Then use the Stack absolute positioning component to draw the merged cell. The principle is the same as the drawing of the cell, except that an absolute positioning component is nested in the outermost layer. The specific code is as follows:
[0244] Widget groupCellWidget(GroupCell cell, bool fixed,Map <int, doublerowHeights) {
[0245] double startX = 0.0;
[0246] double startY = 0.0;
[0247] double endX = 0.0;
[0248] double endY = 0.0;
[0249] for (int x = 0; x < cell.rightBottomX; x++) {
[0250] double?width =
[0251] columnWidths.containsKey(x)?columnWidths[x]:defaultColumnWidth;
[0252] if (x < cell.leftTopX) {
[0253] startX += width!;
[0254] }
[0255] endX += width!;
[0256] }
[0257] for (int y = 0; y < cell.rightBottomY; y++) {
[0258] double? height =
[0259] rowHeights.containsKey(y) ? rowHeights[y] : defaultRowHeight;
[0260] if (y < cell.leftTopY) {
[0261] startY += height!;
[0262] }
[0263] endY += height!;
[0264] }
[0265] bool empty = (cell.leftTopX < fixColumn && fixed == false) ? true :false;
[0266] return Positioned(
[0267] left: startX,
[0268] top: startY,
[0269] child: GestureDetector(
[0270] onTap: groupCellClick(cell),
[0271] Here onTap: is the merged cell click event. When clicked, the callback of clicking the merged cell is implemented, that is, groupcCellClick, and the returned parameter is the merged cell instance object.
[0272] child:Container(
[0273] padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 10),
[0274] decoration: BoxDecoration(
[0275] color: WHITE_COLOR,
[0276] border: empty? null: Border(
[0277] right: const BorderSide(width: 1, color: EC_COLOR),
[0278] bottom: const BorderSide(width: 1, color: EC_COLOR),
[0279] left: BorderSide(width: cell.leftTopX == 1 ? 1 : 0, color:EC_COLOR))),
[0280] width: endX - startX,
[0281] height: endY - startY,
[0282] child: Center(
[0283] child: Text(empty ? '' : cell.title,textAlign:TextAlign.center,),
[0284] ),
[0285] ),
[0286] ), );
[0288] }
[0289] Step 5: Overall assembly.
[0290] In step 4 above, all the row views, header views, and merged cell views required in the table are drawn, and the basic drawing has been completed. Use the Column component to fill the drawn header view, single row view, and merged cell view in the overall frame of the target table in sequence. Get a table that can slide horizontally and vertically, merge cells, is clickable, and has a fixed header. This is achieved through the following code:
[0291] List <widget>rows = [
[0292] Column(
[0293] crossAxisAlignment: CrossAxisAlignment.start,
[0294] children:tableRowData.map((e)=>getRowWidget(e, tableRowData.indexOf(e), false, rowHeights)).toList(),) ];
[0296] for (var element in groupCells) {
[0297] rows.add(groupCellWidget(element, false, rowHeights));
[0298] }
[0299] return Column(
[0300] children: [
[0301] headerWidget(headerScrollController, rowHeights),
[0302] Expanded(child: Container(
[0303] child: Stack(
[0304] children: [
[0305] ListView(
[0306] padding: EdgeInsets.zero,
[0307] children: [
[0308] Stack(
[0309] children: [
[0310] SingleChildScrollView(
[0311] controller: tableScrollController,
[0312] scrollDirection: Axis.horizontal,
[0313] child: Stack(
[0314] children: rows,
[0315] ),
[0316] ),
[0317] getFixedWidget(rowHeights),
[0318] ], )
[0320] ],
[0321] ),
[0322] ],
[0323] ),
[0324] ),),
[0325] ], );
[0327] Based on the above steps 1 to 5, first create a data model according to the parameters of the target table, and perform subsequent drawing based on the data model. Then use the basic components provided by Flutter to calculate the row height, build the overall framework, draw the header view of the target table, the single-line view of the content in the target table, and the merged cell view of the target table, and fill all views into the framework. At the same time, the header and content of the table are nested in two SingleChildScrollView components respectively, and two scorllControllers are used for monitoring to realize the linkage between the header and the content. Finally, the functions of supporting cell merging, horizontal and vertical sliding viewing, header fixing, and viewing cell content are realized. It is simple to use and highly practical.
[0328] It should be pointed out that although the various steps in the above embodiments are described in a specific order, those skilled in the art can understand that in order to achieve the effects of the present invention, different steps do not have to be performed in such an order, and they can be performed simultaneously (in parallel) or in other orders. These changes are within the scope of protection of the present invention.
[0329] So far, the technical solutions of the present invention have been described in conjunction with the preferred embodiments shown in the accompanying drawings. However, it is easy for those skilled in the art to understand that the protection scope of the present invention is obviously not limited to these specific embodiments. Without departing from the principle of the present invention, those skilled in the art can make equivalent changes or substitutions to the relevant technical features, and the technical solutions after these changes or substitutions will fall within the protection scope of the present invention.< / widget> < / widget>
Claims
1. A Flutter chart display method with slidable and merging cells, characterized in that: The following steps are involved: Obtain all parameters of the target table and create a data model required for drawing a chart. The first row of data in the target table is defined as a header, and the second row and below of the target table are defined as content. Calculate the height tempHeight of each row in the target table and store the height of each row in a height set Map; Build the overall framework of the target table according to the height collection Map, define two SingleChildScrollView components, namely the header SingleChildScrollView component and the content SingleChildScrollView component, and create two ScrollControllers, namely headerScrollController and tableScrollController, respectively. The headerScrollController is used to monitor and control the header SingleChildScrollView, and the tableScrollController is used to monitor and control the content SingleChildScrollView. Draw the header view of the target table, the single-row view of the content in the target table, and the merged cell view of the target table respectively, nest the drawn header view in the header SingleChildScrollView component, and nest all the single-row views of the content in the drawn target table in the content SingleChildScrollView component; Use the Column component to sequentially fill the drawn header view, single row view, and merged cell view in the overall frame of the target table; The data model includes the default column width defaultColumnWidth, the special column width {n1:m1,n2:m2,...}, the data source of each row and the data source of the merged cell, wherein: n1:m1 means that the width of the n1th column in the target table is m1, and n2:m2 means that the width of the n2th column in the target table is m2; The data source of the row includes all row instance objects of the target table, each row instance object includes all cell instance objects in the row, and each cell instance object includes the text content, text style and background color in the cell; The data source of the merged cell includes all the merged cell instance objects of the target table, each of which includes the upper left corner horizontal index value, the upper left corner vertical index value, the lower right corner horizontal index value, the lower right corner vertical index value of the merged cell in the target table, and the text content of the merged cell; Drawing the table header view includes performing the following steps for the row where the table header is located: Get the current row instance object and the height of the current row; Draw all cell views in the current row; Put all cell views in a Row component, and use the Row component to display all cell views in the row in sequence horizontally; Drawing a single-row view of the content in the target table includes sequentially performing the following steps for each row of the content in the target table: Get the current row instance object, the row number of the current row, and the height of the current row; Draw all cell views in the current row; Put all cell views in a Row component, and use the Row component to display all cell views in the row in sequence horizontally; Drawing the merged cell view includes sequentially performing the following steps for each merged cell in the target table: Get the current merged cell instance object; Define the upper left corner coordinates (startX, starty) and lower right corner coordinates (endX, endY) of the current merged cell; Traverse all columns from 0 to the horizontal index value of the upper left corner of the merged cell, calculate the sum of all column widths as startX, traverse all columns from 0 to the horizontal index value of the lower right corner of the merged cell, and calculate the sum of all column widths as endX; Traverse all rows from 0 to the vertical index value of the upper left corner of the merged cell, calculate the sum of all row heights as startY, traverse all rows from 0 to the vertical index value of the lower right corner of the merged cell, and calculate the sum of all row heights as endY; Calculate the difference between startX and endX to get the width of the current merged cell, and calculate the difference between startY and endY to get the height of the current merged cell; Use the Stack component to draw the current merged cell, use the Container component to set the display style of the current merged cell, and use the Text component to display the text content of the current merged cell.
2. According to a Flutter chart display method of slidable and merging cells according to claim 1, it is characterized in that: The step of calculating the height tempHeight of each row in the target table includes sequentially performing the following steps for each row in the target table: Calculate the height of each cell in the current row; Initially define the height tempHeight of the current row as 0, and compare it with the height of each cell in the current row in turn; If the cell height is greater than tempHeight, assign the value of the cell height to tempHeight. If the cell height is not greater than tempHeight, retain the current tempHeight.
3. According to claim 2, a Flutter chart display method of slidable and mergable cells is characterized in that: The step of calculating the height of each cell in the current row includes sequentially performing the following steps on each cell in the current row: Get the text content of the current cell; Use the TextPainter component to calculate the text height based on the text content, text display style, maximum cell width, and maximum number of text lines to get the current cell height.
4. According to a Flutter chart display method of slidable and merging cells according to claim 1, it is characterized in that: Drawing all the cell views in the current row includes sequentially performing the following steps for each cell in the current row: Get the current cell instance object, the row number of the current cell, the column number of the current cell, and the height of the row where the current cell is located; Get the current cell width and height according to the row and column number of the current cell; Call the obtained parameters to draw the cell, use the GestureDetector component to set the click event of the current cell, use the Container component to set the display style of the current cell, and use the Text component to display the text content of the current cell.
Citation Information
Patent Citations
Table top-fixing method and device and computer readable storage medium
CN113449500A
Multi-data source chart display method based on mobile terminal equipment
CN114463098A