Flutter 萌新高頻問題(加班猿媽媽叫你回家吃飯了)

法的空間發表於2018-12-19

想寫這個很久了,每個人都是從萌新來的,在一些國內Flutter群裡(482462250,422833104)呆著, 經常有很多重複的問題在群裡反覆出現,導致群裡大佬都不愛搭理了。 下面的目錄會不斷更新,如果內容太多,我會拆分掉。

FlutterCandies QQ群:181398081

Flutter 萌新高頻問題(加班猿媽媽叫你回家吃飯了)

我們的組織OpenFlutter,海量外掛萌新必備庫

目錄

以下集合由 什麼都懂一些的財經龍 big nao 授權

Flutter 萌新高頻問題(加班猿媽媽叫你回家吃飯了)

大佬有很多有用外掛Github

我是誰,我從哪裡來,我要做什麼

Flutter跟其他混合開發模式比怎麼樣?

安卓IOS原生是不是滅亡了?

有沒有線上的Flutter產品?

這應該是每個程式猿選擇新的領域的一種焦慮吧,其實我們可以根據自己的情況,以及該領域的發展前景來進行自己的判斷。答案肯定不是唯一的。在塞班滅亡之前,沒人可以那麼肯定它就這樣亡了。一個程式猿當然也不可能一輩子只是接觸一個技術一個領域,學習難道不是作為程式猿來說的一種樂趣嗎。對於前2個問題,我沒法說出標準答案,第三個,有,鹹魚,愛奇藝,東方財富都在原生的基礎上嵌入了Flutter。

萌新入門看啥

Google官方的widget介紹,有中文字幕

Flutter官網

Dart官網

萌新的自己解決問題的能力

每個人都從萌新而來,如果你想開森的寫程式碼,自己解決問題是必須的

  • 英語是很重要的。

  • GoogleSO能解決你大部分的問題

  • 問問題的時候,儘量上程式碼,或者說明你的意圖,因為可能你的想法或者解決方向就是錯誤的

    Flutter 萌新高頻問題(加班猿媽媽叫你回家吃飯了)

狀態列怎麼透明

還是原生大法好,已經有外掛支援,安心食用 flutter_statusbarcolor

怎麼去掉列表上拉或者下拉時候的波紋

glow_notification_widget

該元件在外掛loading_more_list當中

下拉重新整理

掘金-下拉重新整理

上拉載入更多

掘金-上拉載入更多

NestedScrollView的使用

官方的NestedScrollView是有一些缺陷的,在使用這個元件之前,強烈建議食用,裡面的Demo也有NestedScrollView的用法。

掘金-NestedScrollView

我的列表怎麼了

列表或者說ScrollView其實有一個可視區域的概念(Viewport),就是滾動時候的可見的部分,這個區域的大小往往需要你自己告訴他。

  • 列表放在Column裡面

錯誤示例

   child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '測試',
            ),
            ListView.builder(itemBuilder: (context,index){})
          ],
        ),
複製程式碼

你想在列表上面加個Text,當然可能是別的。你把2個元件放到了Column裡面,但是注意,Column裡面的元素,預設是自動大小的,就autosize.這就會造成ListView認為外面的區域是無限大的,它會構建出全部的Items,超出的部分會被截掉,列表也會失去滾動的效果。

正確示例

child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              '測試',
            ),
            Expanded(
              child: ListView.builder(itemBuilder: (context, index) {}),
            )
          ],
        ),
複製程式碼

將列表放進一個Expanded,表示列表的可視區域是除去Text之後的剩下的區域,這樣列表就有了它確定的可視區域

  • List裡面可以放List嗎?

大部分人有這種想法。其實是想水平和垂直區域都要有對應的滾動。

