How to get paragraphs in Flutter textfield or textformfield? - flutter

I am building a form that includes fields for notes. I want the user to be able to hit enter/return and start a new paragraph.
I am able to create a field that will accept and display large amounts of text. But I specifically want the user to be able to create paragraphs, otherwise their notes are just one long string with no breaks making it hard to read and edit.
I filed an issue here, but was told that I just need to do something like this.
This does not do want I want. I am trying to do something like this.
It looks like this should be possible (https://github.com/flutter/flutter/issues/43935). I don't know what I'm missing.
I am building for web, not iOS or Android.
main.dart:
import 'package:flutter/material.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
home: MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) =>Scaffold(
body: Center(
child: Center(
child:TextFormField(
textInputAction: TextInputAction.newline,
keyboardType: TextInputType.multiline,
maxLines: 10,
),
),
),
);
}
pubspec.yaml:
name: textformfield_demo
description: A new Flutter project.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true

There is a property of flutter to set max and min line. You can set maxLine:(int) Or maxLine: null, here maxLine:(int) restrict user to (int) number of line and maxLine: null will provide new line text without limit.
As-
class MultiLineEt extends StatefulWidget {
#override
State<StatefulWidget> createState() {
return _MyHomePageState();
}
}
class _MyHomePageState extends State<MultiLineEt> {
#override
Widget build(BuildContext context) =>Scaffold(
body: ListView(children: <Widget>[
new TextField(
keyboardType: TextInputType.multiline,
maxLines: null,
),
],
) );
}
Using ListView to prevent from pixels error

Related

Wrap.builder like in ListView.builder

I want to use Wrap on large amount of objects.
I tried to just map all object to children but it cause serious performance issue.
I want some alternative way to build only currently displayed widgets but with style of Wrap.
Some code:
Wrap(
children: list.map(createCardFromData), // List contains 20'000 items
);
This is really good example flutter is missing in my opinion.
This is also something which is being discussed on Flutter's repo
https://github.com/flutter/flutter/issues/97544
Unfortunately, it will take some time for it to be in stable release. For the time being, I would suggest to paginate the data into chunks of maybe 100 items. There are other ways as well which might involve a lot of calculations. Meanwhile, I (or maybe some other person) could try to come up with a efficient solution and maybe contribute to the Flutter.
After some fiddling, I could build sample app per your requirement.
pubspec.yaml
name: scrollable_wrap
description: A new Flutter project.
publish_to: "none"
version: 1.0.0+1
environment:
sdk: ">=2.18.4 <3.0.0"
dependencies:
cupertino_icons: ^1.0.2
flutter:
sdk: flutter
flutter_svg: ^1.1.6
random_avatar: ^0.0.7
random_words: ^1.0.2
dynamic_layouts:
git:
url: git#github.com:flutter/packages.git
path: packages/dynamic_layouts
dev_dependencies:
flutter_lints: ^2.0.0
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
main.dart
import 'package:dynamic_layouts/dynamic_layouts.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:random_avatar/random_avatar.dart';
import 'package:random_words/random_words.dart';
class Item {
final String label;
final String avatar;
Item(this.label) : avatar = randomAvatarString(label);
}
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Scrollable Wrap',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
List<Item> data = [];
int n = 100000;
void init() async {
data = generateNoun().take(n).map((e) => Item(e.asString)).toList();
setState(() {});
}
#override
void initState() {
super.initState();
init();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Scrollable Wrap'),
),
body: CustomScrollView(slivers: [
DynamicSliverGrid(
gridDelegate: const SliverGridDelegateWithWrapping(
mainAxisSpacing: 0,
crossAxisSpacing: 0,
childCrossAxisExtent: double.infinity,
childMainAxisExtent: double.infinity,
),
delegate: SliverChildBuilderDelegate(
(context, index) {
if (kDebugMode) {
print('build called for $index');
}
final item = data[index];
return Chip(
key: ValueKey(item),
label: Text('$index ${item.label}'),
avatar: SvgPicture.string(item.avatar),
);
},
childCount: data.length,
),
),
]),
);
}
}
Output
Please use flutter run --no-sound-null-safety as one of the library is not null-safe. Also, you might find lag as lots of svgs are being processed on scroll. It might not happen in production.
Do you need this many items loaded at once? You're probably using a scroll view anyway, so the user only initially sees a small batch of items rather than all of them, until they actually scroll for more. What you're looking for is lazy loading, maybe combined with a technique like infinite scroll.
Try a ListView (specifically, ListView.builder) where each item contains a Wrap widget (say, each 10 items - but you may want to experiment with this number until you see a balance between performance and visual appeal).
Or, alternatively, you may code your own Wrap that does loading lazily and reuses its views, so that it only loads and displays a couple of its children as needed, not thousands at once.
If your items are fixed width you could try something like this:
import 'dart:math';
import 'package:flutter/cupertino.dart';
typedef ValueWidgetBuilder<T> = Widget Function(T value);
class WrapBuilder extends StatelessWidget {
final double itemWidth;
final List items;
final ValueWidgetBuilder itemBuilder;
const WrapBuilder(
{Key? key,
required this.itemWidth,
required this.items,
required this.itemBuilder})
: super(key: key);
#override
Widget build(BuildContext context) {
return LayoutBuilder(builder: (context, constraints) {
var cardsPerRow = max(1, constraints.maxWidth ~/ itemWidth);
return ListView.builder(
shrinkWrap: true,
controller: ScrollController(),
itemCount: (items.length / cardsPerRow).ceil(),
itemBuilder: (BuildContext context, int index) {
var rowItems = items.sublist(cardsPerRow * index,
min(cardsPerRow * (index + 1), items.length));
return Row(children: [
for (final item in rowItems)
SizedBox(
width: itemWidth,
child: itemBuilder(item))
]);
},
);
});
}
}
And then use like
WrapBuilder(
itemWidth: 100, //example
items: list,
itemBuilder: createCardFromData);

