A Deep Dive Into Flutter TextField

This package is a TextField that allows you to implement the OutlineInputBorder with simple settings. It includes all the options provided by the existing TextField, and additionally includes an option to block white space or special characters.

Getting started

To use this package, add simple_text_field as a dependency in your pubspec.yaml file. For example:

dependencies:
  simple_text_field: ^2.1.0

Package

  • SimpleTextField - A widget that implements a SimpleTextField.
  • SimpleTextFieldLabel - A widget that implements the label of SimpleTextField.
  • SimpleInputDecoration - Creates a bundle of the border, labels, icons, and styles used to decorate a SimpleTextField.

SimpleTextField (※ Show only added options)

ParameterDescription
decorationUsed to decorate SimpleTextField.
labelLabel can be created using SimpleTextFieldLabel.
labelAlignmentSet the alignment value of the SimpleTextFieldLabel.
Default value is CrossAxisAlignment.start.
ignoreWhiteSpaceWhether to ignore input of white space.
Default value is false.
ignoreSpecialCharWhether to ignore input of special characters.
Default value is false.

SimpleTextFieldLabel

ParameterDescription
textSet the label text.
styleSpecifies the style of the label text.
Default value is Theme.of(context).textTheme.subtitle1.
asterStyleSpecifies the style of the asterisk character.
Default value is Theme.of(context).textTheme.subtitle1?.copyWith(color: Theme.of(context).primaryColor).
paddingSet the label padding.
Default value is const EdgeInsets.only(top: 16.0, bottom: 8.0).
importantWhen set to true, an asterisk character appears.
Default value is false.

SimpleInputDecoration (※ Show only added options)

ParameterDescription
removeBorderWhether to remove the border of a SimpleTextField.
Default value is false.
simpleBorderWhether to automatically create a OutlineInputBorder.
Default value is false.
disabledColor*fillColor to display when a SimpleTextField is disabled.
borderColor*The color of the border that will be shown to us in general.
errorBorderColor*The color of the border to show when the errorText is not null.
focusedBorderColor*The color of the focused border.
focusedErrorBorderColor*The color of the focused error border.
borderWidth*Set the width of the border.
Default value is 1.0.
focusedBorderWidth*Set the width of the focused border.
Default value is 2.0.
borderRadius*Set the radius of the border.
Default value is const BorderRadius.all(Radius.circular(2.0)).

Note: The parameters marked with an asterisk(*) operate when simpleBorder is true.

Support

If you find any bugs or issues while using the plugin, please register an issues on GitHub. You can also contact us at hwj930513@naver.com.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add simple_text_field

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  simple_text_field: ^2.1.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:simple_text_field/simple_text_field.dart'; 

Download Details:

Author: Dev-hwang

Source Code: https://github.com/Dev-hwang/simple_text_field

#flutter #textfield 

A Deep Dive Into Flutter TextField
Rupert  Beatty

Rupert Beatty

1666068667

Custom UITextFields Effects inspired By Codrops, Built using Swift

TextFieldEffects

I fell in love with the text inputs effects in this article. As an exercise I decided to recreate as many of them as I can using Swift (some of them have a personal touch).

Currently it features the following effects from the article:

  •  Kaede
  •  Hoshi
  •  Jiro
  •  Isao
  •  Minoru
  •  Yoko
  •  Madoka
  •  Akira
  •  Yoshiko

How they look

Kaede

Kaede.gif

Hoshi

Hoshi.gif

Jiro

Jiro.gif

Isao

Isao.gif

Minoru

Minoru.gif

Yoko

Yoko.gif

Madoka

Madoka.gif

Akira

Akira.gif

Yoshiko

Yoshiko.gif

Installation

  • Looking for Swift 2.3 support? Check out the 1.2.0 tag.
  • Looking for Swift 2.1 support? Check out the 1.1.1 tag.
  • Looking for Swift 1.2 support? Check out the swift-1.2 branch.

Manual

The easiest way to install this framework is to drag and drop the TextFieldEffects/TextFieldEffects folder into your project. This also prevents the frameworks problem in iOS where the IBInspectable and IBDesignable are stripped out.

CocoaPods

Add the following to your Podfile:

use_frameworks!
pod 'TextFieldEffects'

Carthage

Add the following to your Cartfile:

github 'raulriera/TextFieldEffects'

How to use them

Every effect is properly documented in the source code, this is the best way to both understand and see what they do. There is also an example project included with all the effects and their settings.

Interface Builder

The library is a simple drop-in, as soon as you set your subclass to one of the effects and your module to TextFieldEffects you will be able to see all the IBDesignable settings in the storyboard.

Code

If you like to get your hands dirty, you can use them just like you would normally use any UITextField

let textField = KaedeTextField(frame: textFieldFrame)
textField.placeholderColor = .darkGrayColor()
textField.foregroundColor = .lightGrayColor()

view.addSubView(textField)

Is that simple.

Created by

Raul Riera, @raulriera

Download Details:

Author: Raulriera
Source Code: https://github.com/raulriera/TextFieldEffects 
License: MIT license

#swift #animation #effective #textfield 

Custom UITextFields Effects inspired By Codrops, Built using Swift
Monty  Boehm

Monty Boehm

1662539700

5 Best React Textfield Libraries

In today's post we will learn about 5 Best React Textfield Libraries. 

Textfields let users enter and edit text. Textfields allow users to enter text into a UI. They typically appear in forms and dialogs.

1 - React Mentions

A React component that let's you mention people in a textarea like you are used to on Facebook or Twitter.

Getting started

Install the react-mentions package via npm:

npm install react-mentions --save

Or yarn:

yarn add react-mentions

The package exports two React components for rendering the mentions textarea:

import { MentionsInput, Mention } from 'react-mentions'

MentionsInput is the main component rendering the textarea control. It takes one or multiple Mention components as its children. Each Mention component represents a data source for a specific class of mentionable objects, such as users, template variables, issues, etc.

Example:

<MentionsInput value={this.state.value} onChange={this.handleChange}>
  <Mention
    trigger="@"
    data={this.props.users}
    renderSuggestion={this.renderUserSuggestion}
  />
  <Mention
    trigger="#"
    data={this.requestTag}
    renderSuggestion={this.renderTagSuggestion}
  />
</MentionsInput>

View on Github

2 - React-text-mask

Input mask for React, Angular, Ember, Vue, & plain JavaScript

Getting started

First, install it.

npm i react-text-mask --save

Then, require it and use it.

import React from 'react'
import MaskedInput from 'react-text-mask'

export default () => (
  <div>
    <MaskedInput
      mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
    />
  </div>
)

<MaskedInput/> is fully compatible with <input/> element. So, you can pass it CSS classes, a placeholder attribute, or even an onBlur handler.

For example, the following works:

<MaskedInput
  mask={['(', /[1-9]/, /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]}
  className="form-control"
  placeholder="Enter a phone number"
  guide={false}
  id="my-input-id"
  onBlur={() => {}}
  onChange={() => {}}
/>

View on Github

3 - Material Search Bar

Material design search bar 

Installation

npm i --save material-ui-search-bar

Note: If you're still using Material-UI v3, please install v0.x of the search bar using npm i --save material-ui-search-bar@beta

Usage

The SearchBar is a controlled input, meaning that you need to keep the input state. This allows for much flexibility, e.g. you can change and clear the search input just by changing its props.

import SearchBar from "material-ui-search-bar";
// *snip*

return (
  <SearchBar
    value={this.state.value}
    onChange={(newValue) => this.setState({ value: newValue })}
    onRequestSearch={() => doSomethingWith(this.state.value)}
  />
);

View on Github

4 - React-filter-box

Filter box which support AND/OR, syntax highlight and AutoComplete

Getting started:

Install react-filter-box using npm.

npm install react-filter-box

Import library, and default stylesheet.

import ReactFilterBox, {AutoCompleteOption,SimpleResultProcessing} from "react-filter-box";
import "react-filter-box/lib/react-filter-box.css"

How to use:

Demo: https://nhabuiduc.github.io , which includes source code.

Simple case:

import ReactFilterBox, {SimpleResultProcessing} from "react-filter-box";
import "react-filter-box/lib/react-filter-box.css"


export default class App extends React.Component {
    
    constructor(props){
        super(props);

         this.options = [
            {
                columnField: "Name",
                type:"text"
            },
            {
                columnField: "Description",
                type:"text"
            },
            {
                columnField: "Status",
                type:"selection" // when using type selection, it will automatically sugest all posible values
            },
            {
                columnText: "Email @",
                columnField: "Email",
                type:"text"
            }
        ];
    }

    onParseOk(expressions){
        var data = [];
        var newData = new SimpleResultProcessing(this.options).process(data,expressions);
        //your new data here, which is filtered out of the box by SimpleResultProcessing
    }

    render(){
         return <div className="main-container"> 
                    <h2>React Filter Box</h2>
         
                        <ReactFilterBox 
                            
                            data={data}
                            options={this.options}
                            onParseOk={this.onParseOk.bind(this)}
                            />
                    
                    </div>
    }
}

View on Github

5 - Reactackle

Open-source components library built with React and Styled-Components.

Getting started

Using NPM:

npm install reactackle --save

Using Yarn:

yarn add reactackle

Or you can install components independently:

npm install reactackle-button --save

View on Github

Thank you for following this article. 

#react #text #textfield 

5 Best React Textfield Libraries
Mike  Kozey

Mike Kozey

1661879820

Circular_textfield: A Circular Textfield Widget for Your Apps

circular_textfield


A circular textfield widget for your apps. This widget makes our TextField come as circular by default. We can also add the icon we want with the icon parameter.

screenshot

Usage


First, add the circular_textfield package to your pubspec dependencies.

To import CircularTextField:

import 'package:circular_textfield/circular_textfield.dart';

To use CircularTextField:

return Scaffold(
      body: Center(
        child: CircularTextField(
          icon: Icons.access_time,
          width: 250,
          hasIcon: true,
        ),
      ),
    );

Installing

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add circular_textfield

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  circular_textfield: ^0.0.5

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:circular_textfield/circular_textfield.dart';

example/main.dart

// ignore_for_file: prefer_const_constructors, avoid_print

import 'package:circular_textfield/circular_textfield.dart';
import 'package:flutter/material.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({Key? key}) : super(key: key);

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Center(
        child: CircularTextField(
          icon: Icons.access_time,
          width: 250,
          backgroundColor: Colors.grey,
          style: TextStyle(
            color: Colors.black,
          ),
          onChanged: (String value) {
            print(value.length);
          },
          hasIcon: true,
        ),
      ),
    );
  }
}

Download Details:

Author: ilyashyrt
Source Code: https://github.com/ilyashyrt/circular_textfield/ 
License: BSD-3-Clause license

#flutter #dart #textfield 

Circular_textfield: A Circular Textfield Widget for Your Apps
Mike  Kozey

Mike Kozey

1661468700

TextEditingController for Providing Common Social Media Text Contents

flutter_social_textfield

