Flutter Widget Container là một trong những widget cơ bản của Flutter. Widget Container sử dụng để bao (bọc) một widget khác như Text và giúp widget con này có các thuộc tính như margin, padding…
transform→ Matrix4?The transformation matrix to apply before painting the container.
final
transformAlignment→ AlignmentGeometry?The alignment of the origin, relative to the size of the container, if transform is specified. […]
final
Các phương thức của widget Container
build(BuildContextcontext) → Widget. Describes the part of the user interface represented by this widget. override
createElement() → StatelessElement. Creates a StatelessElement to manage this widget’s location in the tree.
inherited
toString({DiagnosticLevel minLevel: DiagnosticLevel.info}) → String. A string representation of this object. inherited
toStringDeep({String prefixLineOne: '', String? prefixOtherLines, DiagnosticLevel minLevel: DiagnosticLevel.debug}) → String. Returns a string representation of this node and its descendants.
inherited
toStringShort() → String. A short, textual description of this widget.
inherited
Chúng tôi đang biên soạn Giáo trình tự học Flutter/Dart (bài viết, video, ebook) theo cấu trúc sau, hi vọng có thể giúp ích được cho các bạn. Bạn có thể bấm vào từng đường link để đến bài viết cụ thể. Nếu cần luyện tập ngôn ngữ Dart, bạn có thể tham khảo 50 bài tập lập trình Dart cơ bản
https://flutter.dev/docs là nơi tốt nhất để tự học Flutter, đây là nơi cung cấp tài liệu chính thức về Flutter của Google.
Dưới đây là danh sách các video chúng tôi đang thực hiện, các video được đánh số thứ tự để bạn đọc dễ theo dõi.
Null safety Dart / Null safety Flutter là gì? Tại sao Google lại hỗ trợ null safety? Bắt đầu từ phiên bản 2.0 thì Dart/Flutter đã chính thức hỗ trợ tính năng an toàn null safety.
Khi bạn chọn sử dụng null safety, các biến trong chương trình của bạn là không thể nhận giá trị mặc định null, có nghĩa là các biến không thể nhận giá trị nulltrừ khi bạn chỉ rõ chúng có thể.
Thì do bạn chưa cung cấp cho các biến a, so_nguyen_x, ho_va_ten một giá trị mặc định nên Dart sẽ gán giá trị mặc định của chúng là null. Điều này có thể gây ra lỗi khi chương trình chạy, ví dụ biến so_nguyen_x chưa được cung cấp giá trị nào mà bạn lại đem đi tính toán!
Do đó, từ phiên bản Dart/Flutter 2.0 trở đi, bạn bắt buộc phải cung cấp một giá trị mặc định trước khi sử dụng biến đó (thường là ngay khi khai báo biến).
Trong trường hợp bạn chưa muốn cung cấp giá trị cho biến ngay, hoặc biến của bạn có thể chấp nhận giá trị null thì bạn phải thêm kí tự ? vào sau kiểu của biến khi khai báo hoặc gán giá trị mặc định cho biến là null. Ví dụ, đoạn chương trình trên phải sửa thành:
var bien_a = null;
int? so_nguyen_x;
String? ho_va_ten;
Với việc hỗ trợ null safety thì các lỗi null-dereference trong thời gian chạy của bạn sẽ chuyển thành lỗi phân tích cú pháp ngay trong khi bạn gõ code, do đó giúp việc debug chương trình trở nên thuận tiện hơn.
Bạn không nhất thiết phải cung cấp giá trị cho biến ngay, mà chỉ cần cung cấp trước khi biến đó được sử dụng. Ví dụ, đoạn mã sau là hoàn toàn hợp lệ.
void main() {
int x;
print('Blah blah blah...');
x = 10;
print(x);
}
Như vậy, cách để sửa lỗi null safety của các mã nguồn cũ (phiên bản Dart 1.x) chỉ đơn giản là thêm kí tự ? vào sau kiểu của biến khi khai báo nếu biến đó có thể nhận giá trị null (dĩ nhiên sau đó, trước khi sử dụng đến biến đó bạn phải cung cấp giá trị cho nó); hoặc gán cho biến một giá trị mặc định nếu biến đó không thể nhận giá trị null. Bạn cũng có thể tham khảo chi tiết ở bài viết https://dart.dev/null-safety/migration-guide
Trước phiên bản 2.0, Dart là ngôn ngữ nullability. Theo đó, null sẽ là kiểu con (subtype) của mọi kiểu. Tức là tất cả các kiểu số nguyên int, số thực double, danh sách List… đều chấp nhận giá trị null.
Tuy nhiên, từ phiên bản 2.0 thì Dart là ngôn ngữ hỗ trợ null safety. Theo đó, kiểu Null đã tách ra, không còn là kiểu con của các kiểu khác nữa. Do đó, khi bạn khai báo một biến là non-nullable (ví dụ kiểu int, kiểu String) mà lại gán cho chúng giá trị null thì chương trình sẽ báo lỗi.
2️⃣Nguyên tắc thiết kế của Null safety Dart/Flutter
Null safety Dart (Null safety Flutter) dựa trên 3 nguyên tắc thiết kế cốt lõi sau:
Mặc định khi khai báo các biến là non-nullable (không thể nhận giá trị null), trừ khi bạn chỉ rõ rằng một biến có thể là null. Mặc định này được chọn sau khi Google nghiên cứu phát hiện ra rằng non-null là lựa chọn phổ biến nhất trong các API.
Incrementally adoptable. Bạn quyết định những phần nào của các dự án hiện tại để chuyển sang null safety vào bất cứ khi nào. Bạn có thể di chuyển từng bước, sử dụng đồng thời các mã null- safe và không null- safe trong cùng một dự án. Google cung cấp các công cụ để giúp bạn di chuyển (migration).
Fully sound. Dart cho phép tối ưu hóa trình biên dịch . Nếu hệ thống kiểu dữ liệu của Dart xác định rằng một cái gì đó không phải là null, thì cái đó không bao giờ có thể là null. Một khi bạn di chuyển toàn bộ dự án của mình và các thành phần phụ thuộc của nó sang null safety, bạn sẽ thu được toàn bộ lợi ích của sự ổn định – không chỉ ít lỗi hơn mà còn có các tệp nhị phân nhỏ hơn và việc thực thi dự án của bạn sẽ nhanh hơn.
3️⃣Kí tự !
Bạn sử dụng kí tự ! ở phía sau một biểu thức để thực thi biểu thức đó và chuyển (cast) giá trị nhận được sang kiểu non-nullable
// Using null safety, incorrectly:
class HttpResponse {
final int code;
final String? error;
HttpResponse.ok() : code = 200;
HttpResponse.notFound()
: code = 404,
error = 'Not found';
String toString() {
if (code == 200) return 'OK';
return 'ERROR ${error!.toUpperCase()}';
}
}
4️⃣Late variables (khai báo biến trễ, biến muộn)
Đôi khi các biến – các trường trong một lớp class hoặc các biến cấp cao nhất – phải là kiểu non-nullable, nhưng chúng không thể được gán giá trị ngay lập tức. Đối với những trường hợp như vậy, hãy sử dụng từ khóa late.
class MonAn {
late String ten;
void setTen(String str) {
ten = str;
}
}
void main() {
final buaSang = MonAn();
buaSang.setTen('Chim To Dần');
print(buaSang.ten);
}
Trong ví dụ trên, biến ten rõ ràng là kiểu non-nullable nhưng chúng ta không thể gán giá trị mặc định, vì class MonAn này chưa có đối tượng nào được tạo ra. Khi chúng ta tạo ra đối tượng buaSang thuộc class MonAn thì chúng ta mới biết (và cần) phải cung cấp giá trị cho trường ten trước khi sử dụng nó.
Khi bạn sử dụng latetrước một khai báo biến, điều đó sẽ giúp cho Dart biết rằng:
Biến này không cần kiểm tra phải có giá trị mặc định ngay.
Bạn sẽ gán cho nó một giá trị sau đó.
Bạn sẽ đảm bảo rằng biến có một giá trị trước khi biến được sử dụng.
Nếu bạn khai báo một biến latevà biến đó được sử dụng trước khi nó được gán giá trị, thì Dart vẫn sẽ báo lỗi.
Ví dụ trên, nhiều bạn có thể sẽ sửa lại như sau:
class MonAn {
String? ten;
void setTen(String str) {
ten = str;
}
}
void main() {
final buaSang = MonAn();
buaSang.setTen('Chim To Dần');
print(buaSang.ten);
}
Chương trình vẫn hoạt động! Nhưng sẽ gây bối rối cho việc khởi tạo lớp MonAn bởi vì trường ten rõ ràng là sẽ không bao giờ được nhận giá trị null nên việc sử dụng từ khóa ? để chấp nhận cho nó có thể nhận giá trị null sẽ tiềm ẩn những lỗi logic sau này.
Việc sử dụng từ khóa late này còn được gọi là trì hoãn khởi tạo hoặc khởi tạo muộn, khởi tạo trễ (lazy initialization)
5️⃣Late final variables
Bạn có thể kết hợp từ khóalate với final:
// Using null safety:
class Coffee {
late final String _temperature;
void heat() {
_temperature = 'hot';
}
void chill() {
_temperature = 'iced';
}
String serve() => _temperature + ' coffee';
}
Không giống như cách khai báo biến/trường final thông thường, bạn không phải khởi tạo giá trị cho trường/biến đó trong phần mô tả hoặc phần xây dựng lớp (constructor). Bạn có thể gán giá trị cho nó trong lúc chương trình chạy. Nhưng vì sử dụng từ khóa final, nên bạn chỉ được phép gán một lần!
Required named parameters
To guarantee that you never see a null parameter with a non-nullable type, the type checker requires all optional parameters to either have a nullable type or a default value. What if you want to have a named parameter with a nullable type and no default value? That would imply that you want to require the caller to always pass it. In other words, you want a parameter that is named but not optional.
I visualize the various kinds of Dart parameters with this table:
For unclear reasons, Dart has long supported three corners of this table but left the combination of named+mandatory empty. With null safety, we filled that in. You declare a required named parameter by placing required before the parameter:
// Using null safety:function({int?a,requiredint?b,int?c,requiredint?d}){}
Here, all the parameters must be passed by name. The parameters a and c are optional and can be omitted. The parameters b and d are required and must be passed. Note that required-ness is independent of nullability. You can have required named parameters of nullable types, and optional named parameters of non-nullable types (if they have a default value).
This is another one of those features that I think makes Dart better regardless of null safety. It simply makes the language feel more complete to me
Phần mềm đóng dấu ảnh hàng loạt (phần mềm chèn watermark vào ảnh) là các phần mềm giúp bạn tự động thêm hàng loạt chữ (text) hoặc hình ảnh (logo, icon…) vào các ảnh một cách nhanh chóng và đơn giản và hoàn toàn miễn phí.
Để đóng dấu watermark vào ảnh hàng loạt, bạn có thể tải các phần mềm về và cài đặt vào máy tính. Nếu chỉ cần chèn watermark cho một hoặc vài ảnh, bạn có thể sử dụng các dịch vụ chèn watermark online hoặc sử dụng ngay phần mềm Paint của Windows.
#1 Phần mềm đóng dấu ảnh hàng loạt miễn phí trên Windows
Faststone Photo Resizer là phần mềm đóng dấu ảnh hàng loạt miễn phí trên Windows theo chúng tôi đánh giá là tốt nhất và dễ sử dụng. Bạn xem thêm cách sử dụng cơ bản tại đây Phần mềm Resize ảnh hàng loạt miễn phí
Các tính năng chính của Faststone Photo Resizer:
Miễn phí cho mục đích cá nhân và dung lượng nhẹ (3MB), có phiên bản Portable (chạy trực tiếp không cần cài đặt)
Chuyển đổi định dạng hình ảnh (Convert hình ảnh), giảm dung lượng file ảnh
Đổi tên hình ảnh ở chế độ hàng loạt
Chèn Watermark, chú thích vào hình ảnh.
Hỗ trợ các định dạng ảnh JPEG , BMP , GIF , PNG , TIFF và JPEG2000
Thay đổi kích thước, cắt, thay đổi độ sâu màu, áp dụng hiệu ứng màu, thêm văn bản , hình mờ và hiệu ứng đường viền
Đổi tên hình ảnh bằng số thứ tự
Tìm kiếm và thay thế văn bản trong tên tệp
Hỗ trợ đa luồng, tức là xử lý nhiều hình ảnh đồng thời để có hiệu suất tốt hơn (Chỉnh sửa một hoặc nhiều tập tin ảnh cùng lúc)
Hỗ trợ nén hình ảnh hàng loạt mà không giảm chất lượng hình ảnh quá nhiều.
#2 Phần mềm đóng dấu ảnh hàng loạt cho điện thoại, máy tính uMark
Phần mềm đóng dấu ảnh hàng loạt uMark không chỉ dành cho máy tính Windows mà còn có các phiên bản hỗ trợ cho MacOS (Macbook, iMac, macmini) và cả điện thoại (android, ios), iPad.
Tính năng của mềm đóng dấu ảnh hàng loạt cho điện thoại, máy tính uMark
Chọn phông chữ, cỡ chữ, kiểu và màu sắc cho hình mờ của bạn. Đặt mức độ trong suốt tùy chỉnh, thêm bóng hoặc xoay hình mờ theo sở thích của bạn.
Hỗ trợ nhiều định dạng ảnh
Tùy chọn xem trước hình ảnh trước khi chuyển đổi
Thêm đường viền và bóng
Thêm EXIF và siêu dữ liệu khác dưới dạng hình mờ. Đánh dấu ngày tháng lên ảnh của bạn bằng hình mờ EXIF của uMark. Thêm thông tin máy ảnh hoặc các chi tiết kỹ thuật khác dưới dạng hình mờ. Đặt tên ảnh, thời gian chụp, khẩu độ, tốc độ màn trập, v.v. vào hình mờ.
uMark là một phần mềm watermarking chuyên nghiệp, sử dụng phần mềm này bạn có thể làm mọi thứ để bảo vệ bản quyền tài sản kỹ thuật số của mình.
Mặc dù đây là phần mềm tiên tiến nhưng nó rất dễ sử dụng và làm việc với nó. Nó cung cấp tính năg xử lý hàng loạt, giúp bạn thêm hình mờ vào ảnh và video của mình dễ dàng hơn (tối đa 50 cùng một lúc).
Với phần mềm này, bạn cũng có thể chọn loại hình mờ bạn muốn có trên tác phẩm kỹ thuật số của mình. Nó có thể là văn bản, hình ảnh, hình dạng và mã QR. Bạn có thể điều chỉnh vị trí, kích thước, mức độ trong suốt, kiểu dáng và màu sắc của nó, thêm hiệu ứng bóng râm và xoay hình mờ.
Phần mềm Resize ảnh hàng loạt miễn phí FastStone Photo Resizer không chỉ giúp thay đổi kích thước ảnh mà còn là một phần mềm convert ảnh (chuyển đổi định dạng ảnh) và đổi tên hình ảnh hoàn toàn miễn phí.
Phần mềm miễn phí resize ảnh hàng loạt FastStone Photo Resizer cho phép người dùng chuyển đổi, đổi tên, thay đổi kích thước, cắt, xoay, thay đổi độ sâu màu, thêm watermark dạng văn bản hoặc hình mờ vào hình ảnh ở chế độ hàng loạt nhanh chóng và dễ dàng. Thao tác kéo và thả chuột được hỗ trợ tốt.
Google Sheets (Google Trang tính, Google Bảng tính) là một ứng dụng trang tính tương tự như Microsoft Excel, Google Sheets dựa trên nền tảng web. Một số đặc điểm của Google Sheets:
Tạo và chỉnh sửa đồng thời bảng tính với nhiều người khác, ngay trên trình duyệt web.
Phân tích dữ liệu với các biểu đồ và bộ lọc, xử lý danh sách nhiệm vụ, tạo kế hoạch dự án, v.v.
Lưu các thay đổi một cách tự động, thành nhiều phiên bản.
Google Sheets không thể cung cấp tất cả các tính năng nâng cao như Excel, nhưng bù lại nó khá dễ dàng để tạo và chỉnh sửa các trang tính từ đơn giản đến phức tạp và đương nhiên, có một số điểm ưu việt hơn MS Excel như cho phép lưu trữ nhiều phiên bản (version) khác nhau của cùng một trang tính, cho phép làm việc cộng tác (nhiều người cùng làm việc trên một trang tính)… mà chúng tôi sẽ lần lượt giới thiệu sau.
Bạn truy cập địa chỉ http://sheets.google.com hoặc https://docs.google.com/spreadsheets/ và chọn vào biểu tượng dấu cộng để tạo một trang tính (sheet) trống (trắng) mới; hoặc tạo một sheet mới theo các mẫu (templete) có sẵn như Ngân sách hàng năm, Danh sách việc cần làm…
Bạn cũng có thể tải app cho thiết bị di động (điện thoại, máy tính bảng) tương ứng với 2 hệ điều hành phổ biến là Android, và iOS
2. Tùy biến bảng tính (Hiển thị và dữ liệu)
Lưu ý: Nếu bạn quen với các phím tắt (keyboard shortcuts) trong Microsoft Excel, bạn có thể tự định nghĩa đè các phím tắt.
3. Làm việc với dòng, cột và ô
Thêm dòng row, cột column và ô cell
Sử dụng chuột trái để chọn dòng, cột hoặc ô gần nơi mà bạn muốn thêm mới.
Bấm chuột phải dòng, cột, ô đang được chọn (highlighted)Chèn (Insert)chọn nơi (bên trên, bên dưới, bên trái, bên phải) mà bạn muốn chèn dòng, cột, ô mới.
Bấm chuột phải vào số dòng hoặc (row number) hoặc tên cột (column letter)Chọn Xóa, Xóa nội dung hoặc Ẩn.
Cần lưu ý, nếu chọn Xóa (Delete) thì toàn bộ dòng, cột đó sẽ bị xóa và các dòng ở phía dưới sẽ được đẩy lên trên, cột ở bên phải sẽ được dịch sang trái để thế chỗ của dòng, cột vừa xóa. Còn Xóa nội dung (Clear) thì dòng, cột đó vẫn còn, chỉ có nội dung của dòng, cột đó bị xóa (tức là trở thành dòng, cột trống).
Xóa ô
Chọn ô cần xóa và bấm chuột phảiXóa ôShift left or Shift up.
Di chuyển dòng, cột
Bấm chuột trái và giữ tiêu đề dòng hoặc cột, sau đó kéo đến vị trí mới.
Di chuyển ô:
Bấm chọn ô cần di chuyển.
Đặt con trỏ chuột ở phía trên cùng của ô đó cho đến khi biểu tượng hình bàn tay xuất hiện.
Bấm giữ chuột trái và kéo ô đến vị trí mới.
Đóng băng dòng hoặc cột tiêu đề
Keep a row or column in the same place as you scroll through your spreadsheet. On the menu bar, click ViewFreeze and choose an option.
4. Chia sẻ bảng tính và làm việc cộng tác với
Click Share to share your spreadsheet and then choose what collaborators can do. They’ll also receive an email notification.
Share or unshare
Edit content directly
Add comments
Người chỉnh sửa
✔
✔
✔
Người nhận xét
✔
Người xem
5. Làm việc cộng tác với người khác trong thời gian thực
Google Sheets cho phép nhiều người cùng làm việc (chỉnh sửa) trên cùng một bảng tính trong cùng một lúc bằng tính năng cộng tác.
6. Tạo các phiên bản khác nhau và nhân bản bảng tính của bạn
Make a copy—Create a duplicate of your spreadsheet. This is a great way to create templates.
Download as—Download your spreadsheet in other formats, such as Excel or PDF.
Email as attachment—Email a copy of your spreadsheet.
Version history—See all the changes you and others have made to the spreadsheet or revert to earlier versions.
Publish to the web—Publish a copy of your spreadsheet as a webpage or embed your spreadsheet in a website.
7. Các hàm thông dụng trong Google Sheets
Các hàm phổ biến nhất trong Excel đều có hàm tương ứng trong Google Sheets.
AVERAGE
Thống kê Trả về giá trị trung bình của tập dữ liệu (trong một dòng, cột hoặc phạm vi được chỉ rõ)
Returns the numerical average value in a dataset, ignoring text.
AVERAGEIFS
Thống kê Trả về giá trị trung bình của tập dữ liệu (trong một dòng, cột hoặc phạm vi được chỉ rõ) theo một hoặc nhiều tiêu chí khác nhau
Returns the average of a range that depends upon multiple criteria.
CHOOSE
Tìm kiếm Trả về một phần tử từ một danh sách các lựa chọn dựa trên chỉ số (index) của phần tử đó.
COUNT
Statistical Returns the count of the number of numeric values in a dataset.
COUNTIF
Statistical Returns a conditional count across a range.
DATE
Date Converts a provided year, month, and day into a date.
FIND
Text Returns the position at which a string is first found within text.
GETPIVOTDATA
Text Extracts an aggregated value from a pivot table that corresponds to the specified row and column headings.
IF
Logical Returns one value if a logical expression is true and another if it is false.
INDEX
Lookup Returns the content of a cell, specified by row and column offset.
INT
Math Rounds a number down to the nearest integer that’s less than or equal to it.
LOOKUP
Lookup Looks through a row or column for a key and returns the value of the cell in a result range located in the same position as the search row or column.
MATCH
Lookup Returns the relative position of an item in a range that matches a specified value.
MAX
Statistical Returns the maximum value in a numeric dataset.
MIN
Statistical Returns the minimum value in a numeric dataset.
NOW
Date Returns the current date and time as a date value.
ROUND
Math Rounds a number to a certain number of decimal places according to standard rules.
SUM
Math Returns the sum of a series of numbers and/or cells.
SUMIF
Math Returns a conditional sum across a range.
TODAY
Date Returns the current date as a date value.
VLOOKUP
Lookup Searches down the first column of a range for a key and returns the value of a specified cell in the row found.
Tuy nhiên, một chương trình tin học thông thường gồm rất nhiều câu lệnh xử lý trên dữ liệu (dữ liệu do người dùng nhập vào, dữ liệu tự sinh ra trong quá trình tính toán, dữ liệu lấy từ các tệp trên máy tính….) Và để làm việc (tính toán, xử lý) dữ liệu đó, chúng ta cần đến các biến để lưu trữ chúng.
1. Khai báo biến trong chương trình Dart
1.1. Cú pháp khai báo biến trong Dart
Để khai báo một biến trong chương trình, chúng ta sử dụng cú pháp:
vartên_biến;hoặc kiểu_dữ_liệu_của_biếntên_biến;
Trong các phiên bản cũ, khi khai báo theo cách trên, Dart sẽ gán cho các biến một giá trị mặc định là null. Bắt đầu từ phiên bản 2.0, Dart/Flutter chính thức hỗ trợ null safety, nên sẽ không gán giá trị mặc định null nữa mà bạn bắt buộc phải cho biến một giá trị trước khi sử dụng. Do đó, thông thường chúng ta sẽ khai báo biến như sau:
Khi khai báo biến sử dụng từ khóa var thì khi sử dụng đến biến đó, trình biên dịch Dart sẽ tự xác định kiểu dữ liệu của biến cho chúng ta.
Ví dụ var x; để khai báo một biến có tên là x. Viết int x; để khai báo một biến kiểu số nguyên int và có tên là x.
Khai báo nhiều biến cùng lúc [thường các biến có cùng kiểu], chúng ta sử dụng cú pháp:
vartên_biến1, tên_biến2;
hoặc kiểu_dữ_liệu_của_biếntên_biến1, tên_biến2, tên_biến3;
1.2. Giá trị ban đầu của biến
Xét chương trình sau sử dụng hai biến kiểu số nguyên int là a và b, thực hiện phép cộng hai số a và b rồi in kết quả ra màn hình.
void main() {
int a, b;
print(a+b);
}
Tuy nhiên khi chạy chương trình, trình biên dịch báo lỗi như hình sau:
Nguyên nhân là chúng ta mới khai báo hai biến a và b chứ chưa cung cấp cho chúng một giá trị nào cả. Do đó không thể thực hiện được phép cộng.
Chúng ta tiến hành cung cấp cho hai biến a,b các giá trị, chương trình chạy thành công, kết quả thu được là 9:
Chúng ta có thể vừa khai báo biến, vừa cung cấp cho biến một giá trị mặc định khởi đầu như trong ví dụ sau:
void main() {
int a = 5;
int b = 4;
print(a+b);
}
hoặc viết gọn hơn
void main() {
int a = 5, b = 4;
print(a+b);
}
1.3. Kiểu của biến
Nếu khai báo với từ khóa var, kiểu của biến sẽ được Dart tự động xác định. Nếu muốn chỉ định kiểu của biến, chúng ta đã biết cách khai báo ở trên. Tuy nhiên, đối với những biến nhận giá trị thuộc mọi kiểu, chúng ta có thể khai báo chúng là kiểu dynamic hoặc Object.
void main() {
dynamic a = 4;
dynamic b;
print(a.runtimeType);
a = 'Phuong';
print(a.runtimeType);
print(b.runtimeType);
}
Khi chạy chương trình sẽ được kết quả như hình sau:
Nếu khai báo biến có kiểu dynamic thì giá trị mặc định của biến sẽ là null còn khai báo Object thì biến sẽ không có giá trị mặc định. Ví dụ sau, khai báo biến a có kiểu dynamic thì a sẽ nhận giá trị mặc định là null, còn biến b khai báo kiểu Object thì sẽ không có giá trị mặc định nào cả, kể cả giá trị null. Do đó hãy cẩn thận.
1.4. Sự khác nhau giữa từ khoá var và dynamic
Nếu bạn khai báo biến bằng từ khoá var và gán giá trị mặc định ngay thì biến sẽ có kiểu là kiểu của giá trị mặc định đó, nếu không thì biến sẽ có kiểu dynamic.
void main() {
var a;
print(a.runtimeType); //Null vì giá trị mặc định của dynamic là null
a = 5; //OK
print(a.runtimeType); //kiểu int
a = 'Phuong'; //OK
print(a.runtimeType);//kiểu String
var b = 5;
print(b.runtimeType);//Kiểu int
b = 3; //OK
b = 'five'; //Erros
}
Dart cũng cung cấp một toán tử đặc biệt ??, gọi là Null-aware để đảm bảo null safe trong quá trình thực thi code.
Sử dụng toán tử ??=, để gán một giá trị cho biến nếu và chỉ nếu biến đó đang có giá trị null.
main() {
var a; //biến kiểu dynamic a, mặc định nhận giá trị null
a ??= 3; //Gán 3 cho a nếu a đang có giá trị null, phép gán thành công
print(a); //Phép gán trên thành công nên a nhận giá trị 3
a ??= 5; //Gán 5 cho a nếu a đang có giá trị null, phép gán không thành công
print(a); //a vẫn có giá trị như lúc trước khi thực hiện phép gán
}
Một toán tử null-aware khác là ??, toán tử này trả về biểu thức nằm bên trái toán tử ?? nếu và chỉ nếu biểu thức đó có giá trị khác null, ngược lại thì trả về biểu thức nằm phía bên phải.
print(1 ?? 3); //In ra 1.
print(null ?? 12); // In ra 12.
1.4. Quy tắc đặt tên trong Dart
Trong cú pháp khai báo trên,tên_biến được đặt tên theo các quy tắc bắt buộc sau:
Tên phải bắt đầu bằng kí tự từ a đến z, hoặc từ A đến Z hoặc dấu gạch dưới _ và theo sau là chữ hoặc số.
Tên có phân biệt chữ HOA và chữ thường, do đó ten_bien và Ten_Bien là hai tên khác nhau.
Ngoài các quy tắc bắt buộc phải tuân theo đó, chúng ta nên đặt tên theo các quy ước ngầm sau:
Nên đặt tên có ý nghĩa, điều này giúp việc đọc hiểu code được dễ dàng hơn.
Đặt tên ngắn gọn, giúp việc gõ code được nhanh hơn, thường chúng ta sẽ viết tắt tên bằng cách viết HOA chữ cái đầu của từ viết tắt, ví dụ IOStreamInputOutputStream...
Nên đặt tên kiểu UpperCamelCase cho lớp class, enums, tham số (chữ đầu của từ là chữ in ví dụ HttpRequest)
Tên file, thư viện viết chữ thường, các từ nối với nhau bởi _ ví dụ abc_xyz.dart
Biến, hằng, object đặt tên kiểu lowerCamelCase, chữ đầu các từ viết IN HOA, trừ từ đầu tiên ( ví dụ defaultTimeout)
1.3. Khai báo hằng số trong Dart
Để khai báo một hằng số trong Dart, chúng ta sử dụng cú pháp
consttên_hằng_số = giá_trị;
Ví dụ, sử dụng const pi = 3.1415926;để khai báo hằng số có tên pi và có giá trị bằng 3.1415926
Kiểu số num gồm có hai kiểu con là kiểu số nguyên int, số thực double
Kiểu xâu (kiểu chuỗi) String
Kiểu logic bool
Kiểunull
Kiểu danh sách List tương tự như kiểu mảng arrays trong các ngôn ngữ khác
Kiểu tập hợp set
Kiểu map tương tự kiểu từ điển dict như trong Python
Kiểu ngày tháng DateTime
Kiểu dynamic là kiểu chấp nhận mọi kiểu dữ liệu khác, bạn có thể gán một giá trị là số, xâu, ngày tháng… cho biến kiểu dynamic
Ngoài ra còn có một số kiểu khác nữa như Uri hoặc Error. Chúng ta sẽ lần lượt tìm hiểu về các kiểu dữ liệu trong Dart này trong các bài tiếp theo của loạt bài Tự học lập trình Dart này.
2.1. Kiểu số num trong Dart
Kiểu số num trong Dart bao gồm có kiểu số nguyên int và kiểu số thực double, bài chi tiết xin mời các bạn xem tại đây Kiểu số trong Dart/Flutter
2.2. Kiểu logic bool trong Dart
2.3. Kiểu xâu String trong Dart
3. Phân biệt const và final trong Dart
Để khai báo một hằng số trong Dart, chúng ta sử dụng từ khóa const.
Để khai báo một biến chỉ nhận giá trị một lần và không thay đổi trong suốt chương trình, chúng ta sử dụng từ khóa final. Đương nhiên vẫn có thể sử dụng từ khóa var hoặc khai báo định kiểu cho biến đó, nhưng cách này không tối ưu bằng cách sử dụng final.
Mộtbiến không thay đổi trong suốt chương trình thì có gì khác hằng số, và đâu là sự khác nhau của hai cách khai báo này? Bạn sẽ hiểu rõ hơn điều này khi chúng ta thảo luận về lớp class ở những bài sau.
Có thể coi final và const đều biểu diễn cho các hằng số, nhưng const là hằng số trong lúc biên dịch (compile-time) còn finallà hằng số và sẽ nhận được trong lúc chạy chương trình run-time.
Để lập trình được bằng Flutter thì điều quan trọng là trước tiên bạn phải thành thạo Dart. Bởi xét cho cùng thì Flutter chỉ là một bộ công cụ (toolkit) sử dụng ngôn ngữ Dart để phát triển các ứng dụng đa nền tảng (cross platform).
Dart là ngôn ngữ lập trình được tối ưu hóa cho ứng dụng khách (client-optimized) để phát triển một cách nhanh chóng các ứng dụng trên mọi nền tảng (Android, iOS, Web và Desktop). Mục tiêu của nó là cung cấp ngôn ngữ lập trình hiệu quả nhất để phát triển đa nền tảng, kết hợp với nền tảng thời gian chạy thực thi linh hoạt cho các khung ứng dụng.
1. Cấu trúc chung của một chương trình Flutter/Dart
Một chương trình viết bằng Dart ít nhất phải có một hàm main(), như ví dụ dưới đây.
main() {
print("Hello World!");
}
Chương trình trên có sử dụng hàm print() – là một hàm được xây dựng sẵn của Dart, có chức năng in xâu nằm trong cặp ngoặc đơn ra ngoài màn hình. Kết quả thu được là dòng chữ Hello World! được in ra trên màn hình Console.
Hàm main() là một hàm đặc biệt, nó báo cho trình biên dịch Dart biết điểm bắt đầu để thực hiện chương trình. Hàm main() có thể được đặt ở vị trí đầu tiên hoặc cuối cùng của tệp mã nguồn Dart, nhưng khi thực thi nó sẽ được tìm và thực thi đầu tiên.
Ngoài ra thì một chương trình viết bằng Dart còn có các biến, các hàm, các câu chú thích, các câu lệnh điều khiển luồng, các lớp, các thư viện… Ví dụ sau là chương trình tính toán và in ra số Fibonacci thứ 20.
void main() {
var i = 20;
print(fibonacci(i));
}
int fibonacci(int n) {
if (n < 2) {
return n;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
Các quy ước của chương trình sử dụng ngôn ngữ Dart:
Dart có phân biệt chữ HOA và chữ thường
Cú pháp của Dart gần giống với Java, JavaScript, Python, C#
Mỗi câu lệnh của Dart kết thúc bằng dấu chấm phảy ;
Khác với Python, các lệnh trong Dart được viết mà các thành phần không bị ảnh hưởng bởi khoảng trắng
Một khối lệnh (nhiều câu lệnh, câu lệnh hợp thành) được bao trong cặp ngoặc móc { }
Chú thích trên một dòng được viết sau 2 dấu gạch chéo //
Chú thích trên nhiều dòng được đặt trong cặp dấu /* và */
Là ngôn ngữ lập trình hướng đối tượng, mọi thứ trong Dart đều là đối tượng (object)
Dart không có từ khóa public, private, protected khi khai báo phương thức, thuộc tính lớp. Nếu thuộc tính, tên lớp bắt đầu bằng _ thì hiểu đó là private
Các định danh (tên biến, tên hàm, tên lớp …) bắt đầu bằng chữ (a-zA-Z) hoặc _, theo sau là chuỗi chữ có thể kế hợp với số
Các từ có chỉ số trên 1 là các từ khóa theo ngữ cảnh , chỉ có nghĩa ở những nơi cụ thể. Chúng là số nhận dạng hợp lệ ở mọi nơi.
Các từ có chỉ số trên 2 là số nhận dạng được tích hợp sẵn . Để đơn giản hóa nhiệm vụ chuyển mã JavaScript sang Dart, các từ khóa này là số nhận dạng hợp lệ ở hầu hết các vị trí, nhưng chúng không thể được sử dụng làm tên lớp hoặc tên loại hoặc làm tiền tố nhập.
Các từ có chỉ số trên 3 là các từ dành riêng hạn chế liên quan đến hỗ trợ không đồng bộ . Bạn không thể sử dụng awaithoặc yieldnhư một định danh trong bất kỳ cơ quan chức năng đánh dấu async, async*hoặc sync*.
Tất cả các từ khác trong bảng là các từ dành riêng , không thể là số nhận dạng.
2. Cách chạy chương trình Flutter/Dart trên Windows
Dưới đây, O2 Education xin giới thiệu cách chạy một chương trình viết bằng ngôn ngữ Dart trên Windows.
2.1. Chạy chương trình Dart online
Cách dễ dàng nhất để học lập trình Dart (và từ đó là lập trình Flutter) là sử dụng các trình biên dịch Dart online. Có rất nhiều website cung cấp dịch vụ này, nhưng đơn giản nhất là DartPad
Format (Định dạng lại code cho đúng chuẩn): Shift+Ctrl+F
2.2. Chạy chương trình Dart với Visual Code
Khi bạn cài đặt phần mở rộng (extentions) Flutter trong VS Code thì phần mở rộng Dart cũng được mặc định cài luôn (như trong hình vẽ của tôi có cài đặt các gói mở rộng là Dart, Flutter, Jupyter và Python).
Sau khi cài đặt thành công, để tạo mới và chạy một chương trình Dart trong VS Code bạn thực hiện các bước sau:
Bấm tổ hợp phím tắt Ctrl + Shift + P và gõ Dart để tìm lệnh Dart: New Project để tạo mới một dự án viết bằng Dart.
Lựa chọn tiếp Console Application để tạo chương trình Dart với giao diện dòng lệnh (console)
Chọn tiếp thư mục để lưu dự án Dart và đặt tên cho chương trình. Ở đây tôi lưu tên dự án là heloo và lưu ở Desktop. Lúc này VS Code sẽ tạo sẵn cho chúng ta các thư mục và file mặc định như hình sau:
Để chạy chương trình Dart này, chúng ta bấm vào chữ Run, để gỡ lỗi chương trình chúng ta bấm vào Debug hoặc các nút hình tam giác ở góc trên bên phải. Kết quả thực thi chương trình được hiện ở khung phía dưới.