I have a single string which contains steps of how to do certain thing. Now I am able to get each step but I am using nested splits so it is getting very long so how can I use loop on it.
code
Column(
children: [
Text(
'${asset.lockoutApplicationProcess.split('2.')[0]}',
),
Text(
'2.${asset.lockoutApplicationProcess.split('2.')[1].split('3.')[0]}',
),
Text(
'3.${asset.lockoutApplicationProcess.split('2.')[1].split('3.')[1].split('4.')[0]}',
),
Text(
'4.${asset.lockoutApplicationProcess.split('2.')[1].split('3.')[1].split('4.')[1].split('5.')[0]}',
),
Text(
'5.${asset.lockoutApplicationProcess.split('2.')[1].split('3.')[1].split('4.')[1].split('5.')[1]}',
),
],
),
the string,
"1. Notify affected personnel. 2. Properly shut down machine. 3. Isolate all energy sources. 4. Apply lockout devices, locks, & tags. 5. Verify total de-energization of all sources."
so How can I use loop to reduce the code?
How about this?
// Collect all the data in an indexed list, skipping the first (empty) element
final splitData = asset.lockoutApplicationProcess.split(RegExp(r"\d\.")).asMap().entries.skip(1);
// Create a Text Widget for each entry, prefixed with the index number
final textWidgets = splitData.map((entry) => Text("${entry.key}. ${entry.value}"));
// Render the Text widgets in a column
return Column(children: textWidgets.toList());
Note that this will only work for single digits (1-9). If the list could potentially grow beyond 9, you should edit the RegExp to take this into account. For example, the regex RegExp(r"\d+\.") will also catch numbers with more than one digit.
Related
What I want to do:
I am trying to partition a column into two parts: upper (for settings) and lower (for data).
The settings part is relatively small, but might grow bigger depending on what the user adds (filters, etc...). As such, its size is unknown when building.
When the settings part grow bigger than half the column, they should be limited to half the column. The user should be able to scroll through the rest.
If it is smaller than half the column, the settings should only take the necessary space.
The data part should always fill the rest of the column: meaning, at least half of it, and if the settings container is smaller than half, then the data takes up this leftover space too.
My current "solution" is as follows:
import 'dart:io';
import 'package:flutter/material.dart';
import 'dart:math';
class TestWidget extends StatefulWidget {
final File file;
final FileInterpreter currentInterpreter;
final void Function({File? newFile, FileInterpreter<dynamic>? newInterpreter}) changeViewCallback;
const TestWidget({super.key, required this.file, required this.currentInterpreter, required this.changeViewCallback});
#override
State<TestWidget> createState() => TestWidgetState();
}
class TestWidgetState extends State<TestWidget> {
var rng = Random();
Widget? extensionPanel;
#override
Widget build(BuildContext context) => Container(
color: Colors.amber,
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// just a button to test different settings sizes
Container(
color: Colors.lightBlue.shade100,
child: SizedBox(height: 25, child: Row(children: [const Text("quick settings go here"), IconButton(onPressed: () => setState(() {extensionPanel = Text("SETTINGS START${"\n - :D"*rng.nextInt(40)}\nSETTINGS END");}), icon: const Icon(Icons.keyboard_arrow_down_sharp))],)),
),
// extension of the quick settings
if (extensionPanel!=null) Flexible(
fit: FlexFit.loose,
child: Container(
color: Colors.blue,
child: SingleChildScrollView(controller: ScrollController(), child: extensionPanel,)
)
),
if (extensionPanel!=null) Container(
color: Colors.red,
child: Row(children: [const Expanded(child: Divider()), IconButton(onPressed: (){setState(() {extensionPanel=null;});}, icon: const Icon(Icons.keyboard_arrow_up)), const Expanded(child: Divider())],)
),
// Important info
Expanded(
child: Container(
color: Colors.green,
child: const Center(child: Text("I am centered, very big, and fill ALL the empty vertical space\nEven the space left behind by the settings container\n:D"),)
),
)
],
),
);
}
The widget contains sugar to collapse the settings panel and change the settings size randomly.
It gives me the following result:
When settings are big enough
When settings are not big enough
This solution contains multiple containers: the full column is orange, and contains:
Light blue: fixed size, allows to refresh the settings size.
Blue: the flexible, scroll-able settings. Should only take the necessary space, and AT MOST half the column.
Red: fixed size, to collapse the settings panel.
Green: The expanded data. Should fill ALL the remaining vertical orange space.
Analysis of the result, and issues
It is almost perfect, except:
β
The good:
when there are a lot of settings:
-> they are limited to half the screen (blue container).
-> the green container uses the rest of the space (half the column).
-> I can scroll through the settings with no issues.
when there's not many settings:
-> the settings use up only what they need.
when I collapse the settings:
-> the green container takes all the space.
β The bad:
when there's not many settings:
-> the green section uses only half the column (there's leftover orange space)
π‘ What should happen:
any leftover orange space, should be given to the green container.
Other attempts
I tested multiple variations:
giving the green container more flex: β fills more space, but not all. Also, makes the settings section too small when there are a lot of settings.
giving the settings flexible container flex: 0: β if there are many settings, takes up more than half the space. Worst case, causes overflow. Also removes the scrollable property of the settings.
Using a SizedBox instead of Flexible: β I don't know how much space the settings bit will take... Different settings might need different sizes, that's why I want it flexible. Surely it cannot be this difficult?
Using two Expanded and forgetting about it: β Sure, but the green container displays a ton of very important information. Wasting almost half the column in empty space is very sad...
I also had a look at the solutions given in :
this stackoverflow forum
this github thread
Sadly, to no avail.
If you are using Flexible and Expanded in single Column or Row, then space will be allocated equally with flex value defaulted as 1.
You may have to remove Flexible widget for blue area, but surely you will face the other issue if there are many items.
I have the following function, where within a ListBody I map List values, I have a time parameter that returns a time. This contains unnecessary digits and I want to format it.
In other normal List situations I use the function
var timeFormat = DateFormat("HH:mm");
String timetest = timeFormat.format(my_data);
How can I implement my above function to format the time in the below RichText, where I enter data into TextSpan from the map, and cannot build it as a var outside and then call it in?
var mappedValues = ListBody(
children: [...mappedList.map((m) => RichText (
text: TextSpan(
children: <TextSpan> [
TextSpan(text: m.time!.toLocal().toString(), style: TextStyle(
fontSize: 18 ,
fontWeight: FontWeight.w400,
color: Color(0xff2F2F2F),
fontFamily: 'DMSans'
)
),
]
)))]);
Thank you
Update
Example of initial output
2022-03-05 23:24:00.000
My function will turn it to
23:24
Then you should be able to create a method within this widget that takes the Datetime (m.time) as input and returns the formatted time, as:
String getFormattedTime(DateTime time) {
var timeFormat = DateFormat("HH:mm");
String timePortion = timeFormat.format(time);
return timePortion;
}
Then inside your widget just call it:
TextSpan(text: getFormattedTime(m.time!))
You could also move this method into a common utility class so you can reuse it throughout your app. Let me know if thatβs what you looking for and works for your purposes.
Check out this Gist (make sure to run it through DartPad) that I created that illustrates my point. Another suggestion would be to use ListView in favor or ListBody as it is more robust.
You should get output that looks like this:
Let me know if that's clear.
I want to create a icon from a text like currency symbol. Currency symbols are not available in material icons and i don't want to use any third party library. I want to convert the text string like '$' to Icons and use them.
As per your requirement try below code hope its help to you:
Using \ character
Text(
'\$ Search',
),
Your Output Screen like->
Using Flutter Unicode character. You found Unicode character here
Text(
'Your \u{1F4B2} Symbol',
),
Your result screen like->
You can add any Symbol in between text
Wrap(
crossAxisAlignment: WrapCrossAlignment.center,
children: [
Text('Your'),
Icon(Icons.add),
Text('Icon'),
],
),
Your result screen like->
Or in VS Code you can used Windows + . keys and add any symbol on your need
Please try this one. 0024 is Unicode for $
Icon( IconData(0x0024, fontFamily: 'MaterialIcons'),size: 50, ))
I currently have a ListView that displays a large collection of objects. Quite a lot of these objects share the same first one/two words, for example:
Peter Johnson
Peter Jackson
Peter Smith
I would like to split this ListView into groups based on the start of their names. So for example all the Peters would be put in the same group. And then the next name that multiple people share would also be split into their own group.
The problem is that I can't explicitly say what these names are, how would I go about splitting these up?
This is a hard one, I'm going to try to simplify this as much as possible, but the general answer is first write an algorithm that splits your string how you want (in this case, if the first word is the same) and then nest these into a column or whatever.
Here I split the values into a map with the first name as a key and a list of all the people with that first name as a value
// Theres probably a better way to do this
Map<String, List<String>> valuesByFirstName(List<String> values) {
Map<String, List<String>> result = {};
for (final val in values) {
final fn = val.split().first;
if (result[fn] != null) result[fn]!.add(val);
else result[fn] = [val];
}
return result;
}
Then I'm not sure how you wanna group each of these so I just made some basic example:
var values = valuesByFirstName(originalValues);
return Row(
children: [
for (var key in values.keys)
SizedBox(
height: 200,
width: 100,
child: ListView(
children: [
Text(key, style: TextStyle(fontSize: 20)),
for (var value in values[key])
Text(value),
]
),
),
),
],
);
If what you want is to contract the different sections, take a look at the ExpansionPanel widget
I am making this showcaseview in my app using this library. But I have a long text as the description. But the text will just be in one line like this:
I really want the text to be in multiple lines. A solution would be to do \n to make it a new line, but i would have to do that every time i think it is a long line, and it would be a nightmare.
Is there a better way i could do this?
This is my code:
Showcase(
key: _graph,
title: 'Diagram',
description:
'This is a long description. This is a long description. This is a long description. This is a long description. This is a long description. This is a long description. ',
child: Container(
height: _size.height * 0.3,
child: Diagram()
),
),
Show Case View is supposed to provide a short description of your widget not show multi lines and long descriptions.
For a Text you can try this:
Container(
width: 100,
child: Text(
'This is a long description. This is a long description. This is a long description. This is a long description. This is a long description. This is a long description. ',
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
),
If you want to provide a longer or custom description try using Showcase.withWidget() instead of just Showcase() The takes a container: property where you can build a custom description widget that incorporates things like RichText().