A Flutter plugin that helps detection of common social media contents. The current position of the cursor is used for detecting content. Current detection types are:

  • HashTag (#): Texts start with #
  • Mention (@): Text start with @ sign
  • Web Links: Can detect web links
Overview

You can see the supported detection types from DetectedType enum

enum DetectedType{
    mention, //By Default texts starting with @sign
    hashtag,  //By default, texts starting with #hashtag
    url, //By default texts starting with http://xxx.yyy or https://aaa.bbb 
    plain_text //Any other type falls into this.
}

You can change the relevant regex for that type if you want, which has been mentioned in Configuring the Text Editing Controller part.

Getting Started

SocialTextField is basically an improved Text Editing Controller, so you can just assign text controller to any text editing widget that you want.

_textEditingController = SocialTextEditingController();

TextField(
    controller: _textEditingController,
    expands: true,
    maxLines: null,
    minLines: null,
    decoration: InputDecoration(
    hintText: "Please Enter a Text"
    ),
)

Configuring the Text Editing Controller

SocialTextEditingController can be configured by calling configuration methods.

There are 2 setter methods for this.

setTextStyle: Change how detected content shown.

setTextStyle(DetectedType.mention, TextStyle(...)

setRegexp: Override the detection regexp

setRegexp(DetectedType.url, RegExp("your_own_regex_fr_this_type"))

It is recommended to set these values on initialization;

_textEditingController = SocialTextEditingController()
    ..setTextStyle(DetectedType.mention, TextStyle(color: Colors.purple,backgroundColor: Colors.purple.withAlpha(50)))
    ..setRegexp(DetectedType.url, RegExp("your_own_regex_fr_this_type"));

Listening Content Detection Events

One of the main reasons that i want to create this plugin was that i needed to listen detection events from different widgets. So flutter_social_textfield provides a stream for detections so you can subscribe and listen events when needed.

StreamSubscription<SocialContentDetection> _streamSubscription;

@override
void initState() {
super.initState();
_textEditingController = SocialTextEditingController()
..text = "Lorem ipsum amet."
..setTextStyle(DetectedType.mention, TextStyle(color: Colors.purple,backgroundColor: Colors.purple.withAlpha(50)))
..setTextStyle(DetectedType.url, TextStyle(color: Colors.blue, decoration: TextDecoration.underline))
..setTextStyle(DetectedType.hashtag, TextStyle(color: Colors.blue, fontWeight: FontWeight.w600));

//Subscribe to events
 _streamSubscription = _textEditingController.subscribeToDetection(onDetectContent);
}

void onDetectContent(SocialContentDetection detection){
 print("Detected Contet: $detection");
}

don't forget to unsubscribe on dispose.

@override
void dispose() {
    _streamSubscription.cancel();
    super.dispose();
}

The Stream Subscriptoin returns SocialContentDetection class:

class SocialContentDetection{
    final DetectedType type; //mention, url, hashtag, plan_text
    final TextRange range; //range of detected content
    final String text; //detected content
    SocialContentDetection(this.type, this.range, this.text);
    
    @override
    String toString() {
        return 'SocialContentDetection{type: $type, range: $range, text: $text}';
    }
}

DefaultSocialTextFieldController

I've implemented an experimental widget for ease of use. DefaultSocialTextFieldController puts the main content inside a Stack and allows users to show relevant content when curser comes over a detected content

As with version 0.0.9 There are 2 different types of presentation of detection content:

Detection Presentation Mode

DetectionPresentationMode.split_screen : Shows detection view but moving from bottom to determined widget size. useful for full screen textfields like text editors

DetectionPresentationMode.above_text_field : Useful for showing detection view from above the textfield. The location of textfield is detected from the FocusNode automatically.

Please notice the 'scrollPhysics' property of the TextField;

DefaultSocialTextFieldController(
        detectionPresentationMode: DetectionPresentationMode.above_text_field,
        focusNode: _focusNode,
        scrollController: _scrollController,
        textEditingController: _textEditingController,
        child: Container(
          padding: EdgeInsets.all(8),
          child: Column(
            mainAxisAlignment: MainAxisAlignment.start,
            children: <Widget>[
              Expanded(
                child: TextField(
                  scrollPhysics: ClampingScrollPhysics(), //Use this for unnecessary scroll bounces
                  scrollController: _scrollController,
                  focusNode: _focusNode,
                  controller: _textEditingController,
                  expands: true,
                  maxLines: null,
                  minLines: null,
                  decoration: InputDecoration(
                      hintText: "Please Enter a Text"
                  ),
                ),
              ),
            ],
          ),
        ),
        detectionBuilders: {
          DetectedType.mention:(context)=>mentionContent(height),
          DetectedType.hashtag:(context)=>hashtagContent(height),
          DetectedType.url:(context)=>urlContent(height)
        },
      )

DefaultSocialTextFieldController in action

Using DefaultSocialTextFieldController

An example usage of the DefaultSocialTextFieldController can be seen in the example project. The main goal is to provide an easy way to implement features that have been seen in most of the social media applications.

SocialTextSpanBuilder

flutter_social_textfield uses SocialTextSpanBuilder for rendering the text inside the attached textfield. So if you just want to show formatted text content instead of using inside an editor you can use it like this:

With version 0.0.3 you can also implement onTapDetection function for adding tap gestures to detected strings.

void initBuilder(){
    final Map<DetectedType, RegExp> _regularExpressions = {
        DetectedType.mention:atSignRegExp,
        DetectedType.hashtag:hashTagRegExp,
        DetectedType.url:urlRegex
    };

    final Map<DetectedType, TextStyle> _detectionTextStyles = {
        DetectedType.mention:TextStyle(...)
    };

    final TextStyle _defaultTextStyle = TextStyle();

    final _textSpanBuilder = SocialTextSpanBuilder(regularExpressions: _regularExpressions,defaultTextStyle:_defaultTextStyle,detectionTextStyles: _detectionTextStyles, onTapDetection: (detection){print("Tapped on detection: $detection");});
}

//And you can return RichText content bu calling build(context) method afterwards.
@override
    Widget build(BuildContext context) {
        var height = MediaQuery.of(context).size.height * 0.4;
        return Scaffold(
            appBar: AppBar(
                title: Text(widget.title),
            ),
        body: Container(
           child:RichText(
              text:_textSpanBuilder.build(context)
            )
        )// This trailing comma makes auto-formatting nicer for build methods.
    );  
}   

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_social_textfield

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_social_textfield: ^0.1.0

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_social_textfield/flutter_social_textfield.dart';

example/lib/main.dart

import 'package:example/bottom_sheet_example.dart';
import 'package:example/text_span_example.dart';
import 'package:flutter/material.dart';

import 'default_controller_above.example.dart';
import 'default_controller_example.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Flutter Social Text Field'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, required this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {


  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
        actions: [
        ],
      ),
      body: ListView(
        children: [
          ListTile(
            title: Text("DefaultSocialTextFieldController Example"),
            subtitle: Text("Editable Text field implementations"),
            trailing: Icon(Icons.chevron_right),
            onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder: (_)=>DefaultControllerExampleScreen())),
          ),
          ListTile(
            title: Text("DefaultSocialTextFieldController with above detection field example (NEW!)"),
            subtitle: Text("Editable Text field implementations with above detection field for places like chat pages"),
            trailing: Icon(Icons.chevron_right),
            onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder: (_)=>DefaultControllerAboveExampleScreen())),
          ),
          ListTile(
            title: Text("SocialTextSpanBuilder Bottom Sheet Example"),
            subtitle: Text("A Different Approach for default controller"),
            trailing: Icon(Icons.chevron_right),
            onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder: (_)=>BottomSheetControllerExampleScreen())),
          ),
          ListTile(
            title: Text("SocialTextSpanBuilder Example"),
            subtitle: Text("For rendering detections inside RichTextField"),
            trailing: Icon(Icons.chevron_right),
            onTap: ()=>Navigator.of(context).push(MaterialPageRoute(builder: (_)=>SocialTextSpanExampleScreen())),
          ),

        ],
      )// This trailing comma makes auto-formatting nicer for build methods.
    );
  }
}

Acknowledgements

Thanks https://github.com/Bhupesh-V (@Bhupesh-V) for his contribution to url regex 👌

This widget's default regular expressions taken from this wonderful widget:

detectable_text_field

Download Details:

Author: Dreampowder
Source Code: https://github.com/dreampowder/flutter_social_textfield 
License: BSD-3-Clause license

#flutter #textfield #dart 

TextEditingController for Providing Common Social Media Text Contents

A Text Field That Allows an Input of Tags Inside The Textfield

textfield_tags

This widget allows you to create a textfield that takes in Textfield values and display the values as tags. The tags can also be customized to your own preference. The widget also takes in a controller that can also be customized by extending it into your own custom controller and inheriting its functionalities.

Environment

sdk: ">=2.12.0 <3.0.0"

flutter: ">=1.17.0"

Installation

  dependencies:
      textfield_tags: ^2.0.1

$ flutter pub get

Getting Started

To start using this widget, you will need to first import the package inside your project following the installation guide found on Flutter.dev.

Usage

To use this widget,

  1. import 'package:textfield_tags/textfield_tags.dart'; inside your dart file
  2. Call the widget TextFieldTags().
  3. The widget takes in 8 arguments: List<String>? initialTags, FocusNode? focusNode, TextEditingController? textEditingController, List<String>? textSeperators, LetterCase? letterCase, Validator? validator, InputFieldBuilder inputfieldBuilder, TextfieldTagsController? textfieldController. Read the api documentation about these properties for more details.

When you want to use it, call the TextFieldTags() as bellow examples show

class Home extends StatefulWidget {
  const Home({Key key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  double _distanceToField;
  TextfieldTagsController _controller;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _distanceToField = MediaQuery.of(context).size.width;
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  void initState() {
    super.initState();
    _controller = TextfieldTagsController();
  }

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "wellcome",
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: const Color.fromARGB(255, 74, 137, 92),
          centerTitle: true,
          title: const Text('Enter a tag...'),
        ),
        body: Column(
          children: [
            TextFieldTags(
              textfieldTagsController: _controller,
              initialTags: const [
                'pick',
                'your',
                'favorite',
                'programming',
                'language'
              ],
              textSeparators: const [' ', ','],
              letterCase: LetterCase.normal,
              validator: (String tag) {
                if (tag == 'php') {
                  return 'No, please just no';
                } else if (_controller.getTags.contains(tag)) {
                  return 'you already entered that';
                }
                return null;
              },
              inputfieldBuilder:
                  (context, tec, fn, error, onChanged, onSubmitted) {
                return ((context, sc, tags, onTagDelete) {
                  return Padding(
                    padding: const EdgeInsets.all(10.0),
                    child: TextField(
                      controller: tec,
                      focusNode: fn,
                      decoration: InputDecoration(
                        isDense: true,
                        border: const OutlineInputBorder(
                          borderSide: BorderSide(
                            color: Color.fromARGB(255, 74, 137, 92),
                            width: 3.0,
                          ),
                        ),
                        focusedBorder: const OutlineInputBorder(
                          borderSide: BorderSide(
                            color: Color.fromARGB(255, 74, 137, 92),
                            width: 3.0,
                          ),
                        ),
                        helperText: 'Enter language...',
                        helperStyle: const TextStyle(
                          color: Color.fromARGB(255, 74, 137, 92),
                        ),
                        hintText: _controller.hasTags ? '' : "Enter tag...",
                        errorText: error,
                        prefixIconConstraints:
                            BoxConstraints(maxWidth: _distanceToField * 0.74),
                        prefixIcon: tags.isNotEmpty
                            ? SingleChildScrollView(
                                controller: sc,
                                scrollDirection: Axis.horizontal,
                                child: Row(
                                    children: tags.map((String tag) {
                                  return Container(
                                    decoration: const BoxDecoration(
                                      borderRadius: BorderRadius.all(
                                        Radius.circular(20.0),
                                      ),
                                      color: Color.fromARGB(255, 74, 137, 92),
                                    ),
                                    margin: const EdgeInsets.symmetric(
                                        horizontal: 5.0),
                                    padding: const EdgeInsets.symmetric(
                                        horizontal: 10.0, vertical: 5.0),
                                    child: Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.spaceBetween,
                                      children: [
                                        InkWell(
                                          child: Text(
                                            '#$tag',
                                            style: const TextStyle(
                                                color: Colors.white),
                                          ),
                                          onTap: () {
                                            print("$tag selected");
                                          },
                                        ),
                                        const SizedBox(width: 4.0),
                                        InkWell(
                                          child: const Icon(
                                            Icons.cancel,
                                            size: 14.0,
                                            color: Color.fromARGB(
                                                255, 233, 233, 233),
                                          ),
                                          onTap: () {
                                            onTagDelete(tag);
                                          },
                                        )
                                      ],
                                    ),
                                  );
                                }).toList()),
                              )
                            : null,
                      ),
                      onChanged: onChanged,
                      onSubmitted: onSubmitted,
                    ),
                  );
                });
              },
            ),
            ElevatedButton(
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(
                  const Color.fromARGB(255, 74, 137, 92),
                ),
              ),
              onPressed: () {
                _controller.clearTags();
              },
              child: const Text('CLEAR TAGS'),
            ),
          ],
        ),
      ),
    );
  }
}