Flutter display value of Textfield in a Text Widget by typing

I'm new to Flutter and curious how I can display the value of TextField in a Text widget without pressing a button. To be clearer with my question: When I type "hello" in the TextField, the text should also be "hello".
You need to listen change from TextField and update it in a global variable that can access from another widget (Text)
Example:
import 'package:flutter/material.dart';
void main() => runApp(MaterialApp(home: App()));
class App extends StatefulWidget {
#override
AppState createState() => AppState();
}
class AppState extends State<App> {
String text = ''; // variable stored your text
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: [
TextField(
onChanged: (value) => setState(() => text = value), // change `text` every text input change
decoration: const InputDecoration(labelText: 'input your text'),
),
Text('your text: $text'), // display your text
],
),
);
}
}
The Flutter documentation has become pretty solid. The essential widgets like TextField have detailed explanations on their proper usage with code example/demo, and even videos. Just type "flutter [the widget name]" in Google.

Pass Freezed Constructor Tear-Off to Generic Widget

What the title says. I have a freezed constructor tear-off that I'm trying to pass to a Widget and it's not returning null, and I'm trying to figure out what I'm doing wrong. Here is the freezed class:
#freezed
class PatientField with SetFieldOption, _$PatientField {
factory PatientField.firstName(String value) = PatientFirstName;
}
This is a simplified version of my initial Widget (which actually displays properly):
class SinglePatientView2 extends ConsumerWidget {
const SinglePatientView2({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
print(PatientField.firstName('something'));
return Theme(
data: Theme.of(context).copyWith(dividerColor: Colors.transparent),
child: Expanded(
child: DefaultTabController(
length: 1,
child: Scaffold(
body: TabBarView(children: [
PersonTabContent<PatientField>(
PatientField.firstName,
)
])))));
}
}
Then Widget that's called above looks like (simplifed version anyway):
class PersonTabContent<T> extends StatelessWidget {
const PersonTabContent(
this.firstNameField, {
Key? key,
}) : super(key: key);
final T Function(String) firstNameField;
#override
Widget build(BuildContext context) {
print(firstNameField('something'));
return Padding(
padding: EdgeInsets.all(doubleBySize(context, 32)),
);
}
}
Looking at the output, the above prints:
PatientField.firstName(value: something)
null
I don't understand why I'm getting a null value in the second Widget's build method. Any insights as to what I'm doing wrong?
As usual, it was my fault. For anyone stumbling onto this, the problem was my version. Constructor tear-offs have only been recently implemented, and I was still specifying dart 2.15.0 in my pubspec.yaml file. For anyone else running into this issue, check your pubspec.yaml file and ensure the top looks like the following:
name: a_new_flutter_project
description: A new Flutter project.
publish_to: 'none'
version: 1.0.0+1
environment:
sdk: ">=2.16.0 <3.0.0"
And that should be that.

Flutter 1.22.6 - url_launcher - Sending HTML email

I have two problems with the url_launcher: ^5.7.10
First Problem:
When I try to send an email with html tag, on a real device, if I use Gmail application the body of my email is not well formated. I see the HTML tags. I tried with or without HTML5 doctype
Second Problem:
When I try to send an email with an Href tag the email body is cut at the equal sign.
My code is
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:url_launcher/url_launcher.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'URL Launcher',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'URL Launcher'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
Future<void> _sendMailHtml(String url) async {
if (await canLaunch(url)) {
await launch(
url
);
} else {
throw 'Could not launch $url';
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: ListView(
children: <Widget>[
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
onPressed: () => setState(() {
_launched = _sendMailHtml('mailto:smith#example.org?subject=News&body=<h1>Header 1</h1><p>Paragraph</p>');
}),
child: const Text('Send Mail HTML'),
),
RaisedButton(
onPressed: () => setState(() {
_launched = _sendMailHtml('mailto:smith#example.org?subject=News&body=<h1>Header 1</h1><p>Paragraph</p>Link<p>End of mail</p>');
}),
child: const Text('Send Mail HTML With HREF'),
),
],
),
],
),
);
}
}
My pubspec.yaml is
name: flutter_app
description: A new Flutter application.
publish_to: 'none' # Remove this line if you wish to publish to pub.dev
version: 1.0.0+1
environment:
sdk: ">=2.7.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
url_launcher: ^5.7.10
cupertino_icons: ^1.0.0
dev_dependencies:
flutter_test:
sdk: flutter
# The following section is specific to Flutter.
flutter:
uses-material-design: true
I did not try with flutter 2 because my app is in production and I have some dependencies errors.
For the first problem if I try with another email app, I can see the good formatting.
On Android 10...
screenshots :
first problem on Gmail app
on other email app
Second problem with Gmail and anchor tag
The mailto body parameter only supports plaintext messages. See this question.
If you want you can check out the mailer package which has an interface for sending HTML emails, as shown in the linked page.

