前端學習-flutter學習-009-文字及樣式

ayubene發表於2024-07-14

《Flutter實戰·第二版》

Text

  • TextAlign:left right center 注意點:對齊的參考系是Text widget 本身,如果文字不夠長,設定看起來是沒有生效的;文字長才看得到,字串內容超過一行,Text 寬度等於螢幕寬度,第二行文字便會居中顯示。
  • maxLines、overflow:指定文字顯示的最大行數,預設情況下,文字是自動折行的,如果指定此引數,則文字最多不會超過指定的行。此處截斷方式TextOverflow.ellipsis,它會將多餘文字截斷後以省略符“...”表示;
  • textScaler:字型大小,TextScaler.linear(1.5);TextScaler.noScaling則是:禁止部分文字隨系統字型大小縮放
const Text("Hello worldaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
   textAlign: TextAlign.right,
),
Text("Hello world! I'm Jack. "*4,
  maxLines: 1,
  overflow: TextOverflow.ellipsis,
),
const Text("Hello world",
  // textScaler: TextScaler.noScaling,
  textScaler: TextScaler.linear(1.5),
),

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

// import 'package:flutter/cupertino.dart';
// void main() {
//   runApp(const MyApp());
// }

import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;



void main() => runApp(const MyApp());
// void main() => runApp(CupertinoApp(home: CupertinoTestRoute()));

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      initialRoute:"/", //名為"/"的路由作為應用的home(首頁)
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      routes:{
        "new_page":(context) => TipRoute(text:'這個引數是配置路由傳過來的'),
        "/":(context) => RouterTestRoute(), //註冊首頁路由
      },
    );
  }
}

class TipRoute extends StatelessWidget {
  TipRoute({
    Key? key,
    required this.text,  // 接收一個text引數
  }) : super(key: key);
  final String text;

  // Future<String> loadAsset() async {
  //   return await rootBundle.loadString('assets/my_icon.png');
  // }
  @override
  Widget build(BuildContext context) {
    //獲取路由引數
    var args=ModalRoute.of(context)?.settings.arguments;
    print('舊頁面傳遞引數的方法2:arguments:$args');
    return Scaffold(
      appBar: AppBar(
        title: Text("提示"),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Center(
          child: Column(
            children: <Widget>[
              Text(text),
              ElevatedButton(
                onPressed: () => Navigator.pop(context, "這個資料是新頁面傳遞給舊頁面的"),
                child: Text("返回"),
              ),
              // AssetImage(loadAsset())
              // Image.asset('assets/my_icon.png'),
            ],
          ),
        ),
      ),
    );
  }
}


// flutter run -d chrome --web-renderer canvaskit
class RouterTestRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("初始頁面"),
      ),
      body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ElevatedButton(
              onPressed: () async {
                // 開啟`TipRoute`,並等待返回結果
                // var result = await Navigator.push(
                //   context,
                //   MaterialPageRoute(
                //     builder: (context) {
                //       return TipRoute(
                //         // 路由引數
                //         text: "這個資料是舊頁面傳遞給新頁面的",
                //       );
                //     },
                //   ),
                // );
                var result = await Navigator.pushNamed(context, "new_page",  arguments: "hi");
                //輸出`TipRoute`路由返回結果
                print("路由返回值: $result");
              },
              child: Text("開啟提示頁"),
            ),
            RandomWordsWidget(),
            const Text("Hello world",
               textAlign: TextAlign.right,
            ),
            Text("Hello world! I'm Jack. "*4,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
            ),
            const Text("Hello world",
              // textScaler: TextScaler.noScaling,
              textScaler: TextScaler.linear(1.5),
            ),
          ],
        ),
    );


  }
}

class RandomWordsWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 生成隨機字串
    final wordPair = WordPair.random();
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Text('這是隨機的英文字串:' + wordPair.toString()),
    );
  }
}