V2.0.0+ Examples

Please note that versions bellow V2.0.0 will not be supported anymore. Please consider upgrading to V2.0.0+. The new changes offer more customization and flexibility to developers with many functionalities that solves previous customization issues related to this package. Now you can design this Widget to whatever you wants it. All the functionalities from previous versions are also included.

Sample examples will be shown bellow from left to right respectively.

Example 1

Example 2

Visual Samples For Above Examples

More Advanced Functionality Via Custom Controller

If you feel like you want more functionality than what is offered from the default controller that comes with this widget, you can easily extend the controller's class to your own custom class and inherit all its functionality and add your own stuffs as bellow example shows.

Example:

  // Create my own custom controller
  class MyCustomController extends TextfieldTagsController {
      MyCustomController() : super();

      //create your own methods
      void myCustomMethod(){
      }
     
      //override the super class method
      @override
        set addTag(String tag) {
          if(tag!='php'){
            super.addTag = tag;
            notifyListeners();
          }else{
            _error= '?';
          }
      }
      
      //....
 }

  final _myCustomController = MyCustomController();
  TextFieldTags(textfieldController: _myCustomController);

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add textfield_tags

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  textfield_tags: ^2.0.1

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:textfield_tags/textfield_tags.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:textfield_tags/textfield_tags.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({Key key}) : super(key: key);

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(primarySwatch: Colors.green),
      home: const Home(),
    );
  }
}

class Home extends StatefulWidget {
  const Home({Key key}) : super(key: key);

  @override
  State<Home> createState() => _HomeState();
}

class _HomeState extends State<Home> {
  double _distanceToField;
  TextfieldTagsController _controller;

  @override
  void didChangeDependencies() {
    super.didChangeDependencies();
    _distanceToField = MediaQuery.of(context).size.width;
  }

  @override
  void dispose() {
    super.dispose();
    _controller.dispose();
  }

  @override
  void initState() {
    super.initState();
    _controller = TextfieldTagsController();
  }

  static const List<String> _pickLanguage = <String>[
    'c',
    'c++',
    'java',
    'python',
    'javascript',
    'php',
    'sql',
    'yaml',
    'gradle',
    'xml',
    'html',
    'flutter',
    'css',
    'dockerfile'
  ];
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: "wellcome",
      home: Scaffold(
        appBar: AppBar(
          backgroundColor: const Color.fromARGB(255, 74, 137, 92),
          centerTitle: true,
          title: const Text('Enter a tag...'),
        ),
        body: Column(
          children: [
            Autocomplete<String>(
              optionsViewBuilder: (context, onSelected, options) {
                return Container(
                  margin: const EdgeInsets.symmetric(
                      horizontal: 10.0, vertical: 4.0),
                  child: Align(
                    alignment: Alignment.topCenter,
                    child: Material(
                      elevation: 4.0,
                      child: ConstrainedBox(
                        constraints: const BoxConstraints(maxHeight: 200),
                        child: ListView.builder(
                          shrinkWrap: true,
                          itemCount: options.length,
                          itemBuilder: (BuildContext context, int index) {
                            final dynamic option = options.elementAt(index);
                            return TextButton(
                              onPressed: () {
                                onSelected(option);
                              },
                              child: Align(
                                alignment: Alignment.centerLeft,
                                child: Padding(
                                  padding: const EdgeInsets.symmetric(
                                      vertical: 15.0),
                                  child: Text(
                                    '#$option',
                                    textAlign: TextAlign.left,
                                    style: const TextStyle(
                                      color: Color.fromARGB(255, 74, 137, 92),
                                    ),
                                  ),
                                ),
                              ),
                            );
                          },
                        ),
                      ),
                    ),
                  ),
                );
              },
              optionsBuilder: (TextEditingValue textEditingValue) {
                if (textEditingValue.text == '') {
                  return const Iterable<String>.empty();
                }
                return _pickLanguage.where((String option) {
                  return option.contains(textEditingValue.text.toLowerCase());
                });
              },
              onSelected: (String selectedTag) {
                _controller.addTag = selectedTag;
              },
              fieldViewBuilder: (context, ttec, tfn, onFieldSubmitted) {
                return TextFieldTags(
                  textEditingController: ttec,
                  focusNode: tfn,
                  textfieldTagsController: _controller,
                  initialTags: const [
                    'pick',
                    'your',
                    'favorite',
                    'programming',
                    'language',
                  ],
                  textSeparators: const [' ', ','],
                  letterCase: LetterCase.normal,
                  validator: (String tag) {
                    if (tag == 'php') {
                      return 'No, please just no';
                    } else if (_controller.getTags.contains(tag)) {
                      return 'you already entered that';
                    }
                    return null;
                  },
                  inputfieldBuilder:
                      (context, tec, fn, error, onChanged, onSubmitted) {
                    return ((context, sc, tags, onTagDelete) {
                      return Padding(
                        padding: const EdgeInsets.symmetric(horizontal: 10.0),
                        child: TextField(
                          controller: tec,
                          focusNode: fn,
                          decoration: InputDecoration(
                            border: const UnderlineInputBorder(
                              borderSide: BorderSide(
                                  color: Color.fromARGB(255, 74, 137, 92),
                                  width: 3.0),
                            ),
                            focusedBorder: const UnderlineInputBorder(
                              borderSide: BorderSide(
                                  color: Color.fromARGB(255, 74, 137, 92),
                                  width: 3.0),
                            ),
                            helperText: 'Enter language...',
                            helperStyle: const TextStyle(
                              color: Color.fromARGB(255, 74, 137, 92),
                            ),
                            hintText: _controller.hasTags ? '' : "Enter tag...",
                            errorText: error,
                            prefixIconConstraints: BoxConstraints(
                                maxWidth: _distanceToField * 0.74),
                            prefixIcon: tags.isNotEmpty
                                ? SingleChildScrollView(
                                    controller: sc,
                                    scrollDirection: Axis.horizontal,
                                    child: Row(
                                        children: tags.map((String tag) {
                                      return Container(
                                        decoration: const BoxDecoration(
                                          borderRadius: BorderRadius.all(
                                            Radius.circular(20.0),
                                          ),
                                          color:
                                              Color.fromARGB(255, 74, 137, 92),
                                        ),
                                        margin:
                                            const EdgeInsets.only(right: 10.0),
                                        padding: const EdgeInsets.symmetric(
                                            horizontal: 10.0, vertical: 4.0),
                                        child: Row(
                                          mainAxisAlignment:
                                              MainAxisAlignment.spaceBetween,
                                          children: [
                                            InkWell(
                                              child: Text(
                                                '#$tag',
                                                style: const TextStyle(
                                                    color: Colors.white),
                                              ),
                                              onTap: () {
                                                //print("$tag selected");
                                              },
                                            ),
                                            const SizedBox(width: 4.0),
                                            InkWell(
                                              child: const Icon(
                                                Icons.cancel,
                                                size: 14.0,
                                                color: Color.fromARGB(
                                                    255, 233, 233, 233),
                                              ),
                                              onTap: () {
                                                onTagDelete(tag);
                                              },
                                            )
                                          ],
                                        ),
                                      );
                                    }).toList()),
                                  )
                                : null,
                          ),
                          onChanged: onChanged,
                          onSubmitted: onSubmitted,
                        ),
                      );
                    });
                  },
                );
              },
            ),
            ElevatedButton(
              style: ButtonStyle(
                backgroundColor: MaterialStateProperty.all<Color>(
                  const Color.fromARGB(255, 74, 137, 92),
                ),
              ),
              onPressed: () {
                _controller.clearTags();
              },
              child: const Text('CLEAR TAGS'),
            ),
          ],
        ),
      ),
    );
  }
} 

Download Details:

Author: eyoeldefare

Source Code: https://github.com/eyoeldefare/textfield_tags

#textfield #flutter #android 

A Text Field That Allows an Input of Tags Inside The Textfield

Custom Google Places Autocomplete Widget in Flutter

google_places_flutter

Add dependency into pubspec.yml

dependencies:
  flutter:
    sdk: flutter
  google_places_flutter: <last-version>
  

Google AutoComplete TextField Widget code

    GooglePlaceAutoCompleteTextField(
        textEditingController: controller,
        googleAPIKey: "YOUR_GOOGLE_API_KEY",
        inputDecoration: InputDecoration()
        debounceTime: 800 // default 600 ms,
        countries: ["in","fr"],// optional by default null is set
        isLatLngRequired:true,// if you required coordinates from place detail
        getPlaceDetailWithLatLng: (Prediction prediction) {
         // this method will return latlng with place detail
        print("placeDetails" + prediction.lng.toString());
        }, // this callback is called when isLatLngRequired is true
        itmClick: (Prediction prediction) {
         controller.text=prediction.description;
          controller.selection = TextSelection.fromPosition(TextPosition(offset: prediction.description.length));
        }
    )
    

Customization Option

You can customize a text field input decoration and debounce time

Screenshorts

 

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add google_places_flutter

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  google_places_flutter: ^2.0.5