Error: The getter 'length' was called on null

Error says:
NoSuchMethodError: The getter 'length' was called on null
It is a basic flutter music player App.
main.dart
import 'package:flute_music_player/flute_music_player.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
#override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
List<Song> _songs;
#override
void initState() {
// TODO: implement initState
super.initState();
initPlayer();
}
void initPlayer() async{
var songs = await MusicFinder.allSongs();
songs=new List.from(songs);
setState(() {
_songs = songs;
});
}
#override
Widget build(BuildContext context) {
Widget home(){
new Scaffold(
appBar: new AppBar(title: new Text("Music App"),
),
body: new ListView.builder(
itemCount: _songs.length,
itemBuilder: (context,int index){
return new ListTile(
leading: new CircleAvatar(
child: new Text(_songs[index].title[0]),
),
title: new Text(_songs[index].title),
);
}),
);
}
return new MaterialApp(
home: home(),
);
}
}
pubspec.yaml
name: music_player
description: A new Flutter application.
version: 1.0.0+1
environment:
sdk: ">=2.1.0 <3.0.0"
dependencies:
flutter:
sdk: flutter
cupertino_icons: ^0.1.2
flute_music_player:
dev_dependencies:
flutter_test:
sdk: flutter
flutter:
uses-material-design: true
It should show the list of musics as result but gives an unexpected error.I am running on android.Plz help me out.
It should show the list of musics as result but gives an unexpected error.I am running on android.Plz help me out.
Change itemCount: _songs.length to itemCount: _songs?.length ?? 0 - it helps to avoid exception
Since you're performing an async operation, that would take certain amount of time so when your app first builds, the songs array is null. Try to start with an empty array instead of a null array: List<Song> _songs = []; then, when the async operation is completed the setState will make the widget to rebuild and show the array with data.