TextStyle

  • height:該屬性用於指定行高,但它並不是一個絕對值,而是一個因子,具體的行高等於fontSize*height。
  • fontFamily :由於不同平臺預設支援的字型集不同,所以在手動指定字型時一定要先在不同平臺測試一下。
  • fontSize:該屬性和 Text 的textScaler都用於控制字型大小。但是有兩個主要區別:
    • fontSize可以精確指定字型大小,而textScaler只能透過縮放比例來控制。
    • textScaler主要是用於系統字型大小設定改變時對 Flutter 應用字型進行全域性調整,而fontSize通常用於單個文字,字型大小不會跟隨系統字型大小變化
import 'package:flutter/material.dart';
import 'package:english_words/english_words.dart';

// import 'package:flutter/cupertino.dart';
// void main() {
//   runApp(const MyApp());
// }

import 'dart:async' show Future;
import 'package:flutter/services.dart' show rootBundle;



void main() => runApp(const MyApp());
// void main() => runApp(CupertinoApp(home: CupertinoTestRoute()));

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  // This widget is the root of your application.
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      initialRoute:"/", //名為"/"的路由作為應用的home(首頁)
      theme: ThemeData(
        colorScheme: ColorScheme.fromSeed(seedColor: Colors.blue),
        useMaterial3: true,
      ),
      routes:{
        "new_page":(context) => TipRoute(text:'這個引數是配置路由傳過來的'),
        "/":(context) => RouterTestRoute(), //註冊首頁路由
      },
    );
  }
}

class TipRoute extends StatelessWidget {
  TipRoute({
    Key? key,
    required this.text,  // 接收一個text引數
  }) : super(key: key);
  final String text;

  // Future<String> loadAsset() async {
  //   return await rootBundle.loadString('assets/my_icon.png');
  // }
  @override
  Widget build(BuildContext context) {
    //獲取路由引數
    var args=ModalRoute.of(context)?.settings.arguments;
    print('舊頁面傳遞引數的方法2:arguments:$args');
    return Scaffold(
      appBar: AppBar(
        title: Text("提示"),
      ),
      body: Padding(
        padding: EdgeInsets.all(18),
        child: Center(
          child: Column(
            children: <Widget>[
              Text(text),
              ElevatedButton(
                onPressed: () => Navigator.pop(context, "這個資料是新頁面傳遞給舊頁面的"),
                child: Text("返回"),
              ),
              // AssetImage(loadAsset())
              // Image.asset('assets/my_icon.png'),
            ],
          ),
        ),
      ),
    );
  }
}


// flutter run -d chrome --web-renderer canvaskit
class RouterTestRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("初始頁面"),
      ),
      body: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ElevatedButton(
              onPressed: () async {
                // 開啟`TipRoute`,並等待返回結果
                // var result = await Navigator.push(
                //   context,
                //   MaterialPageRoute(
                //     builder: (context) {
                //       return TipRoute(
                //         // 路由引數
                //         text: "這個資料是舊頁面傳遞給新頁面的",
                //       );
                //     },
                //   ),
                // );
                var result = await Navigator.pushNamed(context, "new_page",  arguments: "hi");
                //輸出`TipRoute`路由返回結果
                print("路由返回值: $result");
              },
              child: Text("開啟提示頁"),
            ),
            RandomWordsWidget(),
            Text("Hello worldaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
               textAlign: TextAlign.right,
                style: TextStyle(
                    color: Colors.blue,
                    fontSize: 18.0,
                    height: 1.2,
                    fontFamily: "Courier",
                    background: Paint()..color=Colors.yellow,
                    decoration:TextDecoration.underline,
                    decorationStyle: TextDecorationStyle.dashed
                ),
            ),
            // Text("Hello world! I'm Jack. "*4,
            //   maxLines: 1,
            //   overflow: TextOverflow.ellipsis,
            // ),
            // const Text("Hello world",
            //   // textScaler: TextScaler.noScaling,
            //   textScaler: TextScaler.linear(1.5),
            // ),
          ],
        ),
    );


  }
}

class RandomWordsWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // 生成隨機字串
    final wordPair = WordPair.random();
    return Padding(
      padding: const EdgeInsets.all(8.0),
      child: Text('這是隨機的英文字串:' + wordPair.toString()),
    );
  }
}

TextSpan