Alternatively, your editor might support flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:google_places_flutter/google_places_flutter.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'package:google_places_flutter/google_places_flutter.dart';
import 'package:google_places_flutter/model/prediction.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: MyHomePage(title: 'Custom Autocomplete sample'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  TextEditingController controller = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        // Here we take the value from the MyHomePage object that was created by
        // the App.build method, and use it to set our appbar title.
        title: Text(widget.title),
      ),
      body: Center(
        // Center is a layout widget. It takes a single child and positions it
        // in the middle of the parent.
        child: Column(
          // Column is also a layout widget. It takes a list of children and
          // arranges them vertically. By default, it sizes itself to fit its
          // children horizontally, and tries to be as tall as its parent.
          //
          // Invoke "debug painting" (press "p" in the console, choose the
          // "Toggle Debug Paint" action from the Flutter Inspector in Android
          // Studio, or the "Toggle Debug Paint" command in Visual Studio Code)
          // to see the wireframe for each widget.
          //
          // Column has various properties to control how it sizes itself and
          // how it positions its children. Here we use mainAxisAlignment to
          // center the children vertically; the main axis here is the vertical
          // axis because Columns are vertical (the cross axis would be
          // horizontal).
          mainAxisAlignment: MainAxisAlignment.start,
          children: <Widget>[
            SizedBox(height: 20),
            placesAutoCompleteTextField(),
          ],
        ),
      ),
    );
  }

  placesAutoCompleteTextField() {
    return Container(
      padding: EdgeInsets.symmetric(horizontal: 20),
      child: GooglePlaceAutoCompleteTextField(
          textEditingController: controller,
          googleAPIKey: "YOUR_GOOGLE_API_KEY",
          inputDecoration: InputDecoration(hintText: "Search your location"),
          debounceTime: 800,
          countries: ["in", "fr"],
          isLatLngRequired: true,
          getPlaceDetailWithLatLng: (Prediction prediction) {
            print("placeDetails" + prediction.lng.toString());
          },
          itmClick: (Prediction prediction) {
            controller.text = prediction.description;

            controller.selection = TextSelection.fromPosition(
                TextPosition(offset: prediction.description.length));
          }
          // default 600 ms ,
          ),
    );
  }
} 

Download Details:

Author: Shrutimahajan

Source Code: https://github.com/Shrutimahajan/Google-AutoComplete-TextField-Flutter

#flutter #textfield 

Custom Google Places Autocomplete Widget in Flutter

Creating Selectable and input Tags (TextField) Has Never Been Easier

flutter_tags_x

Create beautiful tags quickly and easily.

Forked from  (Not supported)

Installing

Add this to your package's pubspec.yaml file: Null-safety version MORE INFO

dependencies:
  flutter_tags: ... # last version

DEMO

Simple usage


import 'package:flutter_tags/flutter_tags.dart';
.
.
.
List _items;
double _fontSize = 14;

@override
void initState(){
    super.initState();
    // if you store data on a local database (sqflite), then you could do something like this
    Model().getItems().then((items){
            _items = items;
        });
}

@override
Widget build(BuildContext context) {
    return Tags(
      key:_tagStateKey,
      textField: TagsTextField(
        textStyle: TextStyle(fontSize: _fontSize),
        constraintSuggestion: true, suggestions: [],
        //width: double.infinity, padding: EdgeInsets.symmetric(horizontal: 10),
        onSubmitted: (String str) {
          // Add item to the data source.
          setState(() {             
             // required             
            _items.add(Item(
                title: str,
                active: true,
                index: 1,                
              ));
          });
        },
      ),
      itemCount: _items.length, // required
      itemBuilder: (int index){          
            final item = _items[index];
    
            return ItemTags(
                  // Each ItemTags must contain a Key. Keys allow Flutter to
                  // uniquely identify widgets.
                  key: Key(index.toString()),
                  index: index, // required
                  title: item.title,
                  active: item.active,
                  customData: item.customData,
                  textStyle: TextStyle( fontSize: _fontSize, ),
                  combine: ItemTagsCombine.withTextBefore,
                  image: ItemTagsImage(
                    image: AssetImage("img.jpg") // OR NetworkImage("https://...image.png")
                  ), // OR null,
                  icon: ItemTagsIcon(
                    icon: Icons.add,
                  ), // OR null,
                  removeButton: ItemTagsRemoveButton(
                    onRemoved: (){
                        // Remove the item from the data source.
                        setState(() {
                            // required
                            _items.removeAt(index);
                        });
                        //required
                        return true;
                    },
                  ), // OR null,
                  onPressed: (item) => print(item),
                  onLongPressed: (item) => print(item),
            );
    
      },
    );    
}

final GlobalKey<TagsState> _tagStateKey = GlobalKey<TagsState>();
// Allows you to get a list of all the ItemTags
_getAllItem(){
    List<Item> lst = _tagStateKey.currentState?.getAllItem;
    if(lst!=null)
        lst.where((a) => a.active==true).forEach( ( a) => print(a.title));        
}

Wrapped widget example

You are free to wrap ItemTags () inside another widget

Tags(  
      itemCount: items.length, 
      itemBuilder: (int index){ 
          return Tooltip(
          message: item.title,
          child:ItemTags(
            title:item.title,
          )
          );
      },
    );    

Tags() parameters

 

PropNameDescriptiondefault value
columnsPossibility to set number of columns when necessarynull
itemCountTag number to displayrequired
symmetryAbility to view and scroll tags horizontallyfalse
horizontalScrollOffset drawer width0.4
heightHorizontalScrollheight for HorizontalScroll to set to display tags correctly60
spacingHorizontal space between the tags6
runSpacingVertical space between the tags14
alignmentHorizontal WrapAlignmentWrapAlignment.center
runAlignmentVertical WrapAlignmentWrapAlignment.center
directionDirection of the ItemTagsAxis.horizontal
verticalDirectionIterate Item from the lower to the upper direction or vice versaVerticalDirection.down
textDirectionText direction of the ItemTagsTextDirection.ltr
itemBuildertag generator 
textFieldadd textFieldTagsTextFiled()

ItemTags() parameters

  • index - required
  • title - required
  • textScaleFactor - custom textScaleFactor
  • active - bool value (default true)
  • pressEnabled - active onPress tag ( default true)
  • customData - Possibility to add any custom value in customData field, you can retrieve this later. A good example: store an id from Firestore document.
  • textStyle - textStyle()
  • alignment - MainAxisAlignment ( default MainAxisAlignment.center)
  • combine - * ability to combine text, icons, images in different ways ( default ItemTagsCombine.imageOrIconOrText)*
  • icon - ItemTagsIcon()
  • image - ItemTagsImage()
  • removeButton - ItemTagsRemoveButton()
  • borderRadius - BorderRadius
  • border - custom border-side
  • padding - default EdgeInsets.symmetric(horizontal: 7, vertical: 5)
  • elevation - default 5
  • singleItem - default false
  • textOverflow - default TextOverflow.fade
  • textColor - default Colors.black
  • textActiveColor - default Colors.white
  • color - default Colors.white
  • activeColor - default Colors.blueGrey
  • highlightColor -
  • splashColor -
  • colorShowDuplicate - default Colors.red
  • onPressed - callback
  • onLongPressed - callback
  • onRemoved - callback

Donate

It takes time to carry on this project. If you found it useful or learned something from the source code please consider the idea of donating 5, 20, 50 € or whatever you can to support the project.

Issues

If you encounter problems, open an issue. Pull request are also welcome.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_tags_x

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_tags_x: ^1.0.0

Alternatively, your editor might support or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_tags_x/flutter_tags_x.dart'; 

