主頁 > 移動端開發 > Flutter 常見問題總結

Flutter 常見問題總結

2021-07-31 08:40:01 移動端開發

文章目錄

    • 1、內容簡介
    • 2、使用Column等容器包裹ListView報錯的問題
    • 3、Navigator operation requested ... does not include a Navigator.
    • 4、設定Container背景色
    • 5、去除AppBar 陰影
    • 6、組件描邊,圓角
    • 7、如何給row或column布局添加手勢監聽?
    • 8、ListView和GridView嵌套報錯?
    • 9、在Android studio中匯入Flutter專案報錯
    • 10、給新頁面傳值
    • 11、實作滑動關閉、洗掉item
    • 12、添加Material觸摸水波效果
    • 13、處理點擊
    • 14、實作Icon可以用Image替換
    • 15、驗證碼倒計時功能
    • 16、從新頁面回傳資料給上一個頁面
    • 17、創建一個 grid List
    • 18、使用不同型別的子項創建串列
    • 19、使用長串列
    • 20、用占位符淡入淡出的顯示圖片
    • 21、Dart中dynamic,var,object三者的區別
    • 22、TextField設定默認值默認值和游標位置
    • 23、限制TextField只能輸入漢字或英文字母或數字,并限制輸入最多中文10字符,英文20字符
    • 24、Dart之正則運算式相關方法總結
    • 25、使用正則運算式驗證手機號
    • 26、去掉輸入框最大字數顯示
    • 27、TextField 限制只允許輸入數字,字母,小數,設定限制小數位數
    • 28、TextField 文本輸入框的基本屬性及詳解
    • 29、實作農歷(陰歷)轉公歷(陽歷)
    • 30、SDK升級
    • 31、Expanded組件不能直接嵌套LitView報錯,解決辦法
    • 32、ListView不能直接嵌套ListView解決辦法
    • 32、Text的overflow屬性不生效(14)

喜歡記得點個贊喲,我是王睿,很高興認識大家!

1、內容簡介

本文主要總結了開發時遇到的Bug、報錯、開發時遇到的技術難題等,同時,讓大家能夠快速解決自己遇到額問題和避免采坑,如果對您有幫助,希望在文章的末尾能點個贊,謝謝!

2、使用Column等容器包裹ListView報錯的問題

報錯如下所示:

I/flutter ( 4625): EXCEPTION CAUGHT BY RENDERING LIBRARY
I/flutter ( 4625): The following assertion was thrown during performResize():
I/flutter ( 4625): Vertical viewport was given unbounded height.
I/flutter ( 4625): Viewports expand in the scrolling direction to fill their container.In this case, a vertical
I/flutter ( 4625): viewport was given an unlimited amount of vertical space in which to expand. This situation
I/flutter ( 4625): typically happens when a scrollable widget is nested inside another scrollable widget.
I/flutter ( 4625): If this widget is always nested in a scrollable widget there is no need to use a viewport because
I/flutter ( 4625): there will always be enough vertical space for the children. In this case, consider using a Column
I/flutter ( 4625): instead. Otherwise, consider using the “shrinkWrap” property (or a ShrinkWrappingViewport) to size
I/flutter ( 4625): the height of the viewport to the sum of the heights of its children.

解決方案:

使用擴展小部件Expanded包裹ListView

new Expanded(
child: new ListView(
          .....
          )
);

這告訴ListView盡可能地獲取寬度和高度,

3、Navigator operation requested … does not include a Navigator.

原錯誤: Navigator operation requested with a context that does not include a Navigator.

flutter 最容易報的一個錯誤就是does not include,因為其思想是組合

這種情況即使是外面包裹了materialapp也是無效的,因為flutter會根據這個context一直上溯,一直到根節點的widget,注意,上溯是根據context的,會上溯到這個context相關的widget的最根節點

14down vote

This error is unrelated to the destination. It happens because you used a context that doesn’t contain a Navigator instance as parent.

How do I create a Navigator instance then ?

This is usually done by inserting in your widget tree a MaterialApp or WidgetApp. Although you can do it manually by using Navigator directly but less recommended. Then, all children of such widget can access NavigatorState using Navigator.of(context).

Wait, I already have a MaterialApp/WidgetApp !

That’s most likely the case. But this error can still happens when you use a context that is a parent of MaterialApp/WidgetApp.

This happens because when you do Navigator.of(context), it will start from the widget associated to the context used. And then go upward in the widget tree until it either find a Navigator or there’s no more widget.

In the first case, everything is fine. In the second, it throws a

Navigator operation requested with a context that does not include a Navigator.

So, how do I fix it ?

First, let’s reproduce this error :

import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Center(
        child: RaisedButton(
          child: Text("Foo"),
          onPressed: () => Navigator.pushNamed(context, "/"),
        ),
      ),
    );
  }
}

This example creates a button that attempts to go to ‘/’ on click but will instead throw an exception.

Notice here that in the

onPressed: () => Navigator.pushNamed(context, “/”),
we used context passed by to build of MyApp.

The problem is, MyApp is actually a parent of MaterialApp. As it’s the widget who instantiate MaterialApp! Therefore MyApp’s BuildContext doesn’t have a MaterialApp as parent!

To solve this problem, we need to use a different context.

In this situation, the easiest solution is to introduce a new widget as child of MaterialApp. And then use that widget’s context to do the Navigator call.

There are a few ways to achieve this. You can extract home into a custom class :

import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: MyHome()
    );
  }
}
 
class MyHome extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
        child: RaisedButton(
          child: Text("Foo"),
          onPressed: () => Navigator.pushNamed(context, "/"),
        ),
      );
  }
}

Or you can use Builder :

import 'package:flutter/material.dart';
 
void main() => runApp(MyApp());
 
class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Builder(
        builder: (context) => Center(
              child: RaisedButton(
                child: Text("Foo"),
                onPressed: () => Navigator.pushNamed(context, "/"),
              ),
            ),
      ),
    );
  }
}

4、設定Container背景色