透過 TextSpan 實現了一個基礎文字片段和一個連結片段,然後透過Text.rich 方法將TextSpan 新增到 Text 中, Text 其實就是 RichText 的一個包裝,而RichText 是可以顯示多種樣式(富文字)的 widget。

Text.rich(TextSpan(
  children: [
    TextSpan(
      text: 'home:'
    ),
    TextSpan(
      text: 'https://aaa.bbb.com',
      style: TextStyle(
        color: Colors.blue,
        fontSize: 20,
      ),
        // recognizer: _tapRecognizer
    )
  ]
))

DefaultTextStyle

如果使用DefaultTextStyle在 Widget 樹的某一個節點處設定一個預設的文字樣式,那麼該節點的子樹中所有文字都會預設使用這個樣式,不使用的話要inherit: false;不過我試了只要子樹設定了style 不寫inherit: false也沒事

class RouterTestRoute extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("初始頁面"),
      ),
      body: DefaultTextStyle(
        style: const TextStyle(
          color:Colors.red,
          fontSize: 20.0,
        ),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            ElevatedButton(
              onPressed: () async {
                // 開啟`TipRoute`,並等待返回結果
                // var result = await Navigator.push(
                //   context,
                //   MaterialPageRoute(
                //     builder: (context) {
                //       return TipRoute(
                //         // 路由引數
                //         text: "這個資料是舊頁面傳遞給新頁面的",
                //       );
                //     },
                //   ),
                // );
                var result = await Navigator.pushNamed(context, "new_page",  arguments: "hi");
                //輸出`TipRoute`路由返回結果
                print("路由返回值: $result");
              },
              child: Text("開啟提示頁"),
            ),
            RandomWordsWidget(),
            Text("Hello worldaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
              textAlign: TextAlign.right,
              // style: TextStyle(
              //     color: Colors.blue,
              //     fontSize: 18.0,
              //     height: 1.2,
              //     fontFamily: "Courier",
              //     background: Paint()..color=Colors.yellow,
              //     decoration:TextDecoration.underline,
              //     decorationStyle: TextDecorationStyle.dashed
              // ),
            ),
            Text('這句話不繼承預設樣式',
              style: TextStyle(
                inherit: false,
                color: Colors.green,
                fontSize: 20,
              ),
            )
            // Text.rich(TextSpan(
            //     children: [
            //       TextSpan(
            //           text: 'home:'
            //       ),
            //       TextSpan(
            //         text: 'https://aaa.bbb.com',
            //         style: TextStyle(
            //           color: Colors.blue,
            //           fontSize: 20,
            //         ),
            //         // recognizer: _tapRecognizer
            //       )
            //     ]
            // ))
            // Text("Hello world! I'm Jack. "*4,
            //   maxLines: 1,
            //   overflow: TextOverflow.ellipsis,
            // ),
            // const Text("Hello world",
            //   // textScaler: TextScaler.noScaling,
            //   textScaler: TextScaler.linear(1.5),
            // ),
          ],
        ),
      )
    );


  }
}

字型

可以在 Flutter 應用程式中使用不同的字型
在 Flutter 中使用字型分兩步完成。首先在pubspec.yaml中宣告它們,以確保它們會打包到應用程式中。然後透過TextStyle (opens new window)屬性使用字型。
在pubspec.yaml中宣告

flutter:

  # The following line ensures that the Material Icons font is
  # included with your application, so that you can use the icons in
  # the material Icons class.
  uses-material-design: true

  fonts:
    - family: Raleway
      fonts:
        - asset: lib/assets/fonts/Raleway/Raleway-LightItalic.ttf
          weight: 300
          style: italic
    - family: MiaoZi
      fonts:
        - asset: lib/assets/fonts/MiaoZi-YunYingTi-2.ttf

使用:

Text('這句話使用了喵喵字型',
  style: TextStyle(
    inherit: false,
    fontFamily: 'MiaoZi',
    color: Colors.blue,
    fontSize: 30,
    // fontWeight: FontWeight.w300,
    // fontStyle: FontStyle.italic,
  ),

不太會用的話可以看看這個影片

相關文章