example/lib/main.dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import 'package:flutter_tags/flutter_tags.dart';

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Tags Demo',
      theme: ThemeData(
        primarySwatch: Colors.blueGrey,
      ),
      home: MyHomePage(title: 'Flutter Tags'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);
  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage>
    with SingleTickerProviderStateMixin {
  TabController _tabController;
  ScrollController _scrollViewController;

  final List<String> _list = [
    '0',
    'SDK',
    'plugin updates',
    'Facebook',
    '哔了狗了QP又不够了',
    'Kirchhoff',
    'Italy',
    'France',
    'Spain',
    '美',
    'Dart',
    'SDK',
    'Foo',
    'Select',
    'lorem ip',
    '9',
    'Star',
    'Flutter Selectable Tags',
    '1',
    'Hubble',
    '2',
    'Input flutter tags',
    'A B C',
    '8',
    'Android Studio developer',
    'welcome to the jungle',
    'Gauss',
    '美术',
    '互联网',
    '炫舞时代',
    '篝火营地',
  ];

  bool _symmetry = false;
  bool _removeButton = true;
  bool _singleItem = true;
  bool _startDirection = false;
  bool _horizontalScroll = true;
  bool _withSuggesttions = false;
  int _count = 0;
  int _column = 0;
  double _fontSize = 14;

  String _itemCombine = 'withTextBefore';

  String _onPressed = '';

  List _icon = [Icons.home, Icons.language, Icons.headset];

  @override
  void initState() {
    super.initState();
    _tabController = TabController(length: 2, vsync: this);
    _scrollViewController = ScrollController();

    _items = _list.toList();
  }

  List _items;

  final GlobalKey<TagsState> _tagStateKey = GlobalKey<TagsState>();

  @override
  Widget build(BuildContext context) {
    //List<Item> lst = _tagStateKey.currentState?.getAllItem; lst.forEach((f) => print(f.title));
    return Scaffold(
      body: NestedScrollView(
          controller: _scrollViewController,
          headerSliverBuilder: (BuildContext context, bool boxIsScrolled) {
            return <Widget>[
              SliverAppBar(
                title: Text("flutter tags"),
                centerTitle: true,
                pinned: true,
                expandedHeight: 0,
                floating: true,
                forceElevated: boxIsScrolled,
                bottom: TabBar(
                  isScrollable: false,
                  indicatorSize: TabBarIndicatorSize.label,
                  labelStyle: TextStyle(fontSize: 18.0),
                  tabs: [
                    Tab(text: "Demo 1"),
                    Tab(text: "Demo 2"),
                  ],
                  controller: _tabController,
                ),
              )
            ];
          },
          body: TabBarView(
            controller: _tabController,
            children: [
              CustomScrollView(
                slivers: <Widget>[
                  SliverList(
                      delegate: SliverChildListDelegate([
                    Container(
                      decoration: BoxDecoration(
                          border: Border(
                              bottom: BorderSide(
                                  color: Colors.grey[300], width: 0.5))),
                      margin:
                          EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                      child: ExpansionTile(
                        title: Text("Settings"),
                        children: <Widget>[
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _removeButton,
                                        onChanged: (a) {
                                          setState(() {
                                            _removeButton = !_removeButton;
                                          });
                                        }),
                                    Text('Remove Button')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _removeButton = !_removeButton;
                                  });
                                },
                              ),
                              Padding(
                                padding: EdgeInsets.all(5),
                              ),
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _symmetry,
                                        onChanged: (a) {
                                          setState(() {
                                            _symmetry = !_symmetry;
                                          });
                                        }),
                                    Text('Symmetry')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _symmetry = !_symmetry;
                                  });
                                },
                              ),
                              Padding(
                                padding: EdgeInsets.all(5),
                              ),
                              DropdownButton(
                                hint: _column == 0
                                    ? Text("Not set")
                                    : Text(_column.toString()),
                                items: _buildItems(),
                                onChanged: (a) {
                                  setState(() {
                                    _column = a;
                                  });
                                },
                              ),
                            ],
                          ),
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _horizontalScroll,
                                        onChanged: (a) {
                                          setState(() {
                                            _horizontalScroll =
                                                !_horizontalScroll;
                                          });
                                        }),
                                    Text('Horizontal scroll')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _horizontalScroll = !_horizontalScroll;
                                  });
                                },
                              ),
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _singleItem,
                                        onChanged: (a) {
                                          setState(() {
                                            _singleItem = !_singleItem;
                                          });
                                        }),
                                    Text('Single Item')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _singleItem = !_singleItem;
                                  });
                                },
                              ),
                            ],
                          ),
                          Column(
                            children: <Widget>[
                              Text('Font Size'),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  Slider(
                                    value: _fontSize,
                                    min: 6,
                                    max: 30,
                                    onChanged: (a) {
                                      setState(() {
                                        _fontSize = (a.round()).toDouble();
                                      });
                                    },
                                  ),
                                  Text(_fontSize.toString()),
                                  Padding(
                                    padding:
                                        EdgeInsets.symmetric(horizontal: 20),
                                  ),
                                  Container(
                                    height: 30,
                                    width: 30,
                                    //color: Colors.blueGrey,
                                    child: IconButton(
                                      padding: EdgeInsets.all(0),
                                      //color: Colors.white,
                                      icon: Icon(Icons.add),
                                      onPressed: () {
                                        setState(() {
                                          _count++;
                                          _items.add(_count.toString());
                                          //_items.removeAt(3); _items.removeAt(10);
                                        });
                                      },
                                    ),
                                  ),
                                  Padding(
                                    padding:
                                        EdgeInsets.symmetric(horizontal: 5),
                                  ),
                                  Container(
                                    height: 30,
                                    width: 30,
                                    //color: Colors.grey,
                                    child: IconButton(
                                      padding: EdgeInsets.all(0),
                                      //color: Colors.white,
                                      icon: Icon(Icons.refresh),
                                      onPressed: () {
                                        setState(() {
                                          _items = _list.toList();
                                        });
                                      },
                                    ),
                                  ),
                                ],
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                    Padding(
                      padding: EdgeInsets.all(20),
                    ),
                    _tags1,
                    Container(
                        padding: EdgeInsets.all(20),
                        child: Column(
                          children: <Widget>[
                            Divider(
                              color: Colors.blueGrey,
                            ),
                            Padding(
                              padding: EdgeInsets.symmetric(vertical: 20),
                              child: Text(_onPressed),
                            ),
                          ],
                        )),
                  ])),
                ],
              ),
              CustomScrollView(
                slivers: <Widget>[
                  SliverList(
                      delegate: SliverChildListDelegate([
                    Container(
                      decoration: BoxDecoration(
                          border: Border(
                              bottom: BorderSide(
                                  color: Colors.grey[300], width: 0.5))),
                      margin:
                          EdgeInsets.symmetric(horizontal: 10, vertical: 10),
                      child: ExpansionTile(
                        title: Text("Settings"),
                        children: <Widget>[
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _withSuggesttions,
                                        onChanged: (a) {
                                          setState(() {
                                            _withSuggesttions =
                                                !_withSuggesttions;
                                          });
                                        }),
                                    Text('Suggestions')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _withSuggesttions = !_withSuggesttions;
                                  });
                                },
                              ),
                              Padding(
                                padding: EdgeInsets.all(20),
                              ),
                              DropdownButton(
                                hint: Text(_itemCombine),
                                items: _buildItems2(),
                                onChanged: (val) {
                                  setState(() {
                                    _itemCombine = val;
                                  });
                                },
                              ),
                            ],
                          ),
                          Row(
                            mainAxisAlignment: MainAxisAlignment.center,
                            children: <Widget>[
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _horizontalScroll,
                                        onChanged: (a) {
                                          setState(() {
                                            _horizontalScroll =
                                                !_horizontalScroll;
                                          });
                                        }),
                                    Text('Horizontal scroll')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _horizontalScroll = !_horizontalScroll;
                                  });
                                },
                              ),
                              GestureDetector(
                                child: Row(
                                  children: <Widget>[
                                    Checkbox(
                                        value: _startDirection,
                                        onChanged: (a) {
                                          setState(() {
                                            _startDirection = !_startDirection;
                                          });
                                        }),
                                    Text('Start Direction')
                                  ],
                                ),
                                onTap: () {
                                  setState(() {
                                    _startDirection = !_startDirection;
                                  });
                                },
                              ),
                            ],
                          ),
                          Column(
                            children: <Widget>[
                              Text('Font Size'),
                              Row(
                                mainAxisAlignment: MainAxisAlignment.center,
                                children: <Widget>[
                                  Slider(
                                    value: _fontSize,
                                    min: 6,
                                    max: 30,
                                    onChanged: (a) {
                                      setState(() {
                                        _fontSize = (a.round()).toDouble();
                                      });
                                    },
                                  ),
                                  Text(_fontSize.toString()),
                                ],
                              ),
                            ],
                          ),
                        ],
                      ),
                    ),
                    Padding(
                      padding: EdgeInsets.all(20),
                    ),
                    _tags2,
                    Container(
                        padding: EdgeInsets.all(20),
                        child: Column(
                          children: <Widget>[
                            Divider(
                              color: Colors.blueGrey,
                            ),
                            Padding(
                              padding: EdgeInsets.symmetric(vertical: 20),
                              child: Text(_onPressed),
                            ),
                          ],
                        )),
                  ])),
                ],
              ),
            ],
          )),
    );
  }

  Widget get _tags1 {
    return Tags(
      key: _tagStateKey,
      symmetry: _symmetry,
      columns: _column,
      horizontalScroll: _horizontalScroll,
      //verticalDirection: VerticalDirection.up, textDirection: TextDirection.rtl,
      heightHorizontalScroll: 60 * (_fontSize / 14),
      itemCount: _items.length,
      itemBuilder: (index) {
        final item = _items[index];

        return ItemTags(
          key: Key(index.toString()),
          index: index,
          title: item,
          pressEnabled: true,
          activeColor: Colors.blueGrey[600],
          singleItem: _singleItem,
          splashColor: Colors.green,
          combine: ItemTagsCombine.withTextBefore,
          image: index > 0 && index < 5
              ? ItemTagsImage(
                  //image: AssetImage("img/p$index.jpg"),
                  child: Image.network(
                  "http://www.clipartpanda.com/clipart_images/user-66327738/download",
                  width: 16 * _fontSize / 14,
                  height: 16 * _fontSize / 14,
                ))
              : (1 == 1
                  ? ItemTagsImage(
                      image: NetworkImage(
                          "https://d32ogoqmya1dw8.cloudfront.net/images/serc/empty_user_icon_256.v2.png"),
                    )
                  : null),
          icon: (item == '0' || item == '1' || item == '2')
              ? ItemTagsIcon(
                  icon: _icon[int.parse(item)],
                )
              : null,
          removeButton: _removeButton
              ? ItemTagsRemoveButton(
                  onRemoved: () {
                    setState(() {
                      _items.removeAt(index);
                    });
                    return true;
                  },
                )
              : null,
          textScaleFactor:
              utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1,
          textStyle: TextStyle(
            fontSize: _fontSize,
          ),
          onPressed: (item) => print(item),
        );
      },
    );
  }

  // Position for popup menu
  Offset _tapPosition;

  Widget get _tags2 {
    //popup Menu
    final RenderBox overlay = Overlay.of(context).context?.findRenderObject();

    ItemTagsCombine combine = ItemTagsCombine.onlyText;

    switch (_itemCombine) {
      case 'onlyText':
        combine = ItemTagsCombine.onlyText;
        break;
      case 'onlyIcon':
        combine = ItemTagsCombine.onlyIcon;
        break;
      case 'onlyIcon':
        combine = ItemTagsCombine.onlyIcon;
        break;
      case 'onlyImage':
        combine = ItemTagsCombine.onlyImage;
        break;
      case 'imageOrIconOrText':
        combine = ItemTagsCombine.imageOrIconOrText;
        break;
      case 'withTextAfter':
        combine = ItemTagsCombine.withTextAfter;
        break;
      case 'withTextBefore':
        combine = ItemTagsCombine.withTextBefore;
        break;
    }

    return Tags(
      key: Key("2"),
      symmetry: _symmetry,
      columns: _column,
      horizontalScroll: _horizontalScroll,
      verticalDirection:
          _startDirection ? VerticalDirection.up : VerticalDirection.down,
      textDirection: _startDirection ? TextDirection.rtl : TextDirection.ltr,
      heightHorizontalScroll: 60 * (_fontSize / 14),
      textField: _textField,
      itemCount: _items.length,
      itemBuilder: (index) {
        final item = _items[index];

        return GestureDetector(
          child: ItemTags(
            key: Key(index.toString()),
            index: index,
            title: item,
            pressEnabled: false,
            activeColor: Colors.green[400],
            combine: combine,
            image: index > 0 && index < 5
                ? ItemTagsImage(image: AssetImage("img/p$index.jpg"))
                : (1 == 1
                    ? ItemTagsImage(
                        image: NetworkImage(
                            "https://image.flaticon.com/icons/png/512/44/44948.png"))
                    : null),
            icon: (item == '0' || item == '1' || item == '2')
                ? ItemTagsIcon(
                    icon: _icon[int.parse(item)],
                  )
                : null,
            removeButton: ItemTagsRemoveButton(
              backgroundColor: Colors.green[900],
              onRemoved: () {
                setState(() {
                  _items.removeAt(index);
                });
                return true;
              },
            ),
            textScaleFactor:
                utf8.encode(item.substring(0, 1)).length > 2 ? 0.8 : 1,
            textStyle: TextStyle(
              fontSize: _fontSize,
            ),
          ),
          onTapDown: (details) => _tapPosition = details.globalPosition,
          onLongPress: () {
            showMenu(
                    //semanticLabel: item,
                    items: <PopupMenuEntry>[
                  PopupMenuItem(
                    child: Text(item, style: TextStyle(color: Colors.blueGrey)),
                    enabled: false,
                  ),
                  PopupMenuDivider(),
                  PopupMenuItem(
                    value: 1,
                    child: Row(
                      children: <Widget>[
                        Icon(Icons.content_copy),
                        Text("Copy text"),
                      ],
                    ),
                  ),
                ],
                    context: context,
                    position: RelativeRect.fromRect(
                        _tapPosition & Size(40, 40),
                        Offset.zero &
                            overlay
                                .size) // & RelativeRect.fromLTRB(65.0, 40.0, 0.0, 0.0),
                    )
                .then((value) {
              if (value == 1) Clipboard.setData(ClipboardData(text: item));
            });
          },
        );
      },
    );
  }

  TagsTextField get _textField {
    return TagsTextField(
      autofocus: false,
      //width: double.infinity,
      padding: EdgeInsets.symmetric(horizontal: 10, vertical: 0),
      textStyle: TextStyle(
        fontSize: _fontSize,
        //height: 1
      ),
      enabled: true,
      constraintSuggestion: true,
      suggestions: _withSuggesttions
          ? [
              "One",
              "two",
              "android",
              "Dart",
              "flutter",
              "test",
              "tests",
              "androids",
              "androidsaaa",
              "Test",
              "suggest",
              "suggestions",
              "互联网",
              "last",
              "lest",
              "炫舞时代"
            ]
          : null,
      onSubmitted: (String str) {
        setState(() {
          _items.add(str);
        });
      },
    );
  }

  List<DropdownMenuItem> _buildItems() {
    List<DropdownMenuItem> list = [];

    int count = 19;

    list.add(
      DropdownMenuItem(
        child: Text("Not set"),
        value: 0,
      ),
    );

    for (int i = 1; i < count; i++)
      list.add(
        DropdownMenuItem(
          child: Text(i.toString()),
          value: i,
        ),
      );

    return list;
  }

  List<DropdownMenuItem> _buildItems2() {
    List<DropdownMenuItem> list = [];

    list.add(DropdownMenuItem(
      child: Text("onlyText"),
      value: 'onlyText',
    ));

    list.add(DropdownMenuItem(
      child: Text("onlyIcon"),
      value: 'onlyIcon',
    ));
    list.add(DropdownMenuItem(
      child: Text("onlyImage"),
      value: 'onlyImage',
    ));
    list.add(DropdownMenuItem(
      child: Text("imageOrIconOrText"),
      value: 'imageOrIconOrText',
    ));
    list.add(DropdownMenuItem(
      child: Text("withTextBefore"),
      value: 'withTextBefore',
    ));
    list.add(DropdownMenuItem(
      child: Text("withTextAfter"),
      value: 'withTextAfter',
    ));

    return list;
  }
} 

