flutter一文通4

flutter图标库:http://fluttericon.com/

一. ClipOval椭圆组件

使被包裹的子组件椭圆化

 

ClipOval(
            child: Image.network("https://timgsa.baidu.com/timg68"),
          ),

 

二. ClipRRect 圆角矩形

使被包裹的子组件圆角矩形化

 

ClipRRect(
            borderRadius: BorderRadius.circular(16),
            child: Image.network("https://timgsa.baidu.com/timg68"),
          ),

 

image.png

三. form表单

form也是一个组件,与它配套的是可以提交内容的组件,比如:

  • TextFormField
  •  

提交过程很繁琐:

  1. 提前声明一个GlobalKey,用来绑定form GlobalKey<FormState> formGlobalKey = GlobalKey();
  2. 给form的key属性绑定这个GlobalKey
  3. 在配套组件中注册提交事件 onSaved: (value){}
  4. 在提交按钮中用GlobalKey找到form,并调用它的formGlobalKey.currentState.save();

这样,在按钮点击时,表单会触发与它配套的组件的onSaved: (value){}方法,并将他们的值传给这个方法

 

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: Scaffold(
        appBar: AppBar(
          title: Text("data"),
        ),
        body: Login(),
      ),
    );
  }
}

class Login extends StatefulWidget {
  @override
  _LoginState createState() => _LoginState();
}

class _LoginState extends State<Login> {
  String username;  
  String password;

  GlobalKey<FormState> formGlobalKey = GlobalKey();
  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(10),
      child: Form(
          key: formGlobalKey,
          child: Column(
            children: <Widget>[
              TextFormField(
                decoration: InputDecoration(
                    icon: Icon(Icons.people), labelText: 'USERs'),
                onSaved: (value) {
                  setState(() {
                    print(value);
                    this.username = value;
                  });
                },
              ),
              TextFormField(
                decoration: InputDecoration(
                    icon: Icon(Icons.lock), labelText: 'password'),
                obscureText: true,
                onSaved: (value) {
                  setState(() {
                    print(value);
                    this.password = value;
                  });
                },
              ),
              RaisedButton(
                  child: Container(
                    width: double.infinity,
                    alignment: Alignment.center,
                    child: Text(
                      "login",
                      style: TextStyle(color: Colors.white),
                    ),
                  ),
                  color: Colors.green,
                  onPressed: () {
                    setState(() {
                      print("OK");
                      formGlobalKey.currentState.save();
                    });
                  })
            ],
          )),
    );
  }
}

四. 表单验证器

我们想验证表单里的内容输入的合法性,这需要:

  1. 在form配套子组件中添加属性validator
    validator属性里面如何设置?
    validator属性里要传入一个函数,这个函数默认接收value参数,可以对value做一些判断,如果合规就return null,如果不合规就return一个字符串错误提示

 

validator: (value) {
  if (value.length == 0) {
    return "密码不能为空";
  }
  return null;
},
  1. 在提交按钮中触发formGlobalKey.currentState.validate();

五. 表单自动验证

很简单,在form配套子组件中添加属性autovalidate: true,
同时,可以省略在提交按钮中触发formGlobalKey.currentState.validate();这一步了

六. 主题设置

一个APP我们往往要求色调统一等全局性设置,这些设置都被放在了根组件MaterialApp的theme属性里.
主题数据里的设置非常非常多,而且全都是跟颜色 动画等APP风格有关的设置
例,设置方法:

 

class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: MyStatefulWidget(),
      theme: ThemeData(primaryColor: Colors.green),
    );
  }
}

七. 底部导航栏

  • 底部导航栏BottomNavigationBar里面要放至少两个BottomNavigationBarItem,而且每个BottomNavigationBarItem必须有title
  • BottomNavigationBar有一个关键属性currentIndex,此属性传入数字,传入几第几个标签就会标记为按下
  • BottomNavigationBar有一个ontap事件,事件会在点击BottomNavigationBarItem时触发,事件默认传入一个参数value, 其指代的是被点击的BottomNavigationBarItem的index
  • 底栏切换时,脚手架的home也随之切换,实现的方式是:把所有要显示的内容放在列表中,用elementAt(_selectedIndex)来切换

 

import 'package:flutter/material.dart';

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

/// This Widget is the main application widget.
class MyApp extends StatelessWidget {
  static const String _title = 'Flutter Code Sample';

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: _title,
      home: MyStatefulWidget(),
      theme: ThemeData(primaryColor: Colors.green),
    );
  }
}

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

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

class _MyStatefulWidgetState extends State<MyStatefulWidget> {
  int _selectedIndex = 0;
  static const TextStyle optionStyle =
      TextStyle(fontSize: 30, fontWeight: FontWeight.bold);
  static const List<Widget> _widgetOptions = <Widget>[
    Text(
      'Index 0: Home',
      style: optionStyle,
    ),
    Text(
      'Index 1: Business',
      style: optionStyle,
    ),
    Text(
      'Index 2: School',
      style: optionStyle,
    ),
  ];