程式碼示例

 CustomScrollView(
        slivers: <Widget>[
          //水平
          SliverToBoxAdapter(
            child: Container(
              height: 40.0,
              child: ListView.builder(
                itemBuilder: (context, index) {
                  return Text("測試${index}");
                },
                itemCount: 50,
                scrollDirection: Axis.horizontal,
              ),
            ),
          ),
          //垂直
          SliverList(
            delegate: SliverChildBuilderDelegate((context, index) {
              return Text("測試${index}");
            }, childCount: 50),
          )
        ],
      ),
複製程式碼

注意你要給水平的列表增加指定的高度,因為對於垂直方向來說。。這個水平列表如果沒有固定高度,那麼垂直方法的viewport將沒法進行計算

  • 使用ListView還是SliverList?

這2者的區別在於 1.SliverList必須放在Sliver系列裡面,常見的是CustomScrollView,NestedScrollView的header裡面。 請牢牢記住,Sliver系列只能放Sliver系列,別直接把其他widget比如Container/ListView直接放裡面。 2.ListView內部其實也是包裹了ScrollView,而SliverList依靠的是外部的CustomScrollView或者NestedScrollView的header 裡面的ScrollView 來進行控制的。

這裡我們提一下常用的Sliver元件

CustomScrollView

是Sliver元件的老祖宗,全部的Sliver都放在這個裡面。

SliverList, which is a sliver that displays linear list of children.

SliverFixedExtentList, which is a more efficient sliver that displays linear list of children that have the same extent along the scroll axis. 比SliverList多一個就是相同的行高。這樣效能會更好

SliverGrid, which is a sliver that displays a 2D array of children. 可以設定每行的個數的Grid

SliverPersistentHeader A sliver whose size varies when the sliver is scrolled to the leading edge of the viewport. This is the layout primitive that SliverAppBar uses for its shrinking/growing effect.

非常好用的元件,SliverAppBar就是用這個實現的。這個元件的特點是可以建立出隨著滑動變化的可以Pinned的元素,大家經常用的什麼吸頂元件可以用這個很方便的構建

SliverToBoxAdapter 當你想把一個非Sliver的Widget放在CustomScrollview裡面的時候,你需要用這個包裹一下。千萬別把非Sliver widget直接放在Sliver裡面,記得用這個

SliverFillRemaining sizes its child to fill the viewport in the cross axis and to fill the remaining space in the viewport in the main axis. 使用這個它會填充完剩餘viewport裡面的全部空間

SliverPadding, which is a sliver that adds blank space around another sliver. 你可以把不是Sliver系列的widget放這個裡面,跟SliverToBoxAdapter效果差不多,其實你也可以用SliverToBoxAdapter 裡面放個Padding來實現

SliverAppBar, which is a sliver that displays a header that can expand and float as the scroll view scrolls.

SliverSafeArea A sliver that insets another sliver by sufficient padding to avoid intrusions by the operating system. For example, this will indent the sliver by enough to avoid the status bar at the top of the screen.為了防止各種邊界的越界,比如說越過頂部的狀態列,跟SafeArea效果一樣。只是這個是放Sliver裡面的

除了Sliver列表之外,SliverToBoxAdapter,SliverFillRemaining是Sliver系列裡面高頻使用的元件。

圓角

ClipRRect(
        borderRadius: new BorderRadius.circular(radius),child:child)
複製程式碼

點選水波紋

 return InkWell(
                    child: Text("測試${index}"),
                    onTap: () {},
                  );
複製程式碼

點選空白透明區域沒事件響應

 return GestureDetector(
                    behavior: HitTestBehavior.translucent,
                    child: Text("測試${index}"),
                    onTap: () {},
                  );
複製程式碼

設定HitTestBehavior

enum HitTestBehavior {
  /// Targets that defer to their children receive events within their bounds
  /// only if one of their children is hit by the hit test.
  deferToChild, //只生效在child的區域比如文字

  /// Opaque targets can be hit by hit tests, causing them to both receive
  /// events within their bounds and prevent targets visually behind them from
  /// also receiving events.
  opaque,//GestureDetector的整個區域,不包括它下面的區域

  /// Translucent targets both receive events within their bounds and permit
  /// targets visually behind them to also receive events.
  translucent,// GestureDetector的整個區域以及它下面的區域
}
複製程式碼