Download Details:

Author: avdosev

Source Code: https://github.com/avdosev/flutter_tags/

#flutter #textfield #tags 

Creating Selectable and input Tags (TextField) Has Never Been Easier

A Custom Auth Code Textfield Widget

flutter_auth_code_textfield

A custom auth code textfield widget.

一个Flutter自定义的验证码Widget,纯Flutter代码,支持安卓,iOS.

Useage

Mode: singleItem , like Keep

Item模式,如Keep的风格。

AuthCodeTextfield(
                  mode: AuthCodeMode.singleItem,
                  itemWidth: 50,
                  itemHeight: 50,
                  itemSpacing: 35 * scaleWidth,
                  itemBackgroundColor: Color.fromRGBO(120, 114, 127, 1),
                  textColor: Colors.white,
                  cursorColor: Color.fromRGBO(94,178,138,1),
                  onChanged: (s) {
                    setState(() {
                      _inputText = s;
                    });
                  },
                ),
iOSAndroid

Mode: bottomLine , like DingDing

bottomLine模式,如钉钉的风格。

AuthCodeTextfield(
                  mode: AuthCodeMode.bottomLine,
                  itemWidth: 50,
                  itemHeight: 60,
                  itemSpacing: 35 * scaleWidth,
                  itemBottomLineColor: Color.fromRGBO(229, 231, 233, 1),
                  cursorWidth: 1,
                  cursorHeight: 30,
                  onChanged: (s) {
                    _inputText = s;
                    if (s.toString().length >= 4 && widget.onSubmited != null) {
                      widget.onSubmited(_inputText);
                      Navigator.pop(context);
                    }
                  },
                ),
iOSAndroid

Getting Started

Add this to your package's pubspec.yaml file:

dependencies: auth_code_textfield: ^0.0.2

If you want to support flutter 2.0 null safety please:

dependencies: auth_code_textfield: ^2.0.0

This project is a starting point for a Dart package, a library module containing code that can be shared easily across multiple Flutter or Dart projects.

For help getting started with Flutter, view our online documentation, which offers tutorials, samples, guidance on mobile development, and a full API reference.

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add auth_code_textfield

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  auth_code_textfield: ^2.0.0

Alternatively, your editor might support or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:auth_code_textfield/auth_code_textfield.dart'; 

example/lib/main.dart

import 'package:flutter/material.dart';
import 'item_login_page.dart';
import 'bottom_line_login_page.dart';
import 'package:flutter/services.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
        visualDensity: VisualDensity.adaptivePlatformDensity,
      ),
      home: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key? key, this.title}) : super(key: key);
  final String? title;
  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  String _receiveCode = '';
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        brightness: Brightness.dark,
        title: Text(widget.title ?? ""),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text('Receive code : $_receiveCode'),
            SizedBox(height: 20),
            Container(
              width: 200,
              height: 44,
              child: ElevatedButton(
                onPressed: () {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (_) => ItemLoginDemoPage(
                          onSubmited: (s) {
                            _receiveCode = s;
                            setState(() {});
                          },
                        ),
                      ));
                },
                child: Text('item mode demo'),
              ),
            ),
            SizedBox(height: 20),
            Container(
              width: 200,
              height: 44,
              child: ElevatedButton(
                onPressed: () {
                  Navigator.push(
                      context,
                      MaterialPageRoute(
                        builder: (_) => BottomLineLoginPage(
                          onSubmited: (s) {
                            _receiveCode = s;
                            setState(() {});
                          },
                        ),
                      ));
                },
                child: Text('bottom line mode demo'),
              ),
            ),
          ],
        ),
      ), // This trailing comma makes auto-formatting nicer for build methods.
    );
  }
} 

Download Details:

Author: JerryFans

Source Code: https://github.com/JerryFans/flutter_auth_code_textfield

#flutter #textfield #widget 

A Custom Auth Code Textfield Widget

A TextField Widget to Help Display Different Style Pin

Flutter pin input

PinInputTextField is a TextField widget to help display different style pin. It supports all the platforms flutter supports.

Feature 🌟

  • allow you customized the shape, any!
  • built-in 4 commonly used pin styles of shape
  • obscure support
  • solid support
  • enterColor support
  • cursor support
  • support all the textField properties theoretically
  • Flutter all platform support

Example 🦀

Thanks to the Flutter Web, you can enjoy the preview by website without any installation.

Installing 🔧

Install the latest version from pub.

Usage ✍️

Attributes

Customizable attributes for PinInputTextField

Attribute NameExample ValueDescription
pinLength6The max length of pin, the default is 6
onSubmit(String pin){}The callback will execute when user click done, sometimes is not working in Android.
decorationBoxLooseDecorationDecorate the pin, there are 3 inside styles, the default is BoxLooseDecoration
inputFormattersWhitelistingTextInputFormatter.digitsOnlyJust like TextField's inputFormatter, the default is WhitelistingTextInputFormatter.digitsOnly
keyboardTypeTextInputType.phoneJust like TextField's keyboardType, the default is TextInputType.phone
pinEditingControllerPinEditingControllerControls the pin being edited. If null, this widget will create its own PinEditingController
autoFocusfalseSame as TextField's autoFocus, the default is false
focusNodeFocusNodeSame as TextField's focusNode
textInputActionTextInputAction.doneSame as TextField's textInputAction, not working in digit mode
enabledtrueSame as TextField's enabled, the default is true
onChanged(String pin){}Same as TextField's onChanged
textCapitalizationTextCapitalization.wordsSame as TextField's textCapitalization
cursorCursor.disabled()The cursor of the pin, default is not enabled

FormField

Instead of using PinInputTextField, using PinInputTextFormField to control validate.

ObscureStyle

/// Determine whether replace [obscureText] with number.
final bool isTextObscure;
/// The display text when [isTextObscure] is true, emoji supported
final String obscureText;

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add flutter_pin_input

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:
  flutter_pin_input: ^1.1.0

Alternatively, your editor might support or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:flutter_pin_input/flutter_pin_input.dart'; 

example/lib/main.dart

import 'dart:ui';

import 'package:flutter/material.dart';
import 'package:flutter_pin_input/flutter_pin_input.dart';

void main() => runApp(MyApp());

const _kInputHeight = 64.0;
const _kDefaultHint = 'abcd';

class MyApp extends StatelessWidget {
  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Pin Demo',
      debugShowCheckedModeBanner: false,
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: ListPage(),
    );
  }
}

enum TextFieldType {
  NORMAL,
  FORM,
}

class ListPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('demo'),
      ),
      body: ListView.builder(
        itemCount: TextFieldType.values.length,
        itemBuilder: (ctx, index) {
          return ListTile(
            title: Text(TextFieldType.values[index].toString()),
            onTap: () {
              Navigator.push(
                  ctx,
                  MaterialPageRoute(
                      builder: (context) =>
                          MyHomePage(TextFieldType.values[index])));
            },
          );
        },
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage(this.textFieldType, {Key key}) : super(key: key);

  final TextFieldType textFieldType;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  /// Default max pin length.
  static final int _pinLength = 4;

  /// PinInputTextFormField form-key
  final GlobalKey<FormFieldState<String>> _formKey =
      GlobalKey<FormFieldState<String>>(debugLabel: '_formkey');

  /// Control the input text field.
  TextEditingController _pinEditingController =
      TextEditingController(text: '123');

  GlobalKey<ScaffoldState> _globalKey =
      GlobalKey<ScaffoldState>(debugLabel: 'home page global key');

  /// Decorate the outside of the Pin.
  PinDecoration _pinDecoration;

  /// Control whether show the obscureCode.
  bool _obscureEnable = false;

  PinEntryType _pinEntryType = PinEntryType.underline;
  ColorBuilder _solidColor =
      PinListenColorBuilder(Colors.grey, Colors.grey[400]);
  bool _solidEnable = false;

  /// Control whether textField is enable.
  bool _enable = true;

  /// Indicate whether the PinInputTextFormField has error or not
  /// after being validated.
  bool _hasError = false;

  bool _cursorEnable = true;

  /// Set a pin to the textField.
  void _setPinValue() {
    _pinEditingController
      ..text = "0000"
      ..selection = TextSelection.collapsed(offset: 4);
  }

  @override
  void initState() {
    _pinEditingController.addListener(() {
      debugPrint('controller execute. pin:${_pinEditingController.text}');
    });
    super.initState();
    _selectedMenu(PinEntryType.underline);
  }

  @override
  void dispose() {
    _pinEditingController.dispose();
    super.dispose();
  }

  void _selectedMenu(PinEntryType type) {
    _pinEntryType = type;
    switch (type) {
      case PinEntryType.underline:
        setState(() {
          _pinDecoration = UnderlineDecoration(
            colorBuilder: PinListenColorBuilder(Colors.cyan, Colors.green),
            bgColorBuilder: _solidEnable ? _solidColor : null,
            obscureStyle: ObscureStyle(
              isTextObscure: _obscureEnable,
              obscureText: '😂',
            ),
            hintText: _kDefaultHint,
          );
        });
        break;
      case PinEntryType.boxTight:
        setState(() {
          _pinDecoration = BoxTightDecoration(
            bgColorBuilder: _solidEnable ? _solidColor : null,
            obscureStyle: ObscureStyle(
              isTextObscure: _obscureEnable,
              obscureText: '👿',
            ),
            hintText: _kDefaultHint,
          );
        });
        break;
      case PinEntryType.boxLoose:
        setState(() {
          _pinDecoration = BoxLooseDecoration(
            strokeColorBuilder:
                PinListenColorBuilder(Colors.cyan, Colors.green),
            bgColorBuilder: _solidEnable ? _solidColor : null,
            obscureStyle: ObscureStyle(
              isTextObscure: _obscureEnable,
              obscureText: '☺️',
            ),
            hintText: _kDefaultHint,
          );
        });
        break;
      case PinEntryType.circle:
        setState(() {
          _pinDecoration = CirclePinDecoration(
            bgColorBuilder: _solidEnable ? _solidColor : null,
            strokeColorBuilder:
                PinListenColorBuilder(Colors.cyan, Colors.green),
            obscureStyle: ObscureStyle(
              isTextObscure: _obscureEnable,
              obscureText: '🤪',
            ),
            hintText: _kDefaultHint,
          );
        });
        break;
      case PinEntryType.customized:
        setState(() {
          _pinDecoration = ExampleDecoration();
        });
        break;
    }
  }

  _buildExampleBody() {
    switch (widget.textFieldType) {
      case TextFieldType.NORMAL:
        return _buildPinInputTextFieldExample();
      case TextFieldType.FORM:
        return _buildPinInputTextFormFieldExample();
    }
  }

  _buildConfigWidget() {
    return [
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            'obscureEnabled',
            style: TextStyle(
              fontSize: 18,
            ),
          ),
          SizedBox(
            width: 12,
          ),
          Checkbox(
              value: _obscureEnable,
              onChanged: (enable) {
                setState(() {
                  _obscureEnable = enable;
                  _selectedMenu(_pinEntryType);
                });
              }),
        ],
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            'solidEnabled',
            style: TextStyle(
              fontSize: 18,
            ),
          ),
          SizedBox(
            width: 12,
          ),
          Checkbox(
              value: _solidEnable,
              onChanged: (enable) {
                setState(() {
                  _solidEnable = enable;
                  _selectedMenu(_pinEntryType);
                });
              }),
        ],
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            'enabled',
            style: TextStyle(fontSize: 18),
          ),
          SizedBox(width: 12),
          Checkbox(
            value: _enable,
            onChanged: (enable) {
              setState(() {
                _enable = enable;
              });
            },
          )
        ],
      ),
      Row(
        mainAxisAlignment: MainAxisAlignment.center,
        children: <Widget>[
          Text(
            'cursor enabled',
            style: TextStyle(fontSize: 18),
          ),
          SizedBox(width: 12),
          Checkbox(
            value: _cursorEnable,
            onChanged: (enable) {
              setState(() {
                _cursorEnable = enable;
              });
            },
          )
        ],
      ),
    ];
  }

  Widget _buildPinInputTextFieldExample() {
    return Center(
      // Center is a layout widget. It takes a single child and positions it
      // in the middle of the parent.
      child: ListView(
        children: <Widget>[
          ..._buildConfigWidget(),
          SizedBox(
            height: _kInputHeight,
            child: PinInputTextField(
              pinLength: _pinLength,
              decoration: _pinDecoration,
              controller: _pinEditingController,
              textInputAction: TextInputAction.go,
              enabled: _enable,
              keyboardType: TextInputType.text,
              textCapitalization: TextCapitalization.characters,
              onSubmit: (pin) {
                debugPrint('submit pin:$pin');
              },
              onChanged: (pin) {
                debugPrint('onChanged execute. pin:$pin');
              },
              enableInteractiveSelection: false,
              cursor: Cursor(
                width: 2,
                color: Colors.lightBlue,
                radius: Radius.circular(1),
                enabled: _cursorEnable,
              ),
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildPinInputTextFormFieldExample() {
    return Center(
      // Center is a layout widget. It takes a single child and positions it
      // in the middle of the parent.
      child: ListView(
        children: <Widget>[
          ..._buildConfigWidget(),
          SizedBox(
            height: _kInputHeight,
            child: PinInputTextFormField(
              key: _formKey,
              pinLength: _pinLength,
              decoration: _pinDecoration,
              controller: _pinEditingController,
              textInputAction: TextInputAction.go,
              enabled: _enable,
              keyboardType: TextInputType.text,
              textCapitalization: TextCapitalization.characters,
              onSubmit: (pin) {
                if (_formKey.currentState.validate()) {
                  _formKey.currentState.save();
                }
              },
              onChanged: (pin) {
                debugPrint('onChanged execute. pin:$pin');
              },
              onSaved: (pin) {
                debugPrint('onSaved pin:$pin');
              },
              validator: (pin) {
                if (pin.isEmpty) {
                  setState(() {
                    _hasError = true;
                  });
                  return 'Pin cannot empty.';
                }
                if (pin.length < _pinLength) {
                  setState(() {
                    _hasError = true;
                  });
                  return 'Pin is not completed.';
                }
                setState(() {
                  _hasError = false;
                });
                return null;
              },
              cursor: Cursor(
                width: 2,
                color: Colors.lightBlue,
                radius: Radius.circular(1),
                enabled: _cursorEnable,
              ),
            ),
          ),
          SizedBox(
            height: 16,
          ),
          Row(
            mainAxisAlignment: MainAxisAlignment.center,
            children: <Widget>[
              ElevatedButton(
                onPressed: () {
                  if (_formKey.currentState.validate()) {
                    _formKey.currentState.save();
                  }
                },
                child: Text(
                  'Submit',
                  style: TextStyle(
                    color: Colors.white,
                  ),
                ),
                style: ElevatedButton.styleFrom(
                  elevation: 2,
                  shape: RoundedRectangleBorder(
                    borderRadius: BorderRadius.circular(5),
                  ),
                  primary: _hasError ? Colors.red : Colors.green,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      key: _globalKey,
      appBar: AppBar(
        title: Text(widget.textFieldType.toString()),
        actions: <Widget>[
          PopupMenuButton<PinEntryType>(
            icon: Icon(Icons.more_vert),
            onSelected: _selectedMenu,
            itemBuilder: (context) {
              return [
                PopupMenuItem(
                  child: Text('underline decoration'),
                  value: PinEntryType.underline,
                ),
                PopupMenuItem(
                  child: Text('box loose decoration'),
                  value: PinEntryType.boxLoose,
                ),
                PopupMenuItem(
                  child: Text('box tight decoration'),
                  value: PinEntryType.boxTight,
                ),
                PopupMenuItem(
                  child: Text('circle decoration'),
                  value: PinEntryType.circle,
                ),
                PopupMenuItem(
                  child: Text('Customize decorarion'),
                  value: PinEntryType.customized,
                )
              ];
            },
          ),
        ],
      ),
      body: _buildExampleBody(),
      floatingActionButton: FloatingActionButton(
        child: Icon(Icons.refresh),
        tooltip: 'set new value',
        onPressed: () {
          _setPinValue();
        },
      ),
    );
  }
}

class ExampleDecoration extends PinDecoration {
  ExampleDecoration({
    TextStyle textStyle,
    ObscureStyle obscureStyle,
    String errorText,
    TextStyle errorTextStyle,
    String hintText,
    TextStyle hintTextStyle,
    ColorBuilder bgColorBuilder,
  }) : super(
          textStyle: textStyle,
          obscureStyle: obscureStyle,
          errorText: errorText,
          errorTextStyle: errorTextStyle,
          hintText: hintText,
          hintTextStyle: hintTextStyle,
        );

  @override
  PinDecoration copyWith({
    TextStyle textStyle,
    ObscureStyle obscureStyle,
    String errorText,
    TextStyle errorTextStyle,
    String hintText,
    TextStyle hintTextStyle,
    ColorBuilder bgColorBuilder,
  }) {
    return ExampleDecoration(
        textStyle: textStyle ?? this.textStyle,
        obscureStyle: obscureStyle ?? this.obscureStyle,
        errorText: errorText ?? this.errorText,
        errorTextStyle: errorTextStyle ?? this.errorTextStyle,
        hintText: hintText ?? this.hintText,
        hintTextStyle: hintTextStyle ?? this.hintTextStyle,
        bgColorBuilder: bgColorBuilder);
  }

  @override
  void notifyChange(String pin) {}

  @override
  void drawPin(
    Canvas canvas,
    Size size,
    String text,
    int pinLength,
    Cursor cursor,
  ) {
    /// You can draw anything you want here.
    canvas.drawLine(
      Offset.zero,
      Offset(size.width, size.height),
      Paint()
        ..color = Colors.red
        ..strokeWidth = 10
        ..style = PaintingStyle.stroke
        ..isAntiAlias = true,
    );
  }

  @override
  PinEntryType get pinEntryType => PinEntryType.customized;
}

Download Details:

Author: devasx666

Source Code: https://github.com/devasx666/flutter-pin-input

#flutter #textfield 

A TextField Widget to Help Display Different Style Pin

Flutter TextField Widget That Automatically Resizes Text Field

Auto Size TextField

✍️ Flutter TextField widget that automatically resizes text field to fit perfectly within its bounds.

Note: Kudos to @leisim! This work is inspired by his awesome lib Auto Size Text. Please check it out if you want to auto size the Flutter Text widget content.

Show some ❤️ and star the repo to support the project

TODO

  • [ ] Update README.md to show examples of more use cases
  • [ ] Add more unit tests

Contents

Usage

AutoSizeTextField behaves exactly like a TextField. The only difference is that it resizes text to fit within its bounds.

AutoSizeTextField(  controller: _textEditingController,  style: TextStyle(fontSize: 20),  maxLines: 2,)

Note: AutoSizeTextField needs bounded constraints to resize the text. More info here.

fullwidth (default value: true)

The fullwidth parameter extends the width of TextField to its parent's BoxContraints to occupy full width.

Set to false to let the width TextField determined by the width of the text.

maxLines

The maxLines parameter works like you are used to with the Text widget. If there is no maxLines parameter specified, the AutoSizeTextField only fits the text according to the available width and height.

AutoSizeTextField(  controller: _textEditingController,  style: TextStyle(fontSize: 30),  maxLines: null,  decoration: InputDecoration(    border: InputBorder.none,    isDense: true,    contentPadding: const EdgeInsets.all(20)  ),)

minFontSize & maxFontSize

The AutoSizeTextField starts with TextStyle.fontSize. It measures the resulting text and rescales it to fit within its bonds. You can however set the allowed range of the resulting font size.

With minFontSize you can specify the smallest possible font size. If the text still doesn't fit, it will be handled according to overflow. The default minFontSize is 12.

maxFontSize sets the largest possible font size. This is useful if the TextStyle inherits the font size and you want to constrain it.

AutoSizeTextField(  controller: _textEditingController,  style: TextStyle(fontSize: 30),  minFontSize: 18,  maxLines: 4,  overflow: TextOverflow.ellipsis,)

stepGranularity

The AutoSizeTextField will try each font size, starting with TextStyle.fontSize until the text fits within its bounds.
stepGranularity specifies how much the font size is decreased each step. Usually, this value should not be below 1 for best performance.

AutoSizeTextField(  controller: _textEditingController,  style: TextStyle(fontSize: 40),  minFontSize: 10,  stepGranularity: 10,  maxLines: 4,  overflow: TextOverflow.ellipsis,)

presetFontSizes

If you want to allow only specific font sizes, you can set them with presetFontSizes. If presetFontSizes is set, minFontSize, maxFontSize and stepGranularity will be ignored.

AutoSizeTextField(  controller: _textEditingController,  presetFontSizes: [40, 20, 14],  maxLines: 4,)

overflowReplacement

If the text is overflowing and does not fit its bounds, this widget is displayed instead. This can be useful to prevent text being too small to read.

AutoSizeTextField(  maxLines: 1,  controller: _textEditingController)

Parameters

ParameterDescription
key*Controls how one widget replaces another widget in the tree.
textKeySets the key for the resulting Text widget
style*If non-null, the style to use for this text
fullwidthDefault: true, It extends the width of TextField to its parent's BoxContraints to occupy full width. Set to false to let the width TextField determined by the width of the text.
minFontSizeThe minimum text size constraint to be used when auto-sizing text.
Is being ignored if presetFontSizes is set.
maxFontSizeThe maximum text size constraint to be used when auto-sizing text.
Is being ignored if presetFontSizes is set.
stepGranularityThe step size in which the font size is being adapted to constraints.
presetFontSizesPredefines all the possible font sizes.
Important: presetFontSizes have to be in descending order.
locale*Used to select a font when the same Unicode character can be rendered differently, depending on the locale.
wrapWordsWhether words which don't fit in one line should be wrapped. Defaults to true to behave like Text.
overflowReplacementIf the text is overflowing and does not fit its bounds, this widget is displayed instead.
maxLinesAn optional maximum number of lines for the text to span.
minWidthAn optional min width for input field. Only set it when fullwidth = false
  • Parameters marked with * behave exactly the same as in TextField.
  • The unlisted parameters behave exactly the same as TextField.

Performance

AutoSizeTextField is really fast. In fact, you can replace all your TextField widgets with AutoSizeTextField.
Nevertheless you should not use an unreasonable high fontSize in your TextStyle. E.g. don't set the fontSize to 1000 if you know, that the text will never be larger than 30.

If your font size has a very large range, consider increasing stepGranularity.

Troubleshooting

Missing bounds

If AutoSizeTextField overflows or does not resize the text, you should check if it has constrained width and height.

Wrong code:

Row(  children: <Widget>[    AutoSizeTextField(      controller: _textEditingController,      maxLines: 1,    ),  ],)

Because Row and other widgets like Container, Column or ListView do not constrain their children, the text will overflow.
You can fix this by constraining the AutoSizeTextField. Wrap it with Expanded in case of Row and Column or use a SizedBox or another widget with fixed width (and height).

Correct code:

Row(  children: <Widget>[    Expanded( // Constrains AutoSizeTextField to the width of the Row      child: AutoSizeTextField(        controller: _textEditingController,        maxLines: 1,      )    ),  ],)}

MinFontSize too large

AutoSizeTextField does not resize text below the minFontSize which defaults to 12.:

Use this package as a library

Depend on it

Run this command:

With Flutter:

 $ flutter pub add auto_size_text_field

This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get):

dependencies:  auto_size_text_field: ^1.0.1

Alternatively, your editor might support or flutter pub get. Check the docs for your editor to learn more.

Import it

Now in your Dart code, you can use:

import 'package:auto_size_text_field/auto_size_text_field.dart'; 

example/lib/main.dart

import 'package:auto_size_text_field/auto_size_text_field.dart';import 'package:flutter/material.dart';void main() {  runApp(MyApp());}class MyApp extends StatelessWidget {  // This widget is the root of your application.  @override  Widget build(BuildContext context) {    return MaterialApp(      title: 'Auto Size TextField Example',      theme: ThemeData(        primarySwatch: Colors.amber,        visualDensity: VisualDensity.adaptivePlatformDensity,      ),      home: MyHomePage(title: 'Auto Size TextField Demo'),    );  }}class MyHomePage extends StatefulWidget {  MyHomePage({Key key, @required this.title}) : super(key: key);  final String title;  @override  _MyHomePageState createState() => _MyHomePageState();}class _MyHomePageState extends State<MyHomePage> {  TextEditingController _textEditingControllerOne;  TextEditingController _textEditingControllerTwo;  TextEditingController _textEditingControllerThree;  TextEditingController _textEditingControllerFour;  TextEditingController _textEditingControllerFive;  @override  Widget build(BuildContext context) {    return Scaffold(      appBar: AppBar(        title: Text(widget.title),      ),      body: SingleChildScrollView(        child: Center(          child: Column(            mainAxisAlignment: MainAxisAlignment.center,            children: <Widget>[              SizedBox(height: 48),              Text(                'Fixed width (full width of parent\'s BoxConstraints)',              ),              Padding(                padding: const EdgeInsets.symmetric(horizontal: 24),                child: AutoSizeTextField(                  controller: _textEditingControllerOne,                  minFontSize: 24,                  style: TextStyle(fontSize: 64),                ),              ),              SizedBox(                height: 48,              ),              Text(                'Auto adjusted width based on contents',              ),              Padding(                padding: const EdgeInsets.symmetric(horizontal: 24),                child: AutoSizeTextField(                  textAlign: TextAlign.center,                  fullwidth: false,                  controller: _textEditingControllerTwo,                  minFontSize: 24,                  style: TextStyle(fontSize: 64),                ),              ),              SizedBox(height: 48),              Text('Auto adjusted width with hintText and minWidth'),              Padding(                padding: const EdgeInsets.symmetric(horizontal: 24),                child: AutoSizeTextField(                  controller: _textEditingControllerThree,                  decoration: InputDecoration(hintText: 'Hint Text'),                  fullwidth: false,                  minFontSize: 24,                  minWidth: 280,                  style: TextStyle(fontSize: 64),                  textAlign: TextAlign.center,                ),              ),              SizedBox(height: 48),              Text('Auto adjusted width with prefix and suffix text'),              Padding(                padding: const EdgeInsets.symmetric(horizontal: 24),                child: AutoSizeTextField(                  minWidth: 100,                  controller: _textEditingControllerFour,                  decoration: InputDecoration(                    prefixText: '\$',                    suffixText: '😁',                  ),                  fullwidth: false,                  minFontSize: 24,                  style: TextStyle(fontSize: 64),                  textAlign: TextAlign.center,                ),              ),              SizedBox(height: 48),              Text(                'multi line text with input padding',              ),              Padding(                padding: const EdgeInsets.symmetric(vertical: 24.0),                child: Container(                  constraints: BoxConstraints(                    maxHeight: 200,                    maxWidth: 300,                  ),                  decoration: BoxDecoration(                    border: Border.all(width: 2, color: Colors.amber),                  ),                  child: AutoSizeTextField(                    controller: _textEditingControllerFive,                    fullwidth: false,                    minFontSize: 0,                    maxLines: null,                    style: TextStyle(fontSize: 50),                    textAlignVertical: TextAlignVertical.center,                    decoration: InputDecoration(                        border: InputBorder.none,                        isDense: true,                        contentPadding: const EdgeInsets.all(20)                    ),                    keyboardType: TextInputType.multiline,                  ),                ),              ),              TextButton(                  onPressed: () {                    _textEditingControllerFive?.clear();                  },                  child: Text('clear'))            ],          ),        ),      ), // This trailing comma makes auto-formattig nicer for build methods.    );  }  @override  void initState() {    super.initState();    _textEditingControllerOne = TextEditingController();    _textEditingControllerTwo = TextEditingController();    _textEditingControllerThree = TextEditingController();    _textEditingControllerFour = TextEditingController();    _textEditingControllerFive = TextEditingController();  }  @override  void dispose() {    _textEditingControllerOne?.dispose();    _textEditingControllerTwo?.dispose();    _textEditingControllerThree?.dispose();    _textEditingControllerFour?.dispose();    _textEditingControllerFive?.dispose();    super.dispose();  }}

Download Details:

Author: lzhuor

Source Code: https://github.com/lzhuor/auto_size_text_field

#flutter #textfield 

Flutter TextField Widget That Automatically Resizes Text Field

SwiftUI 2.0 Material Design TextField - How to limit text In TextField? -SwiftUI Tutorials

In this Video i’m going to show how to create a Custom TextField That will Look Like Material Design TextField Using SwiftUI 2.0 | SwiftUI 2.0 Custom TextField | SwiftUI 2.0 Limiting Text’s in Textfield | SwiftUI Textfield Max Length | SwiftUI Material Design | Xcode 12 SwiftUI.

Source Code

https://kavsoft.dev/SwiftUI_2.0/Material_Text_Field

Support Us By Patreon : https://www.patreon.com/kavsoft
Support Us By Contributions : https://donorbox.org/kavsoft

Support Us By Visiting the Link Given Below.

⭐ Kite is a free AI-powered coding assistant that will help you code faster and smarter. The Kite plugin integrates with all the top editors and IDEs to give you smart completions and documentation while you’re typing. It’s gives a great experience and I think you should give it a try too https://www.kite.com/get-kite/?utm_medium=referral&utm_source=youtube&utm_campaign=kavsoft&utm_content=description-only

My Xcode Version is 12.4
My macOS Version is 11.2.3 Big Sur

For Any Queries And Any Request For Videos Use The Given Link

https://kavsoft.dev/#contact

For More

https://kavsoft.dev

Instagram

https://www.instagram.com/_kavsoft/

Twitter

https://twitter.com/_Kavsoft

#swiftui #textfield

SwiftUI 2.0 Material Design TextField - How to limit text In TextField? -SwiftUI Tutorials
Vada  Dare

Vada Dare

1625792760

How To Change TextField's/TextFormField's Border Colors - Flutter

If you have ever wondered how to completely control and change the colors of any TextField or TextFormField, then this video is your answer.

I go over how to change the colors of these widgets no matter what state TextField/TextFormField can find itself in.

Through the decoration property and by using InputDecoration() everything is possible!

(In the beginning I also show a line of code that takes the focus away from whatever it is in)

00:00 - Intro
00:15 - How to Remove Focus From a Widget
00:30 - Giving a Border to the TextField
01:05 - Rounding the Border
01:30 - All Border Properties
01:47 - enabledBorder
02:45 - disabledBorder
03:36 - focusedBorder
04:28 - “border” Property Explained
04:50 - errorBorder
05:13 - focusedErrorBorder
05:28 - Changing Error Text Color
06:12 - Default TextField Colors Explained
06:30 - Flutter Mentor Out

#textfield #borders #colors

Credits:

OUTRO SONG:
Mitsubachi by Smith The Mister https://smiththemister.bandcamp.com
Smith The Mister https://bit.ly/Smith-The-Mister-YT
Free Download / Stream: http://bit.ly/mitsubachi
Music promoted by Audio Library https://youtu.be/0IgndUb1YQI

#flutter #borders #colors #textfield

How To Change TextField's/TextFormField's Border Colors - Flutter
Vada  Dare

Vada Dare

1625759400

TextField and TextFormField - Functionality (Text Input Widgets) - Flutter

Welcome to part 2!

In part 1 you learned how to style and decorate your TextFields and TextFormFields. But now, you will learn how to use forms in Flutter!

In part 2 you will learn how to use the following properties:

autofocus:
textAlign:
keyboardType:
maxLength:
textCapitalization:
textInputAction:
focusNode:
onFieldSubmitted: (TextFormFields)
OnSubmitted: (TextFields)

So, click play and start learning from this Flutter tutorial designed for beginners!

Credits:

OUTRO SONG:
Mitsubachi by Smith The Mister https://smiththemister.bandcamp.com
Smith The Mister https://bit.ly/Smith-The-Mister-YT
Free Download / Stream: http://bit.ly/mitsubachi
Music promoted by Audio Library https://youtu.be/0IgndUb1YQI

#flutter #textfield #textformfield

keywords:

Flutter, flutter tutorial, android studio, english, american accent, subtitles, closed captions, tutorial closed captions, flutter tutorial closed captions, flutter tutorial for beginners, flutter widgets, native english flutter tutorial,Dart tutorial,Dart language tutorial,Dart lang,Dart language,Dart

#flutter #textformfield #textfield

TextField and TextFormField - Functionality (Text Input Widgets) - Flutter

Mahesh Lalwani

1614003443

How to supply an Initialvalue to TextField Widget in Flutter? | Flutter Tutorial

In this video, We will set up a text field default value using the TextField widget property in Flutter.

Related Article Link:- https://flutteragency.com/initialvalue-to-textfield-widget/

Please subscribe our channel : https://www.youtube.com/channel/UCQp3j50Q3tdkZVwYt-eEz9A

For more detail visit : https://FlutterAgency.com

https://youtu.be/bONsb5Z1XJg

#flutter #flutterdevelopment #textfield #defaulttextfieldvalue

How to supply an Initialvalue to TextField Widget in Flutter? | Flutter Tutorial