  void _onItemTapped(int index) {
    setState(() {
      _selectedIndex = index;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('BottomNavigationBar Sample'),
      ),
      body: Center(
        child: _widgetOptions.elementAt(_selectedIndex),
      ),
      bottomNavigationBar: BottomNavigationBar(
        items: const <BottomNavigationBarItem>[
          BottomNavigationBarItem(
            icon: Icon(Icons.home),
            title: Text('首页'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.business),
            title: Text('分类'),
          ),
          BottomNavigationBarItem(
            icon: Icon(Icons.school),
            title: Text('我的'),
          ),
        ],
        currentIndex: _selectedIndex,
        onTap: _onItemTapped,
      ),
    );
  }
}

 

八. 封装一个自己的组件

建立一个文件 如:components/my_bottom_bar.dart

 

import 'package:flutter/material.dart';
 
class MyBottomBar extends BottomNavigationBarItem{
  MyBottomBar(String name,Icon icon,Icon activeIcon):super(
    icon: icon,
    activeIcon:activeIcon,
    title:Text(name)
  );
}

引用时:

 

import './components/my_bottom_bar.dart';

九. 导航条配合神器 IndexedStack组件

IndexedStack会根据index选择自己要显示的子组件

 

 

import 'package:flutter/material.dart';
class MyBottomNavBar extends StatefulWidget {
  @override
  _MyBottomNavBarState createState() => _MyBottomNavBarState();
}

class _MyBottomNavBarState extends State<MyBottomNavBar> {
  int _currentIndex=0;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("底部导航栏"),),
      body: IndexedStack(
        index: _currentIndex,
        children: <Widget>[
          Text("首页"),
          Text("商店页"),
        ],
      ),
      bottomNavigationBar: BottomNavigationBar(
        currentIndex: _currentIndex,
        items: [
          BottomNavigationBarItem(icon: Icon(Icons.home),title: Text("home")),
          BottomNavigationBarItem(icon: Icon(Icons.shop),title: Text("shop")),
        ],
        onTap: (index){
          setState(() {
            _currentIndex=index;
          });
        },
        ),
    );
  }
}

十. 状态组件中状态管理器如何拿到组件的变量

使用widget.xxx

 

import 'package:flutter/material.dart';

class EachView extends StatefulWidget {
  final String _title;
  EachView(this._title);
  @override
  _EachViewState createState() => _EachViewState();
}

class _EachViewState extends State<EachView> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text(widget._title)),
      body: Center(
        child: Text(widget._title),
      ),
    );
  }
}

十一. 搜索框

先看效果:

 

 

import 'package:flutter/material.dart';
import './asset.dart'; //数据本应该是数据库提供的 这里我们写了个假数据文件假扮.

class SearchBarDemo extends StatefulWidget {
  @override
  _SearchBarDemoState createState() => _SearchBarDemoState();
}

class _SearchBarDemoState extends State<SearchBarDemo> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("搜索DEMO"),
        actions: <Widget>[
          IconButton(
              icon: Icon(Icons.search),
              onPressed: () {
                //点击搜索按钮后会调用原生showSearch方法显示SearchBarDelegate搜索条
                showSearch(context: context, delegate: SearchBarDelegate());
              })
        ],
      ),
    );
  }
}

class SearchBarDelegate extends SearchDelegate<String> {
  @override
  List<Widget> buildActions(BuildContext context) {
    //重写bulidActions 构造搜索动作区域  就是后面的X  这个重构基本不会变
    return [IconButton(icon: Icon(Icons.clear), onPressed: () => query = "")];
  }

  @override
  Widget buildLeading(BuildContext context) {
    //重写buildLeading 构造搜索头部区域  就是前面的⬅  这个重构基本不会变
    return IconButton(
        icon: AnimatedIcon(
            icon: AnimatedIcons.menu_arrow, progress: transitionAnimation),
        onPressed: () => close(context, null));
  }

  @override
  Widget buildResults(BuildContext context) {
    //重写buildResults 构造搜索结果区域, 这里写的是搜索按钮按下后的逻辑
    return Container(
      width: 400.0,
      height: 200.0,
      child: Card(
        //点击搜索后可以显示列表清单\特等结果等, 这里是假装搜索到一个卡片.
        color: Colors.indigo,
        child: Text(
          '这里是假装的搜索$query 得到的结果!!最好做成一个列表,通过点击跳转到想去的页面',
          style: TextStyle(color: Colors.white, fontSize: 20),
          textAlign: TextAlign.center,
        ),
      ),
    );
  }