Flutter錯誤提示

Flutter中如果有錯誤,將會在控制檯當中顯示出錯誤資訊(雖然有時候資訊不能反映出準確的位置),你可以根據這個資訊來了解錯誤的原因和地方

I/flutter ( 9746): The following assertion was thrown building NotificationListener<ScrollNotification>: I/flutter ( 9746): A RenderViewport expected a child of type RenderSliver but received a child of type I/flutter ( 9746): RenderRepaintBoundary. I/flutter ( 9746): RenderObjects expect specific types of children because they coordinate with their children during I/flutter ( 9746): layout and paint. For example, a RenderSliver cannot be the child of a RenderBox because a I/flutter ( 9746): RenderSliver does not understand the RenderBox layout protocol.

E/flutter ( 9746): #6 runApp (package:flutter/src/widgets/binding.dart:756:7) E/flutter ( 9746): #7 main (package:flutter_app123123213/main.dart:3:16)

上面錯誤是我嘗試將ListView(非Sliver元件)放進CustomScrollView中,上面是錯誤資訊,下面的是錯誤發生在我寫的程式碼的哪裡。

這個東西沒別的方法,多被坑幾次就會好了。。

Flutter 萌新高頻問題(加班猿媽媽叫你回家吃飯了)

鍵盤擋住頁面了

請使用一些能滾動的元件包住你的頁面。比如SingleChildScrolView,

Appbar/Tabbar/StatusBar的高度

Appbar kToolbarHeight 這個是一個系統的Const可以直接獲得

Flutter 萌新高頻問題(加班猿媽媽叫你回家吃飯了)

Tabbar 可以用tabbar.preferredSize獲取 如果你看原始碼。其實它也還是一個Const 多看原始碼吧。。

StatusBar

  final double statusBarHeight = MediaQuery.of(context).padding.top;
複製程式碼

處理安卓/IOS系統中文字縮放對Flutter文字的影響以及根據App的文字大小設定某個頁面的文字大小

獲取MediaQuery並且對它的textScaleFactor進行重定義 下面是實現

  import 'dart:math' as math;

import 'package:flutter/material.dart';

class NoScaleTextWidget extends StatelessWidget {
  final Widget child;

  const NoScaleTextWidget({
    Key key,
    @required this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaxScaleTextWidget(
      max: 1.0,
      child: child,
    );
  }
}

class MaxScaleTextWidget extends StatelessWidget {
  final double max;
  final Widget child;

  const MaxScaleTextWidget({
    Key key,
    this.max = 1.2,
    @required this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var data = MediaQuery.of(context);
    var scale = math.min(max, data.textScaleFactor);
    return MediaQuery(
      data: data.copyWith(textScaleFactor: scale),
      child: child,
    );
  }
}

class ScaleTextWidget extends StatelessWidget {
  final double scale;

  final Widget child;

  const ScaleTextWidget({
    Key key,
    @required this.scale,
    @required this.child,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    var data = MediaQuery.of(context);
    var scale = this.scale ?? data.textScaleFactor;
    return MediaQuery(
      data: data.copyWith(textScaleFactor: scale),
      child: child,
    );
  }
}
複製程式碼

使用方式如下,當然你也使用這個來實現對某個頁面字型大小縮放的功能(比如app裡面的有調整字型大小)

return MaterialApp(
    builder: (c, w) {
      //不應用系統的字型縮放
      return NoScaleTextWidget(
        child: w,
      );
    },
    home: child,
  );
複製程式碼

好用的圖片,支援網路快取,縮放,拖拽,剪下,自定義Loading/Failed 效果,圓角,邊框等效果

extended_image 相關文章

好用的富文字庫,支援圖片,自定義背景效果,自定義文字溢位效果

extended text 相關文章

最後放上 Flutter_Candies,如果你覺得有什麼問題也是常常被萌新問到的,請告訴我,我會增加到彙總當中.

相關文章