child: Container(

  decoration: new BoxDecoration(
    color: Colors.grey,
  ),

5、去除AppBar 陰影

頁面本身是白色,所以我想將appbar 也設定成白色,并且需要去除陰影

child: Scaffold(
          appBar: AppBar(
            title: Text("xixi"),
            backgroundColor: Colors.white,
            elevation: 0,  //默認是4, 設定成0 就是沒有陰影了
          ),
          backgroundColor: Colors.white,

6、組件描邊,圓角

通常用Container組件的decoration來做

Container(
              padding: EdgeInsets.symmetric(horizontal: 4.0, vertical: 2.0),
              decoration: BoxDecoration(
                  border: Border.all(color: Colors.grey, width: 1.0),
                  borderRadius: BorderRadius.circular(3.0)),
              child: Text(_products[index]['description'])),

padding內邊距屬性,如果不添加描邊會緊貼文字image加上邊距之后image

EdgeInsets支持多種自定義方法

EdgeInsets.all() 全方向
EdgeInsets.only(left,top,right,bottom) 自定義各方向的邊距
EdgeInsets.symmetric(vertical, horizontal)自定義垂直,水平對稱邊距
EdgeInsets.fromWindowPadding(ui.WindowPadding padding, double devicePixelRatio) 根據機型螢屏尺寸定義
decoration這里用到BoxDecoration組件 常用屬性

color顏色
border 描邊寬度
borderRadius 圓角值
boxShadow 陰影 支持gradient 梯度,混合模式backgroundBlendMode shape自定義形狀 Border BorderRadius同樣支持多種自定方法.

7、如何給row或column布局添加手勢監聽?

直接在需要堅挺的布局外面套一層如下的代碼即可!

GestureDetector(
  behavior: HitTestBehavior.translucent,
  onTap(){		//監聽器
	Navigator.pushNamed(context, '/guide');//處理一些相關邏輯
	
}

8、ListView和GridView嵌套報錯?

直接在GridView布局里,加上這兩句代碼,即可解決問題!

physics: new NeverScrollableScrollPhysics(),//增加
shrinkWrap: true,//增加

例子如下:

GridView.count(
      physics: new NeverScrollableScrollPhysics(),//增加
      shrinkWrap: true, //增加
      ...
      ...
      children: <Widget>[
       ...
       ...
      ],
    );

9、在Android studio中匯入Flutter專案報錯

第一步:左上角File→Settings→Dart
配置如下:
在這里插入圖片描述
第二步:
在這里插入圖片描述

10、給新頁面傳值

效果圖一:
點擊跳轉

在這里插入圖片描述
效果圖二:

點擊第四項后并傳值到下一個頁面來顯示
在這里插入圖片描述

代碼+注釋:

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

/**
 * 定義主頁,
    添加一個打開選擇頁面的按鈕,
    在選擇頁面上顯示兩個按鈕,
    點擊一個按鈕時,關閉選擇的頁面,
    主頁上彈出一個snackbar以顯示用戶的選擇,
 */
class Todo {
  final String title;
  final String description;

  Todo(this.title, this.description);
}

void main() {
  runApp(new MaterialApp(
    title: 'Passing Data',
    home: new TodosScreen(
      todos: new List.generate(
        20,
            (i) => new Todo(
          'Todo $i',
          'A description of what needs to be done for Todo $i',
        ),
      ),
    ),
  ));
}

class TodosScreen extends StatelessWidget {
  final List<Todo> todos;

  TodosScreen({Key key, @required this.todos}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Todos'),
      ),
      body: new ListView.builder(
        itemCount: todos.length,
        itemBuilder: (context, index) {
          return new ListTile(
            title: new Text(todos[index].title),
            // When a user taps on the ListTile, navigate to the DetailScreen.
            // Notice that we're not only creating a new DetailScreen, we're
            // also passing the current todo through to it!
            /**
             *當用戶點擊ListTile時,導航到DetailScreen,請注意,我們不僅在創建新的DetailScreen,而且還在傳遞當前的待辦事項!
             */
            onTap: () {
              Navigator.push(
                context,
                new MaterialPageRoute(
                  builder: (context) => new DetailScreen(todo: todos[index]),   //傳入Todo物件
                ),
              );
            },
          );
        },
      ),
    );
  }
}

class DetailScreen extends StatelessWidget {
  // Declare a field that holds the Todo
  final Todo todo;  //接收Todo 物件

  // In the constructor, require a Todo
  DetailScreen({Key key, @required this.todo}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // Use the Todo to create our UI
    return new Scaffold(
      appBar: new AppBar(
        title: new Text("${todo.title}"),
      ),
      body: new Padding(
        padding: new EdgeInsets.all(16.0),
        child: new Text('${todo.description}'),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:給新頁面傳值

11、實作滑動關閉、洗掉item

效果圖一:

在這里插入圖片描述

效果圖二:
右滑洗掉第六個item
在這里插入圖片描述

效果圖三:
左滑洗掉第4個item
在這里插入圖片描述

效果圖四:
最后看到,第四項和第六項都被洗掉了

在這里插入圖片描述

代碼+注釋:

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

void main() {
  runApp(new MyApp(
    items: new List<String>.generate(20, (i) => "Item ${i + 1}"),
  ));
}

class MyApp extends StatelessWidget {
  final List<String> items;

  MyApp({Key key, @required this.items}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final title = 'Dismissing Items';

    return new MaterialApp(
      title: title,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text(title),
        ),
        body: new ListView.builder(
          itemCount: items.length,
          itemBuilder: (context, index) {
            final item = items[index];

            return new Dismissible(
              // Each Dismissible must contain a Key. Keys allow Flutter to
              // uniquely identify Widgets.
              /**
               * 每個可豁免項都必須包含一個密鑰, 鍵使Flutter能夠唯一標識小部件,
               */
              key: new Key(item),
              // We also need to provide a function that will tell our app
              // what to do after an item has been swiped away.
              /**
               * 我們還需要提供一個可以告訴我們應用程式的功能刷掉物品后該怎么辦,
               * onDismissed —— 被解雇
               * direction —— 方位表示:洗掉方向是左邊還是右邊,startToEnd 左邊,endToStart 右邊
               */
              onDismissed: (direction) {
                print(direction);
                items.removeAt(index);    //根據坐標移除具體的item項
                // 顯示移除了哪一條item
                Scaffold.of(context).showSnackBar(
                    new SnackBar(content: new Text("$item dismissed")));
              },
              // Show a red background as the item is swiped away
              // 滑動洗掉item時顯示紅色背景
              background: new Container(color: Colors.red),
              child: new ListTile(title: new Text('$item')),
            );
          },
        ),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:實作滑動關閉、洗掉item

12、添加Material觸摸水波效果

效果圖一:

點擊按鈕出現灰色水波紋特效
在這里插入圖片描述

效果圖二:

顯示底部彈出框
在這里插入圖片描述

代碼+注釋:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'InkWell Demo';

    return new MaterialApp(
      title: title,
      home: new MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

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

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(title),
      ),
      body: new Center(child: new MyButton()),
    );
  }
}

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // The InkWell Wraps our custom flat button Widget
    /// InkWell 有水波紋, GestureDetector 沒有水波紋
    return new InkWell(
      // When the user taps the button, show a snackbar
      // 當用戶點擊按鈕時,顯示 snackbar
      onTap: () {
        Scaffold.of(context).showSnackBar(new SnackBar(
          content: new Text('Tap'),
        ));
      },
      child: new Container(
        padding: new EdgeInsets.all(12.0),
        child: new Text('Flat Button'),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:添加Material觸摸水波效果

13、處理點擊

效果圖一:
點擊按鈕

在這里插入圖片描述

效果圖二:

顯示底部彈出框
在這里插入圖片描述

代碼+注釋:

import 'package:chapter02one/Api.dart';
import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'Gesture Demo';

    return new MaterialApp(
      title: title,
      home: new MyHomePage(title: title),
    );
  }
}

class MyHomePage extends StatelessWidget {
  final String title;

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

  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text(title),
      ),
      body: new Center(child: new MyButton()),
    );
  }
}

class MyButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Our GestureDetector wraps our button
    ///我們的GestureDetector包裹了我們的按鈕
    return new GestureDetector(
      // When the child is tapped, show a snackbar
      ///監聽器
      onTap: () {
        /**
         * 準備: 底部彈出框物件
         * content 是一個組件,可以是自定義的任何型別組件,也可以是復合型組合組件,例如Column
         */
        final snackBar = new SnackBar(content: Text('底部彈出框呀'));
        // 顯示 SnackBar
        Scaffold.of(context).showSnackBar(snackBar);
      },
      // Our Custom Button!
      child: new Container(
        padding: new EdgeInsets.all(12.0),
        decoration: new BoxDecoration(
          color: Theme.of(context).buttonColor,
          borderRadius: new BorderRadius.circular(8.0),
        ),
        child: new Text('My Button'),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:處理點擊

14、實作Icon可以用Image替換

flutter實作Icon可以用Image替換
23/100
發布文章
qq_27494201
未選擇任何檔案
在這里插入圖片描述
flutter的Icon可以用Image替換

15、驗證碼倒計時功能

效果圖:
在這里插入圖片描述

import 'dart:async';

import 'package:flutter/material.dart';
import '../widget/JdText.dart';
import '../widget/JdButton.dart';
import '../services/ScreenAdapter.dart';
import 'dart:async'; //Timer定時器需要引入
import '../config/Config.dart';
import 'package:dio/dio.dart';
import 'package:fluttertoast/fluttertoast.dart';

/**
 * 注冊 — 第二步
 */
class RegisterSecondPage extends StatefulWidget {
  Map arguments;
  RegisterSecondPage({Key key, this.arguments}) : super(key: key);

  _RegisterSecondPageState createState() => _RegisterSecondPageState();
}

class _RegisterSecondPageState extends State<RegisterSecondPage> {
  String tel;         //手機號碼
  bool sendCodeBtn = false; //判斷發送短信按鈕是否點擊過標志
  int seconds = 10;   //倒計時 10秒
  String code;    //驗證碼

  @override
  void initState() {
    // TODO: implement initState
    super.initState();
    this.tel = widget.arguments['tel'];
    this._showTimer();
  }

  //倒計時
  _showTimer() {
    Timer t;
    t = Timer.periodic(Duration(milliseconds: 1000), (timer) {
      setState(() {
        this.seconds--;
      });
      if (this.seconds == 0) {
        t.cancel(); //清除定時器
        setState(() {
          this.sendCodeBtn = true;
        });
      }
    });
  }

  //重新發送驗證碼
  sendCode() async {
    setState(() {
      this.sendCodeBtn = false;
      this.seconds = 10;
      this._showTimer();
    });
    var api = '${Config.domain}api/sendCode';
    var response = await Dio().post(api, data: {"tel": this.tel});
    if (response.data["success"]) {
      print(response); //演示期間服務器直接回傳  給手機發送的驗證碼
    }
  }
  //驗證驗證碼

  validateCode() async {
    var api = '${Config.domain}api/validateCode';
    var response =
    await Dio().post(api, data: {"tel": this.tel, "code": this.code});
    if (response.data["success"]) {
      Navigator.pushNamed(context, '/registerThird',arguments: {
        "tel":this.tel,
        "code":this.code
      });
    } else {
      Fluttertoast.showToast(
        msg: '${response.data["message"]}',
        toastLength: Toast.LENGTH_SHORT,
        gravity: ToastGravity.CENTER,
      );
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("用戶注冊-第二步"),
      ),
      body: Container(
        padding: EdgeInsets.all(ScreenAdapter.width(20)),
        child: ListView(
          children: <Widget>[
            SizedBox(height: 50),
            Container(
              padding: EdgeInsets.only(left: 10),
              child: Text("驗證碼已經發送到了您的${this.tel}手機,請輸入${this.tel}手機號收到的驗證碼"),
            ),
            SizedBox(height: 40),
            Stack(
              children: <Widget>[
                Container(
                  child: JdText(
                    text: "請輸入驗證碼",
                    onChanged: (value) {
                      // print(value);
                      this.code = value;
                    },
                  ),
                  height: ScreenAdapter.height(100),
                ),
                Positioned(
                  right: 0,
                  top: 0,
                  child: this.sendCodeBtn
                      ? RaisedButton(
                    child: Text('重新發送'),
                    onPressed: this.sendCode,
                  )
                      : RaisedButton(
                    child: Text('${this.seconds}秒后重發'),
                    onPressed: () {},
                  ),
                )
              ],
            ),
            SizedBox(height: 20),
            JdButton(
              text: "下一步",
              color: Colors.red,
              height: 74,
              cb: this.validateCode,
            )
          ],
        ),
      ),
    );
  }
}

16、從新頁面回傳資料給上一個頁面

效果圖一:

點擊按鈕
在這里插入圖片描述

效果圖二:
點擊YES后,回傳上一級頁面并傳值

在這里插入圖片描述

效果圖三:

收到值,并用底部彈出框顯示結果
在這里插入圖片描述

注釋+代碼:

import 'package:flutter/material.dart';

void main() {
  runApp(new MaterialApp(
    title: 'Returning Data',
    home: new HomeScreen(),
  ));
}

class HomeScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Returning Data Demo'),
      ),
      body: new Center(child: new SelectionButton()),
    );
  }
}

class SelectionButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new RaisedButton(
      onPressed: () {
        _navigateAndDisplaySelection(context);
      },
      child: new Text('Pick an option, any option!'),
    );
  }

  // A method that launches the SelectionScreen and awaits the result from
  // Navigator.pop!
  /**
   * 一種啟動SelectionScreen并等待以下結果的方法 Navigator.pop!
   */
  _navigateAndDisplaySelection(BuildContext context) async {
    // Navigator.push returns a Future that will complete after we call
    // Navigator.pop on the Selection Screen!
    /**
     * Navigator.push回傳一個Future,它將在我們呼叫后完成選擇螢屏上的Navigator.pop!
     */
    final result = await Navigator.push(
      context,
      new MaterialPageRoute(builder: (context) => new SelectionScreen()),
    );

    // After the Selection Screen returns a result, show it in a Snackbar!
    ///選擇螢屏回傳結果后,將其顯示在小吃欄中!
    Scaffold
        .of(context)
        .showSnackBar(new SnackBar(content: new Text("$result")));
  }
}

class SelectionScreen extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return new Scaffold(
      appBar: new AppBar(
        title: new Text('Pick an option'),
      ),
      body: new Center(
        child: new Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            new Padding(
              padding: const EdgeInsets.all(8.0),
              child: new RaisedButton(
                onPressed: () {
                  // Close the screen and return "Yep!" as the result
                  /// 關閉螢屏并回傳“是!” 作為結果
                  Navigator.pop(context, 'Yep!');
                },
                child: new Text('Yep!'),
              ),
            ),
            new Padding(
              padding: const EdgeInsets.all(8.0),
              child: new RaisedButton(
                onPressed: () {
                  // Close the screen and return "Nope!" as the result
                  /// 關閉螢屏并回傳“不!” 作為結果
                  Navigator.pop(context, 'Nope.');
                },
                child: new Text('Nope.'),
              ),
            )
          ],
        ),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:從新頁面回傳資料給上一個頁面

