获取设备宽高
double width = MediaQuery.of(context).size.width;
double height = MediaQuery.of(context).size.height;
Android设置状态栏透明
- 原生修改
public class MainActivity extends FlutterActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
{
// api大于21设置状态栏透明
getWindow().setStatusBarColor(0);
}
GeneratedPluginRegistrant.registerWith(this);
}
}
- flutter修改(么有测试过,自己测试下反正不难)
// 输出渲染
void main() {
runApp(App());
if (Platform.isAndroid) {
// 以下两行 设置android状态栏为透明的沉浸。写在组件渲染之后,是为了在渲染后进行set赋值,覆盖状态栏,写在渲染之前MaterialApp组件会覆盖掉这个值。
SystemUiOverlayStyle systemUiOverlayStyle = SystemUiOverlayStyle(statusBarColor: Colors.transparent);
SystemChrome.setSystemUIOverlayStyle(systemUiOverlayStyle);
}
}
区别final与const
在Dart中,当你不需要去改变一个变量的时候,应该使用final或者const,而不是使用var去声明一个变量。一个final变量只允许被赋值一次,必须在定义时或者构造函数参数表中将其初始化。
const所修饰的是编译时常量,我们在编译时就已经知道了它的值,它的值是不可改变的。
const比final更加严格,看以下例子:
final List list = [];
list.add('1'); // 正确
const List list = [];
list.add('1'); // 错误,运行时报错:Cannot add to an unmodifiable list
final timestamp = new DateTime.now().millisecondsSinceEpoch; // 正确
const timestamp = new DateTime.now().millisecondsSinceEpoch; // 错误,编译前报错:Const variables must be initialized with a constant value
FocusScope转移焦点,隐藏输入法
Container(
height: 500.0,
child: new GestureDetector(
onTap: () {
// 通过GestureDetector捕获点击事件,再通过FocusScope将焦点转移至空焦点 new FocusNode()
FocusScope.of(context).requestFocus(FocusNode());
},
child: Container(
margin: EdgeInsets.all(30.0),
child: ListView(children: [
TextField(
decoration: InputDecoration(labelText: 'Username'),
),
TextField(
decoration: InputDecoration(labelText: 'Password'),
)
])),
),
),
- 这里传递给FocusScope的context不能在MaterialApp下面,即你需要将这部分代码放到独立的一个Widget里面
定时任务
- 在我们的开发之中难免要用到定时,比如我们常用的获取验证码的需求,下面请看利用定时器来实现这一功能需求
- 定义3个变量
int _seconds = 0;
String _verifyStr = "获取验证码";
/// 定时器Timer
Timer _timer;
- 实现timer,代码很清晰,简单的说我设了10秒的倒计时,利用Timer.periodic方法来执行,间隔时间是1秒
/// 倒计时
_startTimer() {
_seconds = 10;
_timer = Timer.periodic(new Duration(seconds: 1), (timer){
if(_seconds == 0){
_cancleTimer();
return;
}
_seconds--;
_verifyStr = "${_seconds}s";
if (_seconds == 0){
_verifyStr = "重新发送";
}
setState(() {});
});
}
_cancleTimer(){
_timer?.cancel();
}
@override
void dispose() {
// TODO: implement dispose
super.dispose();
/// 页面销毁的时候,清除timer
_cancleTimer();
}
- 执行,并不是每次按都执行_startTimer,加上判断条件只有_seconds == 0时才执行效果如下图
new Container(
padding: const EdgeInsets.only(top: 15.0, left: 15.0),
child: new RaisedButton(
/// 触发定时任务
onPressed: (_seconds == 0)?(){
_startTimer();
}:null,
child: new Text(_verifyStr),
shape: new RoundedRectangleBorder(
borderRadius: new BorderRadius.all(new Radius.circular(15.0)),
),
textColor: Colors.blue,
color: Colors.yellowAccent,
disabledColor: Colors.yellowAccent,
disabledTextColor: Colors.blue,
),
),
利用 Container的BoxDecoration装饰实现渐变
- 例子如下
Container(
decoration: BoxDecoration(gradient: LinearGradient(
colors: [const Color(0xFFFFFFEE), const Color(0xFF999999),const Color(0xFF862547),],
tileMode: TileMode.repeated, // repeats the gradient over the canvas
),),
-
效果如下
BoxDecoration的属性
const BoxDecoration({
this.color, // 盒子颜色
this.image, // 图片
this.border, 边框颜色和线宽度
this.borderRadius, // 圆角度
this.boxShadow, // 阴影
this.gradient, // 渐变
this.backgroundBlendMode, // 混合Mode
this.shape = BoxShape.rectangle, // 形状
})
- 边框圆角实现
decoration: new BoxDecoration(
border: new Border.all(color: Color(0xFFFF0000), width: 1.0), // 边色与边宽度
color: Color(0xFF999999), // 盒子颜色
// borderRadius: new BorderRadius.circular((15.0)), // 圆角度
borderRadius: new BorderRadius.vertical(top: Radius.elliptical(20, 50)), // 也可控件一边圆角大小
),
- Dart知识点(?. / ??)
- ?. 运算符在左边为null的情况下会阻断右边的调用。
- ?? 运算符表示在左侧表达式为null时为其设置默认值。
对于表达式:
tar[a]?.tars(b)
如果tar为null或tar[a]为null或tars(b)的值为null,都会导致表达式为null。
-
operator
重载操作符
operator 是 Dart 的一个关键字,它和运算符(如=,+,-)一起使用,表示一个 运算符重载函数,在理解时可将operator和运算符(如operator=)视为一个函数名
关于混编中退出flutter页面的时候黑屏的情况
if(Navigator.canPop(context)){
Navigator.pop(context, true);
}else {
SystemNavigator.pop();
}
关于ListView中嵌套使用ListView,请在子组件中设置以下属性
shrinkWrap: true,
底部弹窗默认点击消失,如何保持面板点击不消失
- 可以子组件外面包一层GestureDetector并设置onTap为false,拦截点击事件可以使点击底部面板区域时不消失。
showModalBottomSheet(
context: context,
builder: (context) {
return GestureDetector(
onTap: () => false,
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
titleWidget,
twoWidget,
Expanded(
child: BottomUserRankingPage(
context,
lists: lists,
),
),
],
),
);
});
实现跳转到广告按back返回是主界面
Navigator.of(context).pushReplacementNamed('/Main');
Navigator.of(context).push(WebPage);
如何强制竖屏
void main() {
SystemChrome.setPreferredOrientations([DeviceOrientation.portraitUp])
.then((_) {
runApp(new MyApp());
});
}
在线上的app,如果flutter报错,那一片红可是非常的辣眼睛,给用户的体验也很不好,其实我们可以自定义错误页面
ErrorWidget.builder = (FlutterErrorDetails details) {
print(details.toString());
return Center(
child: Text("Sorry 我下班了"),
);
};
在Flutter中,加载本地图片会存在一个加载过程。比如点击图标做图标的切换时,那么首次会发生闪动的情况。尤其是做类似引导页这类需求是,通过左右滑动切换图片时会发生比较明显的白屏一闪而过。
解决方法很简单,就是使用 precacheImage,它将图像预存到图像缓存中。如果图像稍后被使用,它会被加载得更快。
precacheImage(AssetImage("assets/mylogo"), context);
在iOS 13中遇到了http网页打不开的问题,添加以下文字到Info.plist
yourdomain.com 是你请求的链接的域名
NSAppTransportSecurity
NSExceptionDomains
yourdomain.com
NSExceptionAllowInsecureHTTPLoads
NSAllowsArbitraryLoadsInWebContent
NSAllowsArbitraryLoads