Tag: dart

  • [Mobile – Flutter] Slider trong Flutter

    [Mobile – Flutter] Slider trong Flutter

    Bản thân Flutter là một framework khá hoàn thiện đến mức việc tạo giao diện với Flutter trở nên dễ dàng và nhanh chóng đến mức bất ngờ! Điều này khiến lập trình viên Flutter cảm thấy việc lập trình mobile quá dễ (trừ khi họ là người đã từng nếm trái đắng từ khi code native). Mình cũng thấy dễ cho đến khi nhìn thấy giao diện ứa nước mắt mà designer gửi (đôi khi là kèm theo video animation siêu xịn…).

    Thế bạn đã trang bị cho mình gì để ứng phó trước những design đẹp (hoặc k) nào? Bạn đã biết custom Slider trong Flutter chưa? Hay chỉ là những bé slider cũ mèn như này này này:

    mặc định
    range slider
    cupertino *hình ảnh chụp từ video youtube nên hơi mờ

    Nhưng khi nhận được design thì trông như này

    như này nè
    rồi như này
    trông cũng dễ?

    Chắc ai nhận design cũng sẽ nghĩ: trông dễ phết, khó thì dùng thư viện (nhiều thư viện Slider quá mà). Có thể kể ra một số thư viện cho ai muốn dùng nè:

    Đọc đến đây thì ai thích dùng thư viện có thể dừng lại và tham khảo 3 thư viện này. Đôi khi một số lại thấy thư viện thì quá là nặng thêm nhiều thứ lắt nhắt, rồi cho customize đủ thứ mà cái mình cần thì không có? Hoặc bạn muốn tự mình thử sức làm những slider này, thì tiếp tục đọc cách custom slider nào :3

    Đầu tiên, chúng ta sẽ tìm hiểu về các thành phần của 1 slider và tên gọi của nó trong Flutter với thiết kế theo Material: (đoạn này cop trên document lười dịch nên nhờ bạn đọc tạm nhé)

    • The “thumb”, which is a shape that slides horizontally when the user drags it.
    • The “track”, which is the line that the slider thumb slides along.
    • The “value indicator”, which is a shape that pops up when the user is dragging the thumb to indicate the value being selected.
    • The “active” side of the slider is the side between the thumb and the minimum value.
    • The “inactive” side of the slider is the side between the thumb and the maximum value.
    • The “tick marks”, which are regularly spaced marks that are drawn when using discrete divisions.
    • The “value indicator”, which appears when the user is dragging the thumb to indicate the value being selected.
    • The “overlay”, which appears around the thumb, and is shown when the thumb is pressed, focused, or hovered. It is painted underneath the thumb, so it must extend beyond the bounds of the thumb itself to actually be visible.

    Để thiết kế ra một Slider thì đầu tiên chúng ta sẽ xem đến các widget trực tiếp để tạo ra slider: Slider, RangeSlider, and CupertinoSlider(Flutter Widget of the Week) – YouTube. Tuy nhiên khi xem document (ờ lại là document, document của Flutter là tài liệu hữu ích nhất mà dev Flutter có thể tìm được bên cạnh source code open của nó) thì bạn phát hiện ra nó không có nhiều thứ liên quan đến giao diện cho lắm, ngoài việc cho phép đổi tí màu. Bạn bắt đầu tuyệt vọng.

    một constructor của slider
    có gì đó

    và rồi cuối document, họ bảo, vẻ bề ngoài của nó thì dùng SliderThemeData từ widget SliderTheme hoặc một cái theme nào đó cha ông của nó mà có định nghĩa sliderTheme. Yeah XD

    Bạn tiếp tục đi đến wiki của SliderThemeData xem tùy chỉnh được gì, ở đây nhé SliderThemeData class – material library – Dart API (flutter.dev). Có thể chỉnh được kha khá, hình tròn hình chữ nhật, bo góc (hoặc k), … bạn có thể dừng lại, đọc, và thử xem bạn có thể custom như nào (ảnh phía trên là 1 slider đã được 1 tác giả khác tạo ra nhờ tùy chỉnh các thuộc tính này).

    Để rồi nhận ra rằng: nó không giống mấy cái design nhận được xíu nào 🙁

    hình ảnh slider trong blog cuối bài

    Thế làm sao để custom chúng nó như này? Hãy xem Flutter Team đã tạo ra Slider như nào đã nhé :3

    ồ là một file hơn 3000 dòng code và rất nhiều tác giả

    Họ đã tạo ra RoundedRectSliderTrackShape, RoundSliderThumbShape, PaddleSliderValueIndicatorShape, PaddleSliderValueIndicatorShape, RoundSliderTickMarkShape,… và document cũng nói là:

    The thumb, track, tick marks, value indicator, and overlay can be customized by creating subclasses of SliderTrackShapeSliderComponentShape, and/or SliderTickMarkShape. See RoundSliderThumbShapeRectangularSliderTrackShapeRoundSliderTickMarkShapeRectangularSliderValueIndicatorShape, and RoundSliderOverlayShape for examples.

    Document

    Nên cứ nghe theo thôi ha, họ bảo code mẫu rồi đấy, muốn custom thì xem mà học :3 họ bảo kế thừa mấy cái có sẵn này đi mà custom, nhưng custom sao thì họ không nói 🙁 nên t ở đây để giúp bạn đây hehe. Không dài dòng nữa, bắt đầu thôi :3

    Khi bạn extend các lớp kể ở trên, bạn sẽ được trình gợi ý yêu cầu override hàm paint, đây là hàm để vẽ nên chúng nó. Trong hàm paint có một số thứ bạn cần chú ý:
    – Đầu tiên là PaintingContext context, ở đây bạn sẽ lấy được canvas ra và vẽ những gì bạn cần (context.canvas)
    – Tiếp theo là center với Thumb và parentBox với Track, bạn sẽ tìm được những điểm hữu dụng để vẽ
    – Tiếp theo là sliderTheme, từ đó bạn có thể lấy ra các thuộc tính khác mà bạn có thể truyền vào theme của slider (màu active, inactive…)
    – Cuối cùng, mn luôn luôn có thể tham khảo code open của Flutter xem họ làm như nào với các shape mặc định, hoặc tham khảo code của mình sau đây :3

    Đây là code để tạo ra chiếc slider này

    Chụp từ màn hình điện thoại
    import 'package:flutter/material.dart';
    
    class CustomSlider extends StatelessWidget {
      final double max, min, value;
      final void Function(double) onValueChange;
    
      const CustomSlider({
        required this.min,
        required this.max,
        required this.value,
        required this.onValueChange,
        Key? key,
      }) : super(key: key);
    
      @override
      Widget build(BuildContext context) {
        return Container(
          decoration: BoxDecoration(
            border: Border.all(color: Colors.grey),
            borderRadius: BorderRadius.circular(10),
          ),
          padding: const EdgeInsets.fromLTRB(4, 16, 4, 16),
          child: Row(
            children: [
              Text(min.toInt().toString()),
              const SizedBox(width: 6),
              Expanded(
                child: SliderTheme(
                  data: SliderTheme.of(context).copyWith(
                    trackHeight: 14.0,
                    trackShape: CustomTrackShape(),
                    activeTrackColor: const Color(0xFF219653),
                    inactiveTrackColor: const Color(0xFFF1E1E1),
                    thumbShape: CustomSliderMarkShape(sliderValue: value, tickMarkRadius: 16),
                    thumbColor: const Color(0xFF219653),
                    // overlayColor: Color(0xFF219653).withOpacity(0.5),
                    // overlayShape: RoundSliderOverlayShape(overlayRadius: 24),
                    overlayShape: SliderComponentShape.noOverlay,
                    showValueIndicator: ShowValueIndicator.always,
                    valueIndicatorShape: const RectangularSliderValueIndicatorShape(),
                    valueIndicatorColor: Colors.black,
                    valueIndicatorTextStyle: const TextStyle(
                      color: Colors.white,
                      fontSize: 16.0,
                    ),
                  ),
                  child: Slider(
                    min: min,
                    max: max,
                    value: value,
                    label: '${value.round()}',
                    onChanged: onValueChange,
                  ),
                ),
              ),
              const SizedBox(width: 6),
              Text(max.toInt().toString()),
            ],
          ),
        );
      }
    }
    
    class CustomSliderMarkShape extends SliderComponentShape {
      final double tickMarkRadius;
      final double sliderValue;
    
      CustomSliderMarkShape({
        required this.tickMarkRadius,
        required this.sliderValue,
      });
    
      @override
      Size getPreferredSize(bool isEnabled, bool isDiscrete) {
        return Size(tickMarkRadius, tickMarkRadius);
      }
    
      @override
      void paint(
        PaintingContext context,
        Offset center, {
        required Animation<double> activationAnimation,
        required Animation<double> enableAnimation,
        required bool isDiscrete,
        required TextPainter labelPainter,
        required RenderBox parentBox,
        required SliderThemeData sliderTheme,
        required TextDirection textDirection,
        required double value,
        required double textScaleFactor,
        required Size sizeWithOverflow,
      }) {
        final Canvas canvas = context.canvas;
    
        canvas.drawRRect(
          RRect.fromRectAndRadius(
            Rect.fromCenter(center: center, width: 36, height: 24), const Radius.circular(16)),
          Paint()..color = Colors.white,
        );
    
        canvas.drawRRect(
          RRect.fromRectAndRadius(
            Rect.fromCenter(center: center, width: 36, height: 24), const Radius.circular(16)),
          Paint()..color = Colors.black
            ..style = PaintingStyle.stroke
            ..strokeWidth = 2,
        );
    
        TextSpan span = TextSpan(
          style: TextStyle(
            fontSize: tickMarkRadius * 0.9,
            fontWeight: FontWeight.w700,
            color: Colors.black
          ),
          text: sliderValue.round().toString(),
        );
    
        TextPainter tp = TextPainter(
          text: span,
          textAlign: TextAlign.center,
          textDirection: TextDirection.ltr,
        );
    
        tp.layout();
    
        Offset textCenter = Offset(
          center.dx - (tp.width / 2),
          center.dy - (tp.height / 2),
        );
        tp.paint(canvas, textCenter);
      }
    }
    
    class CustomTrackShape extends RoundedRectSliderTrackShape {
      @override
      Rect getPreferredRect({
        required RenderBox parentBox,
        Offset offset = Offset.zero,
        required SliderThemeData sliderTheme,
        bool isEnabled = false,
        bool isDiscrete = false,
      }) {
        final double trackHeight = sliderTheme.trackHeight ?? 8;
        final double trackLeft = offset.dx;
        final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
        final double trackWidth = parentBox.size.width;
        return Rect.fromLTWH(trackLeft, trackTop, trackWidth, trackHeight);
      }
    }
    // sử dụng
    CustomSlider(
      max: 100,
      min: 10,
      onValueChange: (_) {  },
      value: 30,
    ),


    Mình đã custom cái slider này từ rất lâu rồi (nên code của nó mình không chắc là ổn lắm).

    Và lí do mình viết bài này chủ yếu để nhớ kĩ hơn và muốn chia sẻ với mọi người khi mà chiều nay mình đã custom ra mấy cái extend SliderComponentShape, rồi ghép vào SliderTheme mà reload restart hoài UI không nhận :'( Mình rất bối rối muốn ném máy ra cửa sổ thì nhận ra nếu là RangeSlider thì cần extend RangeSliderTrackShape, RangeSliderThumbShape… (thêm Range cơ). Hóa ra do mình không đọc kĩ (tiện muốn kể chuyện InteractiveViewer ghê mà ai muốn nghe ib nhé :v)

    range slider sau khi custom
    import 'dart:math';
    
    import 'package:flutter/material.dart';
    import 'dart:ui' as ui;
    
    class CustomRangeSliderTrack extends RangeSliderTrackShape {
      const CustomRangeSliderTrack();
    
      @override
      Rect getPreferredRect({
        required RenderBox parentBox,
        Offset offset = Offset.zero,
        required SliderThemeData sliderTheme,
        bool isEnabled = false,
        bool isDiscrete = false,
      }) {
        final double overlayWidth = sliderTheme.overlayShape!.getPreferredSize(isEnabled, isDiscrete).width;
        final double trackHeight = sliderTheme.trackHeight!;
    
        final double trackLeft = offset.dx + overlayWidth / 2;
        final double trackTop = offset.dy + (parentBox.size.height - trackHeight) / 2;
        final double trackRight = trackLeft + parentBox.size.width - overlayWidth;
        final double trackBottom = trackTop + trackHeight;
        // If the parentBox'size less than slider's size the trackRight will be less than trackLeft, so switch them.
        return Rect.fromLTRB(min(trackLeft, trackRight), trackTop, max(trackLeft, trackRight), trackBottom);
      }
    
      @override
      void paint(
        PaintingContext context,
        Offset offset, {
        required RenderBox parentBox,
        required SliderThemeData sliderTheme,
        required Animation<double> enableAnimation,
        required Offset startThumbCenter,
        required Offset endThumbCenter,
        bool isEnabled = false,
        bool isDiscrete = false,
        required TextDirection textDirection,
        double additionalActiveTrackHeight = 2,
      }) {
        final ColorTween inactiveTrackColorTween = ColorTween(
          begin: sliderTheme.disabledInactiveTrackColor,
          end: sliderTheme.inactiveTrackColor,
        );
    
        final Rect trackRect = getPreferredRect(
          parentBox: parentBox,
          offset: offset,
          sliderTheme: sliderTheme,
          isEnabled: isEnabled,
          isDiscrete: isDiscrete,
        );
    
        final Paint activePaint = Paint()
          ..shader = ui.Gradient.linear(
            Offset(0, trackRect.top),
            Offset(0, trackRect.bottom),
            [
              Color(0xFF4BC65E),
              Color(0xFF379A46),
            ],
          );
        final Paint inactivePaint = Paint()
          ..color = inactiveTrackColorTween.evaluate(enableAnimation)!;
        final Size thumbSize = sliderTheme.rangeThumbShape!.getPreferredSize(isEnabled, isDiscrete);
        final double thumbRadius = thumbSize.width / 2;
        assert(thumbRadius > 0);
    
        final Radius trackRadius = Radius.circular(trackRect.height / 2);
    
        context.canvas.drawRRect(
          RRect.fromLTRBAndCorners(
            trackRect.left,
            trackRect.top,
            startThumbCenter.dx,
            trackRect.bottom,
            topLeft: trackRadius,
            bottomLeft: trackRadius,
          ),
          inactivePaint,
        );
        context.canvas.drawRect(
          Rect.fromLTRB(
            startThumbCenter.dx,
            trackRect.top - (additionalActiveTrackHeight / 2),
            endThumbCenter.dx,
            trackRect.bottom + (additionalActiveTrackHeight / 2),
          ),
          activePaint,
        );
        context.canvas.drawRRect(
          RRect.fromLTRBAndCorners(
            endThumbCenter.dx,
            trackRect.top,
            trackRect.right,
            trackRect.bottom,
            topRight: trackRadius,
            bottomRight: trackRadius,
          ),
          inactivePaint,
        );
      }
    }
    
    class CustomRangeSliderThumb extends RangeSliderThumbShape {
      const CustomRangeSliderThumb();
      
      @override
      Size getPreferredSize(bool isEnabled, bool isDiscrete) {
        return Size.fromRadius(20);
      }
      
      @override
      void paint(PaintingContext context,
        Offset center, {
        required Animation<double> activationAnimation, 
        required Animation<double> enableAnimation, 
        bool isDiscrete = false,
        bool isEnabled = false,
        bool? isOnTop,
        required SliderThemeData sliderTheme,
        TextDirection? textDirection,
        Thumb? thumb,
        bool? isPressed,
      }) {
        final Canvas canvas = context.canvas;
        final outerPaint = Paint()
          ..style = PaintingStyle.fill
          ..shader = ui.Gradient.linear(
            Offset(0, 0),
            Offset(0, 30),
            [
              Color(0xFF4BC65E),
              Color(0xFF379A46),
            ],
          );
        canvas.drawCircle(center, 10, outerPaint);
        canvas.drawCircle(center, 5, Paint()..color = Colors.white);
      }
    }
    // dùng như này để có 1 range slider như ý
    // có thể custom thêm gì đó tùy ý nha
    SliderTheme(
      data: SliderThemeData(
        trackHeight: 4,
        rangeTrackShape: CustomRangeSliderTrack(),
        rangeThumbShape: CustomRangeSliderThumb(),
      ),
      child: RangeSlider(
        values: priceRange,
        min: minPrice,
        max: maxPrice,
        onChanged: (value) {
          setState(() {
            priceRange = value;
          });
        },
      ),
    ),

    Tham khảo: Flutter Slider widgets: A deep dive with examples – LogRocket Blog

  • KIẾN THỨC CƠ BẢN VỀ DART (PHẦN 4)

    KIẾN THỨC CƠ BẢN VỀ DART (PHẦN 4)

    Collections

    Bộ sưu tập rất hữu ích để nhóm dữ liệu liên quan. Dart bao gồm một số loại bộ sưu tập khác nhau, nhưng hướng dẫn này sẽ bao gồm hai loại phổ biến nhất: List và Map.

    Lists

    Lists trong Dart tương tự như arrays trong các ngôn ngữ khác. Bạn sử dụng chúng để duy trì một danh sách các giá trị có thứ tự. Danh sách dựa trên 0, vì vậy mục đầu tiên trong danh sách ở chỉ mục 0:

    Dưới đây là danh sách các món tráng miệng khác nhau:

    List desserts = ['cookies', 'cupcakes', 'donuts', 'pie'];

    Bạn đặt các phần tử của danh sách trong dấu ngoặc vuông [ ] . Bạn sử dụng dấu phẩy để phân tách các phần tử.

    Ở đầu dòng, bạn có thể thấy rằng loại là List. Bạn sẽ nhận thấy không có loại nào được bao gồm. Dart suy luận rằng danh sách có loại List

    Đây là danh sách các số nguyên:

    final numbers = [42, -1, 299792458, 100];

    Nhập numbers vào DartPad và bạn sẽ thấy rằng Dart nhận dạng loại List của int.

    Làm việc với các phần tử trong List

    Để truy cập các phần tử của danh sách, hãy sử dụng ký hiệu chỉ số con bằng cách đặt số chỉ mục giữa dấu ngoặc vuông sau tên biến danh sách. Ví dụ:

    final firstDessert = desserts[0];
    print(firstDessert); // cookies

    Vì chỉ số danh sách dựa trên số không, desserts[0]là phần tử đầu tiên của danh sách.

    Thêm và xóa các phần tử với add và remove tương ứng:

    desserts.add('cake');
    print(desserts); 
    // [cookies, cupcakes, donuts, pie, cake]
    
    desserts.remove('donuts');
    print(desserts); 
    // [cookies, cupcakes, pie, cake]

    Chạy mã để xem kết quả.

    Trước đó, bạn đã học về forvòng lặp. for-inVòng lặp của Dart hoạt động đặc biệt tốt với các danh sách. Hãy thử nó:

    for (final dessert in desserts) {
      print('I love to eat $dessert.');
    }
    // I love to eat cookies.
    // I love to eat cupcakes.
    // I love to eat pie.
    // I love to eat cake.

    Bạn không cần sử dụng chỉ mục. Dart chỉ lặp qua mọi phần tử của dessertsvà gán nó mỗi lần cho một biến có tên dessert.

    Maps

    Khi bạn muốn một danh sách các giá trị được ghép nối, Map là một lựa chọn tốt. Dart Map tương tự như dictionaries  trong Swift và maps trong Kotlin.

    Đây là một ví dụ về map trong Dart:

    Map<String, int> calories = {
      'cake': 500,
      'donuts': 150,
      'cookies': 100,
    };

    Bạn bao quanh Maps bằng dấu ngoặc nhọn { }. Sử dụng dấu phẩy để phân tách các phần tử của bản đồ.

    Các phần tử của bản đồ được gọi là cặp khóa-giá trị , trong đó khóa ở bên trái dấu hai chấm và giá trị ở bên phải.

    Bạn tìm thấy một giá trị bằng cách sử dụng khóa để tra cứu nó, như sau:

    final donutCalories = calories['donuts'];
    print(donutCalories); // 150

    Từ khóa 'donuts'nằm trong dấu ngoặc vuông sau tên bản đồ. Trong trường hợp này, nó ánh xạ tới một giá trị 150.

    Nhập donutCalories vào DartPad và bạn sẽ thấy rằng kiểu được suy luận thì int? đúng hơn int. Đó là bởi vì, nếu một bản đồ không chứa khóa mà bạn đang tìm kiếm, nó sẽ trả về một giá trị null.

    Thêm một phần tử mới vào bản đồ bằng cách chỉ định khóa và gán cho nó một giá trị:

    calories['brownieFudgeSundae'] = 1346;
    print(calories);
    // {cake: 500, donuts: 150, cookies: 100, brownieFudgeSundae: 1346}

    Chạy mã đó và bạn sẽ thấy bản đồ được in ở định dạng ngang với món tráng miệng mới của bạn ở cuối.

    Functions

    Các hàm cho phép bạn đóng gói nhiều dòng mã liên quan vào một nội dung duy nhất. Sau đó, bạn triệu hồi hàm để tránh lặp lại những dòng mã đó trong ứng dụng Dart của mình.

    Một hàm bao gồm các phần tử sau:

    • Kiểu trả về
    • Tên chức năng
    • Danh sách tham số trong ngoặc đơn
    • Nội dung hàm được đặt trong dấu ngoặc

    Defining Functions

    Đoạn mã bạn đang chuyển thành một hàm nằm trong dấu ngoặc nhọn. Khi bạn gọi hàm, bạn truyền vào các đối số phù hợp với loại tham số của hàm.

    Tiếp theo, bạn sẽ viết một hàm mới trong DartPad sẽ kiểm tra xem một chuỗi đã cho có phải là Banana hay không :

    bool isBanana ( String fruit) {
       return fruit == 'banana' ; 
    }

    Hàm sử dụng return để trả về kiểu bool. Đối số bạn truyền vào hàm sẽ xác định bool.

    Hàm này sẽ luôn trả về cùng một kiểu giá trị cho bất kỳ đầu vào nhất định nào. Nếu một hàm không cần trả về giá trị, bạn có thể đặt kiểu trả về void.  main làm điều này, chẳng hạn.

    Làm việc với các Function

    Bạn có thể gọi hàm bằng cách truyền vào một chuỗi. Sau đó, bạn có thể chuyển kết quả của cuộc gọi đó tới print:

    void main() {
      var fruit = 'apple';
      print(isBanana(fruit)); // false
    }

    Các Function lồng vào nhau

    Thông thường, bạn xác định các hàm bên ngoài các hàm khác hoặc bên trong các lớp Dart. Tuy nhiên, bạn cũng có thể lồng các hàm Dart. Ví dụ, bạn có thể làm tổ isBanana bên trong main.

    void main() {
      bool isBanana(String fruit) {
        return fruit == 'banana';
      }
    
      var fruit = 'apple';
      print(isBanana(fruit)); // false
    }

    Bạn cũng có thể thay đổi đối số thành một hàm, sau đó gọi lại đối số đó bằng đối số mới:

    fruit = 'banana';
    print(isBanana(fruit));  // true

    Kết quả của việc gọi hàm phụ thuộc hoàn toàn vào các đối số bạn truyền vào.

    Optional Parameters

    Nếu một tham số cho một hàm là tùy chọn, bạn có thể bao quanh nó bằng dấu ngoặc vuông và đặt kiểu là vô hiệu:

    String fullName(String first, String last, [String? title]) {
      if (title == null) {
        return '$first $last';
      } else {
        return '$title $first $last';
      }
    }

    Trong chức năng này, title là tùy chọn. Nó sẽ mặc định thành null nếu bạn không chỉ định nó.

    Bây giờ, bạn có thể gọi hàm có hoặc không có tham số tùy chọn:

    print(fullName('Joe', 'Howard'));
    // Joe Howard
    
    print(fullName('Albert', 'Einstein', 'Professor'));
    // Professor Albert Einstein

    Named Parameters and Default Values

    Khi bạn có nhiều tham số, bạn có thể nhầm lẫn khi nhớ cái nào là cái nào. Dart giải quyết vấn đề này với các tham số được đặt tên , mà bạn nhận được bằng cách bao quanh danh sách tham số bằng dấu ngoặc nhọn { }.

    Các tham số này là tùy chọn theo mặc định, nhưng bạn có thể cung cấp cho chúng các giá trị mặc định hoặc yêu cầu chúng bằng cách sử dụng từ khóa required:

    bool withinTolerance({required int value, int min = 0, int max = 10}) {
      return min <= value && value <= max;
    }

    valuelà bắt buộc, trong khi minvà maxlà tùy chọn với các giá trị mặc định.

    Với các tham số được đặt tên, bạn có thể chuyển vào các đối số theo một thứ tự khác bằng cách cung cấp các tên tham số bằng dấu hai chấm:

    print(withinTolerance(value: 5)); // true

    Chạy mã của bạn để xem các chức năng mới của bạn đang hoạt động.

    Anonymous Functions

    Dart hỗ trợ first-class functions , nghĩa là nó xử lý các hàm giống như bất kỳ kiểu dữ liệu nào khác. Bạn có thể gán chúng cho các biến, chuyển chúng dưới dạng đối số và trả lại chúng từ các hàm khác.

    Để chuyển các hàm này xung quanh dưới dạng giá trị, hãy bỏ qua tên hàm và kiểu trả về. Vì không có tên nên loại hàm này được gọi là hàm ẩn danh .

    Bạn có thể gán một hàm ẩn danh cho một biến có tên onPressed như sau:

    final onPressed = () {
      print('button pressed');
    };

    onPressedcó giá trị kiểu Function. Các dấu ngoặc trống cho biết hàm không có tham số. Giống như các hàm thông thường, mã bên trong dấu ngoặc nhọn là phần thân của hàm.

    Để thực thi mã bên trong thân hàm, hãy gọi tên biến như thể nó là tên của hàm:

    onPressed(); // button pressed

    Bạn có thể đơn giản hóa các hàm có nội dung chỉ chứa một dòng duy nhất bằng cách sử dụng cú pháp mũi tên . Để thực hiện việc này, hãy xóa dấu ngoặc nhọn và thêm một mũi tên =>.

    Dưới đây là so sánh của hàm ẩn danh ở trên và phiên bản đã cấu trúc lại:

    // original anonymous function
    final onPressed = () {
      print('button pressed');
    };
    
    // refactored
    final onPressed = () => print('button pressed');

    Sử dụng Anonymous Functions

    Bạn sẽ thường thấy các hàm ẩn danh trong Flutter, giống như các hàm ở trên, được chuyển xung quanh dưới dạng lệnh gọi lại cho các sự kiện giao diện người dùng. Điều này cho phép bạn chỉ định mã chạy khi người dùng làm điều gì đó, chẳng hạn như nhấn một nút.

    Một nơi phổ biến khác mà bạn sẽ thấy các chức năng ẩn danh là với các collection. Bạn có thể cung cấp cho tập hợp một hàm ẩn danh sẽ thực hiện một số tác vụ trên mỗi phần tử của tập hợp. Ví dụ:

    // 1
    final drinks = ['water', 'juice', 'milk'];
    // 2
    final bigDrinks = drinks.map(
      // 3
      (drink) => drink.toUpperCase()
    );
    // 4
    print(bigDrinks); // (WATER, JUICE, MILK)

    Hãy xem xét từng bước:

    1. Xác định danh sách drinks có các chữ cái thường.
    2. .map nhận tất cả các giá trị danh sách và trả về một tập hợp mới với chúng.
    3. Một hàm ẩn danh được chuyển dưới dạng một tham số. Trong hàm ẩn danh đó, bạn có một drink đối số đại diện cho từng phần tử của danh sách.
    4. Phần thân của hàm ẩn danh chuyển đổi từng phần tử thành chữ hoa và trả về giá trị. Vì danh sách ban đầu là danh sách các chuỗi, nên drink cũng có kiểu String.

    Sử dụng một hàm ẩn danh và kết hợp nó với .maplà một cách thuận tiện để chuyển đổi một bộ sưu tập này thành một bộ sưu tập khác. Lưu ý : Đừng nhầm giữa .mapmethod với Maptype.

    Chạy mã để xem bộ sưu tập kết quả.

    Xin chúc mừng, bạn đã hoàn thành phần hướng dẫn. Bây giờ bạn sẽ hiểu rõ hơn về mã Dart mà bạn thấy khi học cách xây dựng ứng dụng Flutter!

  • KIẾN THỨC CƠ BẢN VỀ DART (PHẦN 3)

    KIẾN THỨC CƠ BẢN VỀ DART (PHẦN 3)

    Sang phần 3 này, chúng ta sẽ tìm hiểu về Control Flow.

    Control flow cho phép bạn ra lệnh khi nào thực thi, bỏ qua hoặc lặp lại một số dòng mã nhất định. Bạn sử dụng các điều kiện (conditionals ) và vòng lặp (loops ) để xử lý luồng điều khiển trong Dart.

    Trong phần này, bạn sẽ tìm hiểu thêm về:

    • Conditionals
    • While Loops
    • Continue and Break
    • For Loops

    Đây là những gì bạn cần biết về các phần tử luồng điều khiển trong Dart.

    Conditionals

    Hình thức cơ bản nhất của luồng điều khiển là quyết định thực thi hay bỏ qua các phần nhất định của mã của bạn, tùy thuộc vào các điều kiện xảy ra khi chương trình của bạn chạy.

    Cấu trúc ngôn ngữ để xử lý các điều kiện là câu lệnh ifelseifelse trong Dart trông gần giống với việc sử dụng nó trong các ngôn ngữ giống C khác.

    Câu lệnh If

    Giả sử bạn có một biến animal đó hiện là một con cáo. Nó trông như thế này:

    var animal = 'fox';
    

    Bạn có thể sử dụng một if câu lệnh để kiểm tra xem đó animal là mèo hay chó, sau đó chạy một số mã tương ứng.

    if (animal == 'cat' || animal == 'dog') {
      print('Animal is a house pet.');
    }

    Ở đây, bạn đã sử dụng các toán tử equality OR để tạo bool điều kiện bên trong cho if câu lệnh.

    Câu lệnh else

    Với một else mệnh đề, bạn có thể chạy mã thay thế nếu điều kiện sai:

    else {
      print('Animal is NOT a house pet.');
    }
    // Animal is NOT a house pet.

    Bạn cũng có thể kết hợp nhiều câu lệnh ifelse thành một hàm ifelse ifelse:

    if (animal == 'cat' || animal == 'dog') {
      print('Animal is a house pet.');
    } else if (animal == 'rhino') {
      print('That\'s a big animal.');
    } else {
      print('Animal is NOT a house pet.');
    }
    // Animal is NOT a house pet.

    Bạn có thể có nhiều else if nhánh giữa if và else tùy theo nhu cầu.

    While Loops

    Vòng lặp cho phép bạn lặp lại mã một số lần nhất định hoặc dựa trên các điều kiện nhất định. Bạn xử lý sự lặp lại dựa trên điều kiện bằng cách sử dụng vòng lặp while .

    Có hai dạng vòng lặp while trong Dart: while và do-while. Sự khác biệt là với while, điều kiện lặp xảy ra trước khối mã. Trong khi do-while, điều kiện xảy ra sau. Điều đó có nghĩa là do-while các vòng lặp đảm bảo khối mã chạy ít nhất một lần.

    Ví dụ While Loop

    Để thử điều này, hãy tạo một biến được i khởi tạo thành 1:

    var i = 1 ;
    

    Tiếp theo, sử dụng một while vòng lặp để in i trong khi tăng dần. Đặt điều kiện thành i nhỏ hơn 10:

    while (i < 10) {
      print(i);
      i++;
    }
    // 1
    // 2
    // 3
    // 4
    // 5
    // 6
    // 7
    // 8
    // 9

    Chạy mã và bạn sẽ thấy rằng while vòng lặp in các số từ 1 đến 9.

    Ví dụ Do-While

    Đặt lại i trong DartPad, sau đó thêm vòng lặp do-while:

    i = 1;
    do {
      print(i);
      i++;
    } while (i < 10);
    // 1
    // 2
    // 3
    // 4
    // 5
    // 6
    // 7
    // 8
    // 9
    

    Kết quả vẫn giống như trước đây. Tuy nhiên, lần này, phần thân của vòng lặp đã chạy một lần trước khi kiểm tra điều kiện thoát khỏi vòng lặp.

    Continue and Break

    Dart sử dụng continue và break từ khóa trong các vòng lặp và các nơi khác. Đây là những gì họ làm:

    • continue : Bỏ qua mã còn lại bên trong một vòng lặp và ngay lập tức chuyển sang lần lặp tiếp theo.
    • break : Dừng vòng lặp và tiếp tục thực hiện sau phần thân của vòng lặp.

    Hãy cẩn thận khi sử dụng continue trong mã của bạn. Ví dụ: nếu bạn thực hiện do-while vòng lặp từ trên và bạn muốn tiếp tục khi i bằng 5, điều đó có thể dẫn đến một vòng lặp vô hạn tùy thuộc vào vị trí bạn đặt câu lệnh continue :

    i = 1;
    do {
      print(i);
      if (i == 5) {
        continue;
      }            
      ++i;
    } while (i < 10);
    // 1
    // 2
    // 3
    // 4
    // 5
    // 5
    // 5
    // 5
    // 5
    // 5
    // 5
    // 5
    // 5
    // 5
    // ...

    Vòng lặp vô hạn xảy ra bởi vì, một khi i là 5, bạn không bao giờ tăng nó nữa, vì vậy điều kiện luôn đúng.

    Nếu bạn chạy điều này trong DartPad, vòng lặp vô hạn sẽ khiến trình duyệt bị treo. Thay vào đó, hãy sử dụng break, để vòng lặp kết thúc sau khi i đạt đến 5:

    i = 1;
    do {
      print(i);
      if (i == 5) {
        break;
      }
      ++i;
    } while (i < 10);
    // 1
    // 2
    // 3
    // 4
    // 5

    Chạy mã. Bây giờ, vòng lặp kết thúc sau năm lần lặp.

    For Loops

    Trong Dart, bạn sử dụng các vòng lặp for để lặp lại một số lần được xác định trước. Vòng lặp for bao gồm khởi tạo, một điều kiện vòng lặp và một hành động. Chúng tương tự như for các vòng lặp trong các ngôn ngữ khác.

    Dart cũng cung cấp một for-in vòng lặp, lặp lại trên một tập hợp các đối tượng. Bạn sẽ tìm hiểu thêm về những điều này sau.

    Để xem cách for hoạt động của một vòng lặp, hãy tạo một biến cho sum:

    var sum = 0 ;
    

    Tiếp theo, sử dụng một vòng lặp for để khởi tạo bộ đếm vòng lặp từ i đến 1. Sau đó, bạn sẽ kiểm tra xem i nhỏ hơn hoặc bằng 10 và tăng dần i sau mỗi vòng lặp.

    Bên trong vòng lặp, sử dụng phép gán ghép để thêm i vào tổng đang chạy:

    for (var i = 1; i <= 10; i++) {
      sum += i;  
    }
    print("The sum is $sum"); // The sum is 55
    
    

    Chạy mã của bạn trong DartPad để xem tổng.

    Kết thúc phần 3!

  • KIẾN THỨC CƠ BẢN VỀ DART(PHẦN 2)

    KIẾN THỨC CƠ BẢN VỀ DART(PHẦN 2)

    Tiếp tục phần 1, sang phần 2 này ta sẽ tìm hiểu về các toán tử có trong Dart.

    Operators

    Dart có tất cả các toán tử thông thường mà bạn quen thuộc từ các ngôn ngữ khác như C, Swift và Kotlin.

    Một số ví dụ về các toán tử của Dart bao gồm:

    • Toán tử số học
    • Toán tử so sánh
    • Toán tử logic

    Lưu ý : Dart cũng cho phép nạp chồng toán tử , như trong C ++ và Kotlin, nhưng điều đó nằm ngoài phạm vi của hướng dẫn này. Để tìm hiểu thêm về chủ đề này, hãy truy cập trang operator overloading của Wikipedia .

    Tiếp theo, bạn sẽ xem xét từng toán tử này.

    Toán tử số học

    Các toán tử số học hoạt động giống như bạn mong đợi. Hãy thử chúng bằng cách thêm một loạt các thao tác vào DartPad của bạn:

    in ( 40 + 2 ); // 42 
    
    print ( 44 - 2 ); // 42 
    
    print ( 21 * 2 ); // 
    
    42 print ( 84/2 ) ; // 42.0
    
    

    Đối với phép chia, ngay cả với số nguyên, Dart suy ra biến kết quả là a double. Đó là lý do tại sao bạn nhận được 42.0 thay vì 42 cho print câu lệnh cuối cùng.

    So sánh bằng

    Dart sử dụng toán tử double-equals ( ==) và not-equals ( !=):

    in ( 42 == 43 ); // 
    
    in sai ( 42 ! = 43 ); // true
    
    

    Toán tử so sánh

    Dart sử dụng các toán tử so sánh điển hình:

    • Nhỏ hơn (<)
    • Lớn hơn (>)
    • Lơn hơn hoặc bằng(>=)
    • Nhỏ hơn hoặc bằng(<=)

    Dưới đây là một số ví dụ:

    print ( 42 < 43 ); // true 
    print (42> = 43); // false
    
    

    Ngoài ra, nó cũng sử dụng các toán tử số học / phép gán ghép thông thường:

    var value = 42.0;
    
    value += 1; print(value); // 43.0
    
    value -= 1; print(value); // 42.0
    
    value *= 2; print(value); // 84.0
    
    value /= 2; print(value); // 42.0
    
    
    

    Toán tử số học / phép gán ghép thực hiện hai nhiệm vụ. +=thêm giá trị ở bên phải vào biến ở bên trái và sau đó gán kết quả cho biến.

    Một dạng rút gọn của += 1 là ++:

    value++;
    
    print(value); // 43.0
    
    

    Và Dart có toán tử modulo thông thường ( %) để trả về phần còn lại sau khi một số đã được chia cho một số khác:

    print( 392 % 50 ); // 42
    
    

    392 ÷ 50 = 7,84 nhưng 42 đó trong ngăn kết quả đến từ đâu? Nó dễ dàng hơn để xem với sự phân chia dài.

    Toán tử logic

    Dart sử dụng các toán tử logic giống như các ngôn ngữ khác, bao gồm và có kí hiệu là &&, OR  có kí hiệu là ||

    print (( 41 < 42 ) && ( 42 < 43 )); // true 
    
    print (( 41 < 42 ) || ( 42 > 43 )); // true
    
    

    Toán tử phủ định là dấu chấm than , biến false thành true và true thành false.

    print (! ( 41 < 42 )); // false
    
    

    Xem tài liệu Dart để biết danh sách đầy đủ các toán tử được hỗ trợ .

    Strings

    Loại chuỗi Dart là String. Các chuỗi được thể hiện trong Dart bằng cách sử dụng văn bản được bao quanh bởi dấu ngoặc kép đơn hoặc kép .

    Bạn có thể sử dụng var và nhập suy luận hoặc String để tạo biến chuỗi, giống như các kiểu khác mà bạn đã thấy:

    var firstName = 'Albert' ; String lastName = "Einstein" ;
    
    
    
    

    Tương tự như các ngôn ngữ như Kotlin và Swift, bạn có thể nhúng giá trị của một biểu thức bên trong một chuỗi bằng cách sử dụng ký hiệu ký hiệu đô la: $ { biểu thức } .

    Nếu biểu thức là một số nhận dạng, bạn có thể bỏ qua dấu {} . Thêm những điều sau:

    var physicist = "$firstName $lastName likes the number ${84 / 2}";
    
    print(physicist); // Albert Einstein
    
    

    $firstName và $lastName được thay thế bằng các giá trị biến. Trả về kết quả được tính toán.

    Escaping Strings

    Các trình tự thoát được sử dụng trong Dart tương tự như các trình tự được sử dụng trong các ngôn ngữ giống C khác. Ví dụ, bạn sử dụng \n cho một dòng mới.

    Nếu có các ký tự đặc biệt trong chuỗi, hãy sử dụng \ để thoát khỏi chúng:

    var quote = 'If you can\'t explain it simply\nyou don\'t understand it well enough.';
    
    print(quote);
    // If you can't explain it simply
    
    // you don't understand it well enough.
    
    

    Ví dụ này sử dụng các dấu ngoặc kép, vì vậy nó cần một chuỗi thoát \', để nhúng các dấu nháy đơn cho can’t và don’t vào chuỗi. Bạn sẽ không cần phải thoát khỏi dấu nháy đơn nếu thay vào đó bạn sử dụng dấu ngoặc kép.

    Nếu bạn cần hiển thị trình tự thoát trong chuỗi, bạn có thể sử dụng raw strings , có tiền tố là r.

    var rawString = r"If you can't explain it simply\nyou don't understand it well enough.";
    
    print(rawString); 
    
    // If you can't explain it simply\nyou don't understand it well enough.
    
    

    Ở đây, Dart được coi `\n`là văn bản bình thường vì chuỗi bắt đầu bằng r.

    Nhấp vào RUN trong DartPad để xem tất cả các chuỗi của bạn trong bảng điều khiển.

    Immutability

    Dart sử dụng các từ khóa constvà finalcác giá trị không thay đổi.

    Sử dụng constcho các giá trị đã biết tại thời điểm biên dịch. Sử dụng finalcho các giá trị không cần biết tại thời điểm biên dịch nhưng không thể gán lại sau khi được khởi tạo.Lưu ý : finalhoạt động giống như valtrong Kotlin hoặc lettrong Swift.

    Bạn có thể sử dụng constvà finalthay cho varvà để phép suy luận kiểu xác định kiểu:

    const speedOfLight = 299792458 ;
    
    in (speedOfLight); // 299792458
    
    

    Ở đây, Dart cho rằng speedOfLight là một biến kiểu int, như bạn có thể thấy trong bảng thông tin của DartPad.

    final cho biết rằng một biến là không thể thay đổi , nghĩa là bạn không thể gán lại final các giá trị. Bạn có thể nêu rõ loại với một trong hai final hoặc const:

    final planet = 'Jupiter';
    
    // planet = 'Mars';
    
    // error: planet chỉ có thể khởi tạo 1 lần
    
    final String moon = 'Europa';
    
    print('$planet has a moon, $moon');
    
    // Jupiter has a moon, Europa
    

    Nullability

    Trước đây, nếu bạn không khởi tạo một biến, Dart đã cấp cho nó giá trị null, có nghĩa là không có gì được lưu trữ trong biến. Tuy nhiên, kể từ Dart 2.12, Dart kết hợp với các ngôn ngữ khác, như Swift và Kotlin, để không thể null theo mặc định.

    Ngoài ra, Dart đảm bảo rằng kiểu không thể null sẽ không bao giờ chứa giá trị null. Điều này được gọi là sound null safety. .

    Thông thường, nếu bạn muốn khai báo một biến, bạn phải khởi tạo nó:

    String middleName = 'May';
    
    print(middleName); // May
    
    

    Tuy nhiên, không phải tất cả mọi người đều có tên đệm, vì vậy việc tạo middleName một giá trị vô hiệu là rất hợp lý. Để nói với Dart rằng bạn muốn cho phép giá trị null, hãy thêm ? vào sau kiểu giữ liểu.

    String? middleName = null;
    
    print(middleName); // null
    
    

    Giá trị mặc định cho kiểu nullable là null, vì vậy bạn có thể đơn giản hóa biểu thức thành như sau:

    String? middleName;
    
    print(middleName); // null
    
    

    Run nó và null in ra bảng điều khiển.

    Toán tử Null-Aware

    Dart có một số toán tử nhận biết null mà bạn có thể sử dụng khi làm việc với các giá trị null.

    Toán tử dấu hỏi kép ?? giống như toán tử Elvis trong Kotlin: Nó trả về toán hạng bên trái nếu đối tượng không phải là null. Nếu không, nó trả về giá trị bên phải:

    var name = middleName ?? 'none';
    
    print(name); // none
    
    

    Vì middleName là null, Dart chỉ định giá trị bên phải của 'none'.

    Toán tử ?. bảo vệ bạn khỏi việc truy cập các thuộc tính của các đối tượng null. Nó trả về null nếu bản thân đối tượng là null. Nếu không, nó trả về giá trị của thuộc tính ở phía bên phải:

    print(middleName?.length); // null
    

    Ngày trước khi chưa có null safety, nếu bạn quên dấu chấm hỏi và viết middleName.length, ứng dụng của bạn sẽ gặp sự cố trong thời gian chạy nếu middleNametrống. Đó không còn là vấn đề nữa, vì Dart giờ đây sẽ cho bạn biết ngay lập tức khi nào bạn cần xử lý các giá trị null.

    Kết thúc phần 2.

  • Kiến thức cơ bản về Dart(Phần 1)

    Giới thiệu

    Giới thiệu về kiến ​​thức cơ bản của ngôn ngữ lập trình Dart, được sử dụng để phát triển với Flutter SDK dành cho thiết bị di động, web và hơn thế nữa.

    Flutter là một bộ công cụ giao diện người dùng thú vị của Google cho phép bạn viết ứng dụng cho các nền tảng khác nhau bao gồm iOS, Android, web và hơn thế nữa, tất cả đều sử dụng một cơ sở mã. Flutter sử dụng ngôn ngữ Dart.

    Nếu bạn chưa quen với Dart, hướng dẫn này sẽ giới thiệu cho bạn các khái niệm cơ bản của nó và cho bạn thấy nó tương tự như thế nào với các ngôn ngữ lập trình khác mà bạn có thể đã biết.

    Trong suốt quá trình hướng dẫn này, bạn sẽ được giới thiệu về những điều cơ bản của Dart chẳng hạn như:

    • Variables, data types, and operators
    • Conditionals and loops
    • Collections
    • Functions

    Khi bạn hoàn thành, bạn sẽ sẵn sàng đi sâu vào phát triển Flutter bằng cách sử dụng Dart.

    Bắt Đầu

    Để bắt đầu nhanh chóng, cách tốt nhất của bạn là sử dụng công cụ mã nguồn mở DartPad , cho phép bạn viết và kiểm tra mã Dart thông qua trình duyệt web:

    DartPad được thiết lập giống như một IDE thông thường. Nó bao gồm các thành phần sau:

    • Khung trình soạn thảo : Nằm ở bên trái. Mã của bạn sẽ xuất hiện ở đây.
    • Nút RUN : Chạy mã trong trình chỉnh sửa.
    • Bảng điều khiển : Nằm ở phía trên bên phải, bảng này hiển thị đầu ra.
    • Bảng tài liệu : Nằm ở dưới cùng bên phải, bảng này hiển thị thông tin về mã.
    • Samples: Trình đơn thả xuống này hiển thị một số mã mẫu.
    • Nút Null Safety: Sử dụng nút này để chọn tham gia vào tính năng an toàn không có âm thanh mới của Dart.
    • Thông tin phiên bản : Ở phía dưới cùng bên phải, DartPad hiển thị phiên bản Flutter và Dart mà nó hiện đang sử dụng.

    Nếu muốn, bạn có thể cài đặt Dart SDK cục bộ trên máy của mình. Một cách để làm như vậy là cài đặt Flutter SDK . Cài đặt Flutter cũng sẽ cài đặt Dart SDK.

    Để cài đặt trực tiếp SDK Dart, hãy truy cập https://dart.dev/get-dart .

    Tại sao nên chọn Dart

    Dart có nhiều điểm tương đồng với các ngôn ngữ khác như Java, C #, Swift và Kotlin. Một số tính năng của nó bao gồm:

    • Statically typed
    • Type inference
    • String expressions
    • Multi-paradigm including object-oriented and functional programming
    • Null safe

    Dart được tối ưu hóa để phát triển các ứng dụng nhanh trên nhiều nền tảng.

    Variables, Comments and Data Types

    Điều đầu tiên bạn sẽ thêm vào main là một câu lệnh gán biến. Các biến giữ dữ liệu mà chương trình của bạn sẽ hoạt động.

    Bạn có thể coi một biến như một hộp trong bộ nhớ máy tính của bạn chứa một giá trị. Mỗi hộp có một tên, đó là tên của biến. Để biểu thị một biến bằng Dart, hãy sử dụng var từ khóa.

    Thêm một biến mới vào main:

    var myAge = 35 ;  
    
    

    Mỗi câu lệnh Dart kết thúc bằng dấu chấm phẩy, giống như các câu lệnh trong C và Java. Trong đoạn mã trên, bạn đã tạo một biến myAge và đặt nó bằng 35 .

    Bạn có thể sử dụng print Dart tích hợp sẵn để in biến vào bảng điều khiển. Thêm lệnh gọi đó sau biến:

    in (myAge); // 35
    
    

    Nhấp vào RUN trong DartPad để chạy mã. Bạn sẽ thấy giá trị của biến 35 được in trong bảng điều khiển.

    Comments

    Comments trong Dart giống như trong C và các ngôn ngữ khác. Văn bản sau // là một nhận xét một dòng, trong khi văn bản bên trong /* ... */ là một khối nhận xét nhiều dòng.

    Đây là một ví dụ:

    // Đây là một nhận xét một dòng. 
    
    in (myAge); // Đây cũng là một nhận xét một dòng. 
    
    / * 
     Đây là một khối bình luận nhiều dòng. Điều này rất hữu ích cho những 
     bình luận dài kéo dài vài dòng. 
     * /
    
    

    Data Types

    Dart là statically typed , nghĩa là mỗi biến trong Dart có một kiểu mà bạn phải biết khi biên dịch mã. Loại biến không thể thay đổi khi bạn chạy chương trình. C, Java, Swift và Kotlin cũng có statically typed .

    Điều này trái ngược với các ngôn ngữ như Python và JavaScript, được gõ động . Điều đó có nghĩa là các biến có thể chứa các loại dữ liệu khác nhau khi bạn chạy chương trình. Bạn không cần biết kiểu khi bạn biên dịch mã.

    Nhấp vào myAge cửa sổ trình chỉnh sửa và tìm trong bảng Tài liệu . Bạn sẽ thấy Dart được suy ra là myAge kiểu int vì nó được khởi tạo với giá trị số nguyên 35 .

    Nếu bạn không chỉ định rõ ràng một kiểu dữ liệu, Dart sẽ sử dụng suy luận kiểu để cố gắng xác định nó, giống như Swift và Kotlin.

    Dart cũng sử dụng kiểu suy luận cho các kiểu khác int. Nhập một biến pi bằng 3,14:

    var pi = 3,14 ; in (pi); // 3,14
    
    
    
    

    Dart pi được cho là double bởi vì bạn đã sử dụng một giá trị dấu phẩy động để khởi tạo nó. Bạn có thể xác minh điều đó trong bảng thông tin Dart bằng cách nhấp vào pi.

    Các kiểu dữ liệu cơ bản

    Dart sử dụng các loại cơ bản sau:

    • int : Số nguyên
    • double : Số phức
    • bool : Booleans
    • String: Chuỗi ký tự

    Dưới đây là một ví dụ về từng loại trong Dart:

    int và double cả hai đều bắt nguồn từ một kiểu được đặt tên numnum sử dụng dynamic từ khóa để bắt chước cách nhập động trong Dart.

    Thực hiện việc này bằng cách thay thế varbằng loại bạn muốn sử dụng:

    int yourAge = 27 ;
    
    in (yourAge); // 27
    
    

    Từ khóa Dynamic

    Nếu bạn sử dụng từ khóa dynamic từ khóa thay vì var, bạn sẽ nhận được một biến được nhập động một cách hiệu quả:

    dynamic numberOfKittens;
    
    

    Tại đây, bạn có thể đặt numberOfKittensthành một String dấu ngoặc kép. Bạn sẽ tìm hiểu thêm về String loại này sau trong hướng dẫn.

    numberOfKittens = 'There are no kittens!';
    
    print(numberOfKittens); // There are no kittens!
    
    

    numberOfKittenscó một kiểu, vì Dart có kiểu gõ tĩnh. Nhưng kiểu dynamicđó, có nghĩa là bạn có thể gán các giá trị khác với các kiểu khác cho nó. Vì vậy, bạn có thể chỉ định một intgiá trị bên dưới câu lệnh in của mình.

    numberOfKittens = 0 ; print (numberOfKittens); // 0
    
    
    
    

    Hoặc, nếu bạn có một con mèo con trong hộp của Schrödinger , bạn có thể gán một double giá trị:

    numberOfKittens = 0,5 ; print (numberOfKittens); // 0,5
    
    
    
    
    

    Nhấp vào RUN để xem ba giá trị khác nhau numberOfKittens được in trong bảng điều khiển. Trong mỗi trường hợp, kiểu của numberOfKittens phần còn lại dynamic, mặc dù bản thân biến đó giữ các giá trị của các kiểu khác nhau.

    Booleans

    Kiểu bool chứa các giá trị của một trong hai true hoặc false.

    bool areThereKittens = false ; print (areThereKittens); // false
    
    
    
    

    Nhưng, nếu bạn nhìn vào bên trong hộp của Schrödinger, bạn có thể chuyển sang có một con mèo con thực sự có:

    numberOfKittens = 1 ; 
    
    areThereKittens = true ; print (areThereKittens); // true
    
    
    
    

    Chạy lại mã để xem các giá trị Boolean của bạn trong bảng điều khiển.