17、創建一個 grid List

效果圖:

在這里插入圖片描述

代碼+注釋:

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'Grid List';

    return new MaterialApp(
      title: title,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text(title),
        ),
        body: new GridView.count(
          // Create a grid with 2 columns. If you change the scrollDirection to
          // horizontal, this would produce 2 rows.
          /**
           * 創建一個包含2列的網格, 如果將scrollDirection更改為水平,這將產生2行,
           */
          crossAxisCount: 2,
          // Generate 100 Widgets that display their index in the List
          // 生成100個在串列中顯示其索引的小部件,引數一: 數量,引數二: 下標
          children: new List.generate(100, (index) {
            return new Center(
              child: new Text(
                'Item $index',
                style: Theme.of(context).textTheme.headline,
              ),
            );
          }),
        ),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:創建一個 grid List

18、使用不同型別的子項創建串列

效果圖:

在這里插入圖片描述

代碼+注釋:

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

void main() {
  runApp(new MyApp(
    //  List.generate建構式 —— 生成擁有1000個字串的串列
    items: new List<ListItem>.generate(
      1000,
          (i) => i % 6 == 0       //根據規律: 每一個標題后面會跟著五條內容
          ? new HeadingItem("Heading $i")     //標題型別
          : new MessageItem("Sender $i", "Message body $i"),    //內容型別
    ),
  ));
}

class MyApp extends StatelessWidget {
  final List<ListItem> items;

  MyApp({Key key, @required this.items}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final title = 'Mixed List';

    return new MaterialApp(
      title: title,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text(title),
        ),
        body: new ListView.builder(
          // Let the ListView know how many items it needs to build
          // 讓ListView知道需要構建多少個專案
          itemCount: items.length,
          // Provide a builder function. This is where the magic happens! We'll
          //  提供構建器功能, 這就是魔術發生的地方! 好
          // convert each item into a Widget based on the type of item it is.
          //  根據專案型別將每個專案轉換為Widget,
          itemBuilder: (context, index) {
            final item = items[index];      //得到具體的items

            if (item is HeadingItem) {    //是否為標題型別
              return new ListTile(
                title: new Text(
                  item.heading,
                  style: Theme.of(context).textTheme.headline,
                ),
              );
            } else if (item is MessageItem) { //是否為內容型別
              return new ListTile(
                title: new Text(item.sender),
                subtitle: new Text(item.body),
              );
            }
          },
        ),
      ),
    );
  }
}

// The base class for the different types of items the List can contain
// 串列可以包含的不同型別的專案的基類
abstract class ListItem {}

// A ListItem that contains data to display a heading
// 一個ListItem,其中包含顯示標題的資料
class HeadingItem implements ListItem {
  final String heading;

  HeadingItem(this.heading);
}

// A ListItem that contains data to display a message
// 一個ListItem包含顯示訊息的資料
class MessageItem implements ListItem {
  final String sender;
  final String body;

  MessageItem(this.sender, this.body);
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:使用不同型別的子項創建串列

19、使用長串列

效果圖:
利用 List.generate建構式 —— 配合 ListView 生成擁有10000個字串的串列
在這里插入圖片描述

代碼+注釋:

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

void main() {
  runApp(new MyApp(
    //  List.generate建構式 —— 生成擁有10000個字串的串列
    items: new List<String>.generate(10000, (i) => "Item $i"),
  ));
}

class MyApp extends StatelessWidget {
  final List<String> items;

