写在前面

这篇文章的目的是给纯 flutter 萌新回答一些基础问题,ctrl+f/cmd+f 搜索关键字 控件名 本篇会持续更新 最后更新时间 2018-08-02

布局篇

flutter 中 控件各司其职,基础控件中基本只包含自己的功能 显示内容的负责显示内容,如 Text 负责文字,Image 负责图片 容器的负责容器,Row,Column,ListView 等 尺寸位置的负责自己,Padding,Container,SizedBox 等 触摸手势触摸相关:GestureDetector

flutter 中在 widget 层级提倡组合模式,而不提倡继承模式 比如你不应该有一个class TextButton extend Text/RaisedButton这样的方案出现 而应该是


class TextButton extends StatelessWidget {
  final Function onPressed;
  final String text;
  final Color color;
  final double fontSize;
  final EdgeInsets padding;

  const TextButton({
    Key key,
    this.onPressed,
    this.text = "",
    this.color = Colors.black87,
    this.fontSize = 14.0,
    this.padding = EdgeInsets.zero,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Material(
      color: Colors.transparent,
      child: InkWell(
        onTap: onPressed,
        child: Padding(
          padding: padding,
          child: new Text(
            text,
            style: new TextStyle(fontSize: fontSize, color: color),
          ),
        ),
      ),
    );
  }
}

类似于这样的方案

怎么设置宽度/高度

外面包一个 SizedBox,设置 height,Container 也可以,还能加 padding,背景颜色等 child 可以是任意属性

这样的,我应该怎么布局,那样的我该怎么布局

这样的问题,通常归结为不会划分,总体来说有以下几点

  1. 横向多控件,用 Row 包起来,顺序排下去
  2. 纵向多控件,用 Column 包起来,顺序排下去
  3. 单页显示不下的,用 ListView,默认纵向,修改 scrollDirection 属性,ListView 在 flutter 中就是 scrollView

我要给某某控件加一个点击事件,没有 onTap,onPressed 吗

GestureDetector 包含了丰富的手势,包上你的控件就好了

GestureDetector(onTap:()=>print('点击点击'),child:Text('点击'));

GestureDetector 这 on 开头的属性全部都是系统定义好的回调 tap 是点击相关,doubleTap 是双击,longPress 长按 VerticalDrag 相关是纵向拖动 HorizontalDrag 相关是横向拖动 pan 相关是手指移动 scale 是双指缩放手势

behavior代表控件透明时是否可以响应手势

圆角怎么设置,背景图片怎么设置

Container 控件中有decoration属性可以设置,要注意的一点是 这个属性本身和 color 是互斥的,一旦设置 decoration,需要去掉 color 属性 BoxDecoration 有很多属性可以用 image.png 颜色,图片,边框,圆角,阴影,渐变色,形状

SnackBar 显示没有 scaffold

Scaffold.of() called with a context that does not contain a Scaffold.

context 层级用错了 这个是由于 flutter 层级中 这个 context 的父布局没有 Scaffold 的原因,大概就是你是直接用的页面级的 context page -> scaffold -> button 你用了 page 级的, 所以找不到了 解决方案就是中间套一个 builder,用于”转换”出一个位于 scaffold 后的 context,然后就可以了 page -> scaffold -> Builder ->button

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

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: MyAppBar(
        title: Text('测试'),
        elevation: 0.0,
      ),
      body: Container(
        child: Builder( // 这里套一层
            builder: (ctx) => RaisedButton(
                  onPressed: () => _click(ctx), //把builder给的ctx传递给方法
                )),
      ),
    );
  }

  void _click(BuildContext context) {
    // 这里使用传入的context就好了
    Scaffold.of(context).showSnackBar(SnackBar(
          content: Text('内容'),
        ));
  }
}

ListView 套 ListView 报错

这个是因为 ListView 是会占满父布局的控件,你需要给内部的 ListView 加一个高度/宽度限制,如果外部是纵向,则需要高度,外部是横向,需要宽度 可以看你的情况,可以使用 SizedBox,Container,AspectRatio 这样的控件

这样的道理也适用于 Column 内部嵌套 ListView 的情况

适配篇

我个人理解的最佳适配方案是当年那套.文字流式,图片宽高比 image.png 原文链接

图片应该在设计时给定宽高比 文字的话没特殊要求直接自适应 控件弹性的意思,控件高度是固定的,然后占满屏幕,或者百分比,内部的东西左对齐的左对齐,右对齐的右对齐,剩下的占满剩余区域,或者比例分配

dart 相关语法篇

先定义一个类,后面用到

class User{
  String name;
  void print(){
    print(this.name);
  }
}

?. 什么意思

以下两种写法是等效的

void foo(User user){
  user?.print();
}
void foo(User user){
  if(user != null){
    user.print();
  }
}

??啥意思

以下两种写法是等效的

var text = user?.name ?? "默认名字";
String text;
if(user != null && user.name != null){
  text = user.name;
}else{
  text = "默认名字";
}

??= 啥意思

User create(User user){
  var user ??= User();
  return user;
}

User create(User user){
  if(user == null){
    user = User();
  }
  return user;
}

typedef 是啥意思

在 dart 语言中,函数是一等公民,函数本身也是对象 可以被赋值给变量

举个栗子 这个是在 Hero 动画中用到的 final CreateRectTween createRectTween;

查看下 CreateRectTween 的定义,会发现有这么一个写法 typedef Tween<Rect> CreateRectTween(Rect begin, Rect end);

简单的说: 这个是一个函数类型,名称是CreateRectTween,这个函数接收两个 Rect 值,返回一个 Tween 对象 使用的时候就是这样的

Hero(
 createRectTween:(Rect begin,Rect end){
   return MaterialRectArcTween(begin:begin,end:end);
  }
);

拆开来写

CreateRectTween method = (Rect begin,Rect end){
   return MaterialRectArcTween(begin:begin,end:end);
};
Hero(
 createRectTween:method,
);

android studio 中 怎么编辑 android 项目,没有代码提示,还报错

open android module 这里需要在一个新窗口中打开 android 项目