  @override
  Widget buildSuggestions(BuildContext context) {
    //重写buildSuggestions 构造搜索提示区域
    final suggestionList = query.isEmpty //搜索提示列表数据
        ? recentSuggest //最近搜索, 数据应来源于服务器
        : searchList
            .where((input) => input.startsWith(query))
            .toList(); //数据应来源于服务器
    //重写buildSuggestions  构造搜索提示
    return ListView.builder(
        //生成提示列表
        itemBuilder: (context, index) => ListTile(
              //返回列表瓦片
              title: RichText(
                text: TextSpan(
                    //严格匹配的加粗部分
                    text: suggestionList[index].substring(0, query.length),
                    style: TextStyle(
                        color: Colors.black, fontWeight: FontWeight.bold),
                    children: [
                      TextSpan(
                          //未严格匹配到的部分
                          text: suggestionList[index].substring(query.length),
                          style: TextStyle(color: Colors.grey))
                    ]),
              ),
              onTap: () {
                print(query);
                Scaffold.of(context).removeCurrentSnackBar();
                Scaffold.of(context).showSnackBar(SnackBar(
                  content: Text("一个建议选项被点了,可能要跳转到对应的页面了"),
                ));
              },
            ),
        itemCount: suggestionList.length);
  }
}

十二. 闪屏页面 //启动加载页

 

 

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

class SplashScreen extends StatefulWidget {
  @override
  _SplashScreenState createState() => _SplashScreenState();
}

class _SplashScreenState extends State<SplashScreen>
    with SingleTickerProviderStateMixin { //为了动画效果混合这个类SingleTickerProviderStateMixin
  AnimationController _controller;  //动画控制器
  Animation _animation;   //动画过程

  @override
  void initState() {
    //重写初始化方法
    super.initState();
    _controller = AnimationController(   //初始化动画控制器
        vsync: this, duration: Duration(milliseconds: 3000));
    _animation = Tween(begin: 0.0, end: 1.0).animate(_controller); //初始化动画过程
 
    _animation.addStatusListener((status) {       //监听动画状态变化
      if (status == AnimationStatus.completed) {  //当动画状态变为AnimationStatus.completed时,发生跳转
        Navigator.of(context).pushAndRemoveUntil(
            MaterialPageRoute(builder: (context) => MyHomePage()),  //跳转到MyHomePage页面
            (router) => router == null);   //固定写法
      }
    });
    _controller.forward(); //播放动画
  }

  @override
  void dispose() {
    //重写销毁方法
    _controller.dispose(); //销毁动画控制器
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FadeTransition(  //返回一个淡入动画
      opacity: _animation,  //该动画的透明度关联至上面创立的动画过程_animation身上
      child: Image.network(
        "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1587370522470&di=e0ba28a377b1d9d18a5589579af3a35a&imgtype=0&src=http%3A%2F%2Fb-ssl.duitang.com%2Fuploads%2Fitem%2F201611%2F27%2F20161127000843_zLhCx.jpeg",
        scale: 2.0,
        fit: BoxFit.cover,
      ),
    );
  }
}

十三. 右滑返回

实现这个效果,我们引用了另一套UI框架cupertino.这套风格接近IOS风格.

 

 

import 'package:flutter/cupertino.dart'; //引用的是另一套UI风格:cupertino

class RightBackDemo extends StatelessWidget {
  //第二页,里面有个卡布奇诺按钮, 按下返回第一页
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
        child: Center(
            child: Container(
      height: 100,
      width: 100,
      color: CupertinoColors.activeBlue,
      child: CupertinoButton(
          child: Icon(CupertinoIcons.add),
          onPressed: () {
            Navigator.push(context,
                CupertinoPageRoute(builder: (BuildContext context) {
              return FirstPage();
            }));
          }),
    )));
  }
}

class FirstPage extends StatelessWidget {
  //第一页,只是一个普通的页面
  @override
  Widget build(BuildContext context) {
    return CupertinoPageScaffold(
      child: Center(
        child: Container(
          child: CupertinoButton(
              child: Text('next page'),
              onPressed: () {
                Navigator.push(context,
                    CupertinoPageRoute(builder: (BuildContext context) {
                  return RightBackDemo();
                }));
              }),
        ),
      ),
    );
  }
}

十四. tooltip 轻提示

tooltip常常用在图片 按钮上,做小型提示.

 

 

import 'package:flutter/material.dart';

class TooltipDemo extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text("tooltip")),
      body: Center(
        child: Tooltip(
          message: '不要乱点',
          preferBelow:true,
          child: Image.network(
            "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1587630407426&di=dc83b562a13e8f2f870dc19b5dc4fe05&imgtype=0&src=http%3A%2F%2Fattachments.gfan.com%2Fforum%2F201803%2F23%2F1849303zhiwhlvviwplm5l.jpg",
          ),
        ),
      ),
    );
  }
}



作者:熊爸天下_56c7
链接:https://www.jianshu.com/p/6b43e7dc1e74
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值