  MyApp({Key key, @required this.items}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final title = 'Long List';

    return new MaterialApp(
      title: title,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text(title),
        ),
        body: new ListView.builder(
          itemCount: items.length,          //List長度
          itemBuilder: (context, index) {   //Item構造者
            return new ListTile(
              title: new Text('${items[index]}'),
            );
          },
        ),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!
更多原理請參考谷歌官網:
使用長串列

20、用占位符淡入淡出的顯示圖片

效果圖一:
由于是網路圖片,加載速度由網速決定,所以先顯示進度條圈圈
在這里插入圖片描述

效果圖二:
加載完畢后,淡入淡出的顯示圖片,不是一下子顯示的喲!

在這里插入圖片描述

匯入依賴:

transparent_image: ^1.0.0

代碼+注釋:

import 'package:chapter02one/Api.dart';
import 'package:flutter/material.dart';
import 'package:transparent_image/transparent_image.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final title = 'Fade in images';

    return new MaterialApp(
      title: title,
      home: new Scaffold(
        appBar: new AppBar(
          title: new Text(title),
        ),
        body: new Stack(
          children: <Widget>[
            new Center(child: new CircularProgressIndicator()),
            new Center(
              /**
               * FadeInImage.memoryNetwork
               * 正在加載時,會顯示加載進度條
               * 加載完畢后,會慢慢淡入淡出的顯示圖片
               */
              child: new FadeInImage.memoryNetwork(
                placeholder: kTransparentImage,
                image:
                '${Api.URL}/aa.png',
              ),
            ),
          ],
        ),
      ),
    );
  }
}

喜歡記得點個贊喲,我是王睿,很高興認識大家!

更多原理請參考谷歌官網:
用占位符淡入圖片

21、Dart中dynamic,var,object三者的區別

void main()//dynamic,var,object三者的區別
{
  //dynamic
  dynamic x = 'hello';//編譯時不會揣測資料型別,但是運行時會推斷
  print(x.runtimeType);//String
  print(x);
  //但是這樣的壞處就是會讓dart的語法檢查失效,所以有可能會造成混亂而不報錯
  //所以不要直接使用dynamic
  x = 123;
  print(x.runtimeType);//int,說明型別是可變的
  print(x);
 
  //var
  var a = 'hello';
  print(a.runtimeType);
  print(a);
  //a = 123;//會報錯
  a = '123';
  print(a);
 
  //Object
  Object w = 1;
  print(w.runtimeType);
  print(w);
  //不能呼叫Object不存在的方法
  
}

22、TextField設定默認值默認值和游標位置

TextField(
          //輸入鍵盤型別
              keyboardType: TextInputType.text,
              autofocus: true,
              decoration: InputDecoration(
                border: OutlineInputBorder(
                    borderRadius: BorderRadius.circular(),
                    borderSide: BorderSide.none),
              ),
              onChanged: (value) {
                this._keyword = value;
              },
              controller: TextEditingController.fromValue(TextEditingValue(
                  text: '${this._keyword == null ? "" : this._keyword}',  //判斷keyword是否為空
                  // 保持游標在最后
 
                  selection: TextSelection.fromPosition(TextPosition(
                      affinity: TextAffinity.downstream,
                      offset: '${this._keyword}'.length)))),
            ),

23、限制TextField只能輸入漢字或英文字母或數字,并限制輸入最多中文10字符,英文20字符

原文地址

第一步,給textfield設定輸入法則:

inputFormatters: [
WhitelistingTextInputFormatter(RegExp(
“[a-zA-Z]|[\u4e00-\u9fa5]|[0-9]”)), //只能輸入漢字或者字母或數字
LengthLimitingTextInputFormatter(maxLength),//最大長度
],
第二步,動態修改最大字長:

onChanged: (value) {
_changeMaxLimit(value);
},
/// 改字數限制,每輸入一個中文字符,要減1,
/// 字符要求:10個漢字或20個英文
void _changeMaxLimit(String value) {
maxLength = 20;
for (int i = 0; i < value.length; i++) {
if (value.codeUnitAt(i) > 122) {
maxLength–;
}
}
setState(() {});
}
我這里簡略寫了關鍵部分,關于maxLength的初始化,textfield別的引數設定,大家還請自行解決,

24、Dart之正則運算式相關方法總結

原文地址

【Dart學習】–Dart之正則運算式相關方法總結
一,部分屬性
RegExp exp = new RegExp(r"(\w+)");

回傳正則運算式的哈希碼
print(exp.hashCode);
正則運算式是否區分大小寫
print(exp.isCaseSensitive);
正則運算式是否匹配多行
print(exp.isMultiLine);
回傳源正則運算式字串
print(exp.pattern);
回傳物件運行時的型別
print(exp.runtimeType);
二,常用方法

25、使用正則運算式驗證手機號

RegExp exp = RegExp(
          r'^((13[0-9])|(14[0-9])|(15[0-9])|(16[0-9])|(17[0-9])|(18[0-9])|(19[0-9]))\d{8}$');
bool matched = exp.hasMatch(mobileTextController.text);

26、去掉輸入框最大字數顯示

new TextField(
       maxLength:11 ,
       enabled:widget.phone == null?true:false,
       keyboardType: TextInputType.number,
       decoration: InputDecoration(`在這里插入代碼片`
       counterText: "",//此處控制最大字符是否顯示
       hintText: widget.phone == null?'手機號':widget.phone,
       hintStyle: TextStyle(fontSize: 14,color: AppColors.colorGrayText),
       border: InputBorder.none,
     ),
     controller: _phoneContro,    ));

27、TextField 限制只允許輸入數字,字母,小數,設定限制小數位數

原文地址

TextField(
          inputFormatters: [
          //只允許輸入字母
            WhitelistingTextInputFormatter(RegExp("[a-zA-Z]")),
          ],
   ),
    TextField(
    //只允許輸入數字
          inputFormatters: [WhitelistingTextInputFormatter.digitsOnly],
   ),
    TextField(
      			inputFormatters: [
                          //只允許輸入小數
                            WhitelistingTextInputFormatter(RegExp("[0-9.]")),
                          ],,
    TextField(
      			inputFormatters: [
                          //限制小數位數
                            _MyNumberTextInputFormatter(digit:5),
                          ],// 限制小數位數
class _MyNumberTextInputFormatter extends TextInputFormatter {
  static const defaultDouble = 0.001;
  ///允許的小數位數,-1代表不限制位數
  int digit;
  _MyNumberTextInputFormatter({this.digit=-1});
  static double strToFloat(String str, [double defaultValue = defaultDouble]) {
    try {
      return double.parse(str);
    } catch (e) {
      return defaultValue;
    }
  }
  ///獲取目前的小數位數
  static int getValueDigit(String value){
    if(value.contains(".")){
      return value.split(".")[1].length;
    }else{
      return -1;
    }
  }


  @override
  TextEditingValue formatEditUpdate(TextEditingValue oldValue, TextEditingValue newValue) {
    String value = newValue.text;
    int selectionIndex = newValue.selection.end;
    if (value == ".") {
      value = "0.";
      selectionIndex++;
    } else if (value != ""
        && value != defaultDouble.toString()
        && strToFloat(value, defaultDouble) == defaultDouble
        ||getValueDigit(value)>digit) {
      value = oldValue.text;
      selectionIndex = oldValue.selection.end;
    }
    return new TextEditingValue(
      text: value,
      selection: new TextSelection.collapsed(offset: selectionIndex),
    );
  }
}

28、TextField 文本輸入框的基本屬性及詳解

const TextField({
    Key key,
    this.controller,                    // 控制正在編輯文本
    this.focusNode,                     // 獲取鍵盤焦點
    this.decoration = const InputDecoration(),              // 邊框裝飾
    TextInputType keyboardType,         // 鍵盤型別
    this.textInputAction,               // 鍵盤的操作按鈕型別
    this.textCapitalization = TextCapitalization.none,      // 配置大小寫鍵盤
    this.style,                         // 輸入文本樣式
    this.textAlign = TextAlign.start,   // 對齊方式
    this.textDirection,                 // 文本方向
    this.autofocus = false,             // 是否自動對焦
    this.obscureText = false,           // 是否隱藏內容,例如密碼格式
    this.autocorrect = true,            // 是否自動校正
    this.maxLines = 1,                  // 最大行數
    this.maxLength,                     // 允許輸入的最大長度
    this.maxLengthEnforced = true,      // 是否允許超過輸入最大長度
    this.onChanged,                     // 文本內容變更時回呼
    this.onEditingComplete,             // 提交內容時回呼
    this.onSubmitted,                   // 用戶提示完成時回呼
    this.inputFormatters,               // 驗證及格式
    this.enabled,                       // 是否不可點擊
    this.cursorWidth = 2.0,             // 游標寬度
    this.cursorRadius,                  // 游標圓角弧度
    this.cursorColor,                   // 游標顏色
    this.keyboardAppearance,            // 鍵盤亮度
    this.scrollPadding = const EdgeInsets.all(20.0),        // 滾動到視圖中時,填充邊距
    this.enableInteractiveSelection,    // 長按是否展示【剪切/復制/粘貼選單LengthLimitingTextInputFormatter】
    this.onTap,                         // 點擊時回呼
})

29、實作農歷(陰歷)轉公歷(陽歷)

/**
 * 農歷的工具類
 */
class LunarCalendarUtil {
  /**
   * 支持轉換的最小農歷年份
   */
  static final int MIN_YEAR = 1900;

  /**
   * 支持轉換的最大農歷年份
   */
  static final int MAX_YEAR = 2099;
  /**
   * 公歷每月前的天數
   */
  static final List<int> DAYS_BEFORE_MONTH = [0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365];

  /**
   * 用來表示1900年到2099年間農歷年份的相關資訊,共24位bit的16進制表示,其中:
   * 1. 前4位表示該年閏哪個月;
   * 2. 5-17位表示農歷年份13個月的大小月分布,0表示小,1表示大;
   * 3. 最后7位表示農歷年首(正月初一)對應的公歷日期,
   * 以2014年的資料0x955ABF為例說明:
   * 1001 0101 0101 1010 1011 1111
   *  閏九月   農歷正月初一對應公歷1月31號
   */
  static final List<int> LUNAR_INFO = [
    /*1900*/
    0x84B6BF,
    /*1901-1910*/
    0x04AE53, 0x0A5748, 0x5526BD, 0x0D2650, 0x0D9544, 0x46AAB9, 0x056A4D, 0x09AD42, 0x24AEB6, 0x04AE4A,
    /*1911-1920*/
    0x6A4DBE, 0x0A4D52, 0x0D2546, 0x5D52BA, 0x0B544E, 0x0D6A43, 0x296D37, 0x095B4B, 0x749BC1, 0x049754,
    /*1921-1930*/
    0x0A4B48, 0x5B25BC, 0x06A550, 0x06D445, 0x4ADAB8, 0x02B64D, 0x095742, 0x2497B7, 0x04974A, 0x664B3E,
    /*1931-1940*/
    0x0D4A51, 0x0EA546, 0x56D4BA, 0x05AD4E, 0x02B644, 0x393738, 0x092E4B, 0x7C96BF, 0x0C9553, 0x0D4A48,
    /*1941-1950*/
    0x6DA53B, 0x0B554F, 0x056A45, 0x4AADB9, 0x025D4D, 0x092D42, 0x2C95B6, 0x0A954A, 0x7B4ABD, 0x06CA51,
    /*1951-1960*/
    0x0B5546, 0x555ABB, 0x04DA4E, 0x0A5B43, 0x352BB8, 0x052B4C, 0x8A953F, 0x0E9552, 0x06AA48, 0x6AD53C,
    /*1961-1970*/
    0x0AB54F, 0x04B645, 0x4A5739, 0x0A574D, 0x052642, 0x3E9335, 0x0D9549, 0x75AABE, 0x056A51, 0x096D46,
    /*1971-1980*/
    0x54AEBB, 0x04AD4F, 0x0A4D43, 0x4D26B7, 0x0D254B, 0x8D52BF, 0x0B5452, 0x0B6A47, 0x696D3C, 0x095B50,
    /*1981-1990*/
    0x049B45, 0x4A4BB9, 0x0A4B4D, 0xAB25C2, 0x06A554, 0x06D449, 0x6ADA3D, 0x0AB651, 0x095746, 0x5497BB,
    /*1991-2000*/
    0x04974F, 0x064B44, 0x36A537, 0x0EA54A, 0x86B2BF, 0x05AC53, 0x0AB647, 0x5936BC, 0x092E50, 0x0C9645,
    /*2001-2010*/
    0x4D4AB8, 0x0D4A4C, 0x0DA541, 0x25AAB6, 0x056A49, 0x7AADBD, 0x025D52, 0x092D47, 0x5C95BA, 0x0A954E,
    /*2011-2020*/
    0x0B4A43, 0x4B5537, 0x0AD54A, 0x955ABF, 0x04BA53, 0x0A5B48, 0x652BBC, 0x052B50, 0x0A9345, 0x474AB9,
    /*2021-2030*/
    0x06AA4C, 0x0AD541, 0x24DAB6, 0x04B64A, 0x6a573D, 0x0A4E51, 0x0D2646, 0x5E933A, 0x0D534D, 0x05AA43,
    /*2031-2040*/
    0x36B537, 0x096D4B, 0xB4AEBF, 0x04AD53, 0x0A4D48, 0x6D25BC, 0x0D254F, 0x0D5244, 0x5DAA38, 0x0B5A4C,
    /*2041-2050*/
    0x056D41, 0x24ADB6, 0x049B4A, 0x7A4BBE, 0x0A4B51, 0x0AA546, 0x5B52BA, 0x06D24E, 0x0ADA42, 0x355B37,
    /*2051-2060*/
    0x09374B, 0x8497C1, 0x049753, 0x064B48, 0x66A53C, 0x0EA54F, 0x06AA44, 0x4AB638, 0x0AAE4C, 0x092E42,
    /*2061-2070*/
    0x3C9735, 0x0C9649, 0x7D4ABD, 0x0D4A51, 0x0DA545, 0x55AABA, 0x056A4E, 0x0A6D43, 0x452EB7, 0x052D4B,
    /*2071-2080*/
    0x8A95BF, 0x0A9553, 0x0B4A47, 0x6B553B, 0x0AD54F, 0x055A45, 0x4A5D38, 0x0A5B4C, 0x052B42, 0x3A93B6,
    /*2081-2090*/
    0x069349, 0x7729BD, 0x06AA51, 0x0AD546, 0x54DABA, 0x04B64E, 0x0A5743, 0x452738, 0x0D264A, 0x8E933E,
    /*2091-2099*/
    0x0D5252, 0x0DAA47, 0x66B53B, 0x056D4F, 0x04AE45, 0x4A4EB9, 0x0A4D4C, 0x0D1541, 0x2D92B5
  ];

  /**
   * 將農歷日期轉換為公歷日期
   * @param year    農歷年份
   * @param month   農歷月
   * @param monthDay   農歷日
   * @param isLeapMonth   該月是否是閏月(該引數可以根據本類中leapMonth()方法,先判斷一下要查詢的年份是否有閏月,并且閏的幾月)
   * @return 回傳農歷日期對應的公歷日期,year0, month1, day2.
   */
  static  List<int> lunarToSolar(int year, int month, int monthDay, bool isLeapMonth) {
    int dayOffset;
    int leapMonth;
    int i;
    if (year < MIN_YEAR || year > MAX_YEAR || month < 1 || month > 12
        || monthDay < 1 || monthDay > 30) {
      throw new Exception(
          "Illegal lunar date, must be like that:\n\t" +
              "year : 1900~2099\n\t" +
              "month : 1~12\n\t" +
              "day : 1~30");
    }
    dayOffset = (LUNAR_INFO[year - MIN_YEAR] & 0x001F) - 1;
    if (((LUNAR_INFO[year - MIN_YEAR] & 0x0060) >> 5) == 2) {
      dayOffset += 31;
    }
    for (i = 1; i < month; i++) {
      if ((LUNAR_INFO[year - MIN_YEAR] & (0x80000 >> (i - 1))) == 0) {
        dayOffset += 29;
      } else {
        dayOffset += 30;
      }
    }
    dayOffset += monthDay;
    leapMonth = (LUNAR_INFO[year - MIN_YEAR] & 0xf00000) >> 20;
    // 這一年有閏月
    if (leapMonth != 0) {
      if (month > leapMonth || (month == leapMonth && isLeapMonth)) {
        if ((LUNAR_INFO[year - MIN_YEAR] & (0x80000 >> (month - 1))) == 0) {
          dayOffset += 29;
        } else {
          dayOffset += 30;
        }
      }
    }
    if (dayOffset > 366 || (year % 4 != 0 && dayOffset > 365)) {
      year += 1;
      if (year % 4 == 1) {
        dayOffset -= 366;
      } else {
        dayOffset -= 365;
      }
    }
    List<int> solarInfo = new List(3);
    for (i = 1; i < 13; i++) {
      int iPos = DAYS_BEFORE_MONTH[i];
      if (year % 4 == 0 && i > 2) {
        iPos += 1;
      }
      if (year % 4 == 0 && i == 2 && iPos + 1 == dayOffset) {
        solarInfo[1] = i;
        solarInfo[2] = dayOffset - 31;
        break;
      }
      if (iPos >= dayOffset) {
        solarInfo[1] = i;
        iPos = DAYS_BEFORE_MONTH[i - 1];
        if (year % 4 == 0 && i > 2) {
          iPos += 1;
        }
        if (dayOffset > iPos) {
          solarInfo[2] = dayOffset - iPos;
        } else if (dayOffset == iPos) {
          if (year % 4 == 0 && i == 2) {
            solarInfo[2] = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1] + 1;
          } else {
            solarInfo[2] = DAYS_BEFORE_MONTH[i] - DAYS_BEFORE_MONTH[i - 1];
          }
        } else {
          solarInfo[2] = dayOffset;
        }
        break;
      }
    }
    solarInfo[0] = year;
    return solarInfo;
  }

  /**
   * 傳回農歷year年month月的總天數
   *
   * @param year   要計算的年份
   * @param month        要計算的月
   * @return 傳回天數
   */
  static int daysInMonth(int year, int month) {
    return daysInMontaThree(year, month, false);
  }

  /**
   * 傳回農歷year年month月的總天數
   *
   * @param year   要計算的年份
   * @param month    要計算的月
   * @param leap   當月是否是閏月
   * @return 傳回天數,如果閏月是錯誤的,回傳0.
   */
  static int daysInMontaThree(int year, int month, bool leap) {
    int mLeapMonth = leapMonth(year);
    int offset = 0;
    // 如果本年有閏月且month大于閏月時,需要校正
    if (leapMonth != 0 && month > mLeapMonth) {
      offset = 1;
    }
    // 不考慮閏月
    if (!leap) {
      return daysInLunarMonth(year, month + offset);
    } else {
      // 傳入的閏月是正確的月份
      if (leapMonth != 0 && leapMonth == month) {
        return daysInLunarMonth(year, month + 1);
      }
    }
    return 0;
  }

  /**
   * 傳回農歷 year年的總天數
   *
   * @param year 將要計算的年份
   * @return 回傳傳入年份的總天數
   */
  static int daysInLunarYear(int year) {
    int i, sum = 348;
    if (leapMonth(year) != 0) {
      sum = 377;
    }
    int monthInfo = LUNAR_INFO[year - MIN_YEAR] & 0x0FFF80;
    for (i = 0x80000; i > 0x7; i >>= 1) {
      if ((monthInfo & i) != 0) {
        sum += 1;
      }
    }
    return sum;
  }

  /**
   * 傳回農歷 year年month月的總天數,總共有13個月包括閏月
   *
   * @param year  將要計算的年份
   * @param month 將要計算的月份
   * @return 傳回農歷 year年month月的總天數
   */
  static int daysInLunarMonth(int year, int month) {
    if ((LUNAR_INFO[year - MIN_YEAR] & (0x100000 >> month)) == 0) {
      return 29;
    } else {
      return 30;
    }
  }

  /**
   * 傳回農歷 year年閏哪個月 1-12 , 沒閏傳回 0
   * @param year 將要計算的年份
   * @return 傳回農歷 year年閏哪個月1-12, 沒閏傳回 0
   */
  static int leapMonth(int year) {
    return ((LUNAR_INFO[year - MIN_YEAR] & 0xF00000)) >> 20;
  }
}

測驗資料:

測驗資料:2020125日轉公歷結果為:2021117Text('${LunarCalendarUtil.lunarToSolar(2020, 12, 5, true)}'),

30、SDK升級

1、在終端中使用flutter upgrade
2、洗掉SDK包重新下載

31、Expanded組件不能直接嵌套LitView報錯,解決辦法

這樣寫,即可解決問題!

Row(
          children: <Widget>[
            Expanded(
              flex: 1,
              child: Container(
                height: 180,
                child: ListView(
                  children: <Widget>[
                    Container(
                      height: 85,
                      child: Image.network("https://www.itying.com/images/flutter/3.png",fit: BoxFit.cover),

                    ),
                    SizedBox(height: 10),
                    Container(
                      height: 85,
                      child: Image.network("https://www.itying.com/images/flutter/4.png",fit: BoxFit.cover),
                    )
                  ],
                )
              )
            ),

          ],
        )

32、ListView不能直接嵌套ListView解決辦法

ListView(
        scrollDirection: Axis.horizontal,
        children: <Widget>[
          Container(
            width: 180,
            color: Colors.orange,
            child: ListView(
              children: <Widget>[
                Image.network("https://www.itying.com/images/flutter/1.png"),
                Text('我是一個文本')
              ],
            ),
          ),
        ],
      ),

直接套一個Container即可解決問題

32、Text的overflow屬性不生效(14)

Text的overflow屬性不生效(14)

33、

轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/291072.html

標籤:其他

上一篇:【鴻蒙】鴻蒙App應用-《校園通》開發步驟

下一篇:MacBook 配置adb命令

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【從零開始擼一個App】Dagger2

    Dagger2是一個IOC框架,一般用于Android平臺,第一次接觸的朋友,一定會被搞得暈頭轉向。它延續了Java平臺Spring框架代碼碎片化,注解滿天飛的傳統。嘗試將各處代碼片段串聯起來,理清思緒,真不是件容易的事。更不用說還有各版本細微的差別。 與Spring不同的是,Spring是通過反射 ......

    uj5u.com 2020-09-10 06:57:59 more
  • Flutter Weekly Issue 66

    新聞 Flutter 季度調研結果分享 教程 Flutter+FaaS一體化任務編排的思考與設計 詳解Dart中如何通過注解生成代碼 GitHub 用對了嗎?Flutter 團隊分享如何管理大型開源專案 插件 flutter-bubble-tab-indicator A Flutter librar ......

    uj5u.com 2020-09-10 06:58:52 more
  • Proguard 常用規則

    介紹 Proguard 入口,如何查看輸出,如何使用 keep 設定入口以及使用實體,如何配置壓縮,混淆,校驗等規則。

    ......

    uj5u.com 2020-09-10 06:59:00 more
  • Android 開發技術周報 Issue#292

    新聞 Android即將獲得類AirDrop功能:可向附近設備快速分享檔案 谷歌為安卓檔案管理應用引入可安全隱藏資料的Safe Folder功能 Android TV新主界面將顯示電影、電視節目和應用推薦內容 泄露的Android檔案暗示了傳說中的谷歌Pixel 5a與折疊屏新機 谷歌發布Andro ......

    uj5u.com 2020-09-10 07:00:37 more
  • AutoFitTextureView Error inflating class

    報錯: Binary XML file line #0: Binary XML file line #0: Error inflating class xxx.AutoFitTextureView 解決: <com.example.testy2.AutoFitTextureView android: ......

    uj5u.com 2020-09-10 07:00:41 more
  • 根據Uri,Cursor沒有獲取到對應的屬性

    Android: 背景:呼叫攝像頭,拍攝視頻,指定保存的地址,但是回傳的Cursor檔案,只有名稱和大小的屬性,沒有其他諸如時長,連ID屬性都沒有 使用 cursor.getInt(cursor.getColumnIndexOrThrow(MediaStore.Video.Media.DURATIO ......

    uj5u.com 2020-09-10 07:00:44 more
  • Android連載29-持久化技術

    一、持久化技術 我們平時所使用的APP產生的資料,在記憶體中都是瞬時的,會隨著斷電、關機等丟失資料,因此android系統采用了持久化技術,用于存盤這些“瞬時”資料 持久化技術包括:檔案存盤、SharedPreference存盤以及資料庫存盤,還有更復雜的SD卡記憶體儲。 二、檔案存盤 最基本存盤方式, ......

    uj5u.com 2020-09-10 07:00:47 more
  • Android Camera2Video整合到自己專案里

    背景: Android專案里呼叫攝像頭拍攝視頻,原本使用的 MediaStore.ACTION_VIDEO_CAPTURE, 后來因專案需要,改成了camera2 1.Camera2Video 官方demo有點問題,下載后,不能直接整合到專案 問題1.多次拍攝視頻崩潰 問題2.雙擊record按鈕, ......

    uj5u.com 2020-09-10 07:00:50 more
  • Android 開發技術周報 Issue#293

    新聞 谷歌為Android TV開發者提供多種新功能 Android 11將自動填表功能整合到鍵盤輸入建議中 谷歌宣布Android Auto即將支持更多的導航和數字停車應用 谷歌Pixel 5只有XL版本 搭載驍龍765G且將比Pixel 4更便宜 [圖]Wear OS將迎來重磅更新:應用啟動時間 ......

    uj5u.com 2020-09-10 07:01:38 more
  • 海豚星空掃碼投屏 Android 接收端 SDK 集成 六步驟

    掃碼投屏,開放網路,獨占設備,不需要額外下載軟體,微信掃碼,發現設備。支持標準DLNA協議,支持倍速播放。視頻,音頻,圖片投屏。好點意思。還支持自定義基于 DLNA 擴展的操作動作。好像要收費,沒體驗。 這里簡單記錄一下集成程序。 一 跟目錄的build.gradle添加私有mevan倉庫 mave ......

    uj5u.com 2020-09-10 07:01:43 more
最新发布
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:40:31 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:40:11 more
  • 歡迎頁輪播影片

    如圖,引導開始,球從上落下,同時淡入文字,然后文字開始輪播,最后一頁時停止,點擊進入首頁。 在來看看效果圖。 重力球先不講,主要歡迎輪播簡單實作 首先新建一個類 TextTranslationXGuideView,用于影片展示 文本是類似的,最后會有個圖片箭頭影片,布局很簡單,就是一個 TextVi ......

    uj5u.com 2023-04-20 08:39:36 more
  • 【FAQ】關于華為推送服務因營銷訊息頻次管控導致服務通訊類訊息

    一. 問題描述 使用華為推送服務下發IM訊息時,下發訊息請求成功且code碼為80000000,但是手機總是收不到訊息; 在華為推送自助分析(Beta)平臺查看發現,訊息發送觸發了頻控。 二. 問題原因及背景 2023年1月05日起,華為推送服務對咨詢營銷類訊息做了單個設備每日推送數量上限管理,具體 ......

    uj5u.com 2023-04-20 08:39:13 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:16:23 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:16:15 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:15:46 more
  • iOS從UI記憶體地址到讀取成員變數(oc/swift)

    開發除錯時,我們發現bug時常首先是從UI顯示發現例外,下一步才會去定位UI相關連的資料的。XCode有給我們提供一系列debug工具,但是很多人可能還沒有形成一套穩定的除錯流程,因此本文嘗試解決這個問題,順便提出一個暴論:UI顯示例外問題只需要兩個步驟就能完成定位作業的80%: 定位例外 UI 組 ......

    uj5u.com 2023-04-19 09:14:53 more
  • FIDE重磅更新!性能飛躍!體驗有禮!

    FIDE 開發者工具重構升級啦!實作500%性能提升,誠邀體驗! 一直以來不少開發者朋友在社區反饋,在使用 FIDE 工具的程序中,時常會遇到諸如加載不及時、代碼預覽/渲染性能不如意的情況,十分影響開發體驗。 作為技術團隊,我們深知一件趁手的開發工具對開發者的重要性,因此,在2023年開年,FinC ......

    uj5u.com 2023-04-19 09:14:08 more
  • 游戲內嵌社區服務開放,助力開發者提升玩家互動與留存

    華為 HMS Core 游戲內嵌社區服務提供快速訪問華為游戲中心論壇能力,支持玩家直接在游戲內瀏覽帖子和交流互動,助力開發者擴展內容生產和觸達的場景。 一、為什么要游戲內嵌社區? 二、游戲內嵌社區的典型使用場景 1、游戲內打開論壇 您可以在游戲內繪制論壇入口,為玩家提供沉浸式發帖、瀏覽、點贊、回帖、 ......

    uj5u.com 2023-04-19 09:08:34 more