Skip to content
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Fx Studio
  • Home
  • Code
  • iOS & Swift
  • Combine
  • RxSwift
  • SwiftUI
  • Flutter & Dart
  • Tutorials
  • Art
  • Blog
Written by chuotfx on May 7, 2021

Multiplatform App : Design Views – SwiftUI Notes #23

SwiftUI

Contents

  • Chuẩn bị
  • 1. Create View
    • 1.1. Master View
    • 1.2. Detail View
    • 1.3. Navigation
  • 2. Running on MacOS & iPadOS
    • 2.1. MacOS
    • 2.2. iPadOS
  • 3. Adapts to the Platform
  • 4. Design Views
    • 4.1. Minimum width
    • 4.2. Master List
      • 4.2.1. Cells
      • 4.2.2. Model
      • 4.2.3. Build
    • 4.3. Tabbar
  • 5. Sidebar
    • 5.1. Create
    • 5.2. Toolbar
    • 5.3. Combine Views
    • 5.4. Build
  • Tạm kết

Chào bạn đến với series SwiftUI Notes của Fx Studio. Ở bài viết trước, ta đã tìm hiểu việc tạo một project Multiplatform App Template. Học cách cấu hình các View để chúng có thể hoạt động trên các nền tảng khác nhau. Tuy nhiên, chừng đó vẫn chưa đủ khi mỗi nền tảng lại yêu cầu sự khác nhau về mặt giao diện. Do đó, bài viết này sẽ tập trung vào việc Design Views cho đẹp với Multiplatform App của SwiftUI.

Nếu bạn chưa biết gì về SwiftUI, thì bạn có thể đọc thêm các bài viết thuộc series SwiftUI Notes tại đây. Còn nếu mọi thứ đã ổn rồi, thì …

Bắt đầu thôi!

Chuẩn bị

Về mặt tool và version, các bạn tham khảo như sau:

    • SwiftUI 2.0
    • Xcode 12

Ngoài ra, các bạn có thể checkout lại các project của các phần Multiplatform App trước tại đây. Vì lý do chúng ta sẽ phải xoá đi làm lại hơi nhiều thứ.

Về mặt kiến thức, yêu cầu bạn phải thông được phần trước của bài viết này. EZ Game!

    • SwiftUI App – Life Cycle
    • SwiftUI – The Apple Ecosystem

Về project demo, bạn có thể sử dụng lại project của bài viết trước. Hoặc tạo mới một project cũng không sao. Vì hầu như chúng ta làm lại 100% cho tất cả.

1. Create View

Chúng ta sẽ bắt đầu thiết kế một ứng dụng theo kiểu Master-Detail. Bao gồm:

  • Một view hiển thị một danh sách
  • Một view hiển thị chi tiết của cho mỗi phân tử trong danh sách

1.1. Master View

Bắt đầu, bạn tạo mới một file SwiftUI View và đặt tên là ListCategoriesView.swift, nó sẽ được tạo ở thư mục Share. Do đó, bạn chú ý tích chọn hết các Target có trong project.

Multiplatform App

Ta sẽ hiển thị một danh sách cực kì đơn giản với đối tượng List của SwiftUI và 1 array String. Bạn xem code ví dụ như sau:

struct ListCategoriesView: View {
    
    let categories = ["Ordinary Drink",
                      "Cocktail",
                      "Milk / Float / Shake",
                      "Other/Unknown",
                      "Cocoa",
                      "Shot",
                      "Coffee / Tea",
                      "Homemade Liqueur",
                      "Punch / Party Drink",
                      "Beer",
                      "Soft Drink / Soda"]
    
    var body: some View {
        List(categories, id: \.self) { category in
            Text(category)
        }
    }
}

(Chúng ta sẽ tìm hiểu về Danh sách trong SwiftUI ở phần sau nha. Ahihi!)

Sau đó, bạn nhất thử Resume để xem kết quả như thế nào.

Phần đầu tiên thất là quá đơn giản. EZ game!

1.2. Detail View

Tiếp theo, bạn cần phải tạo thêm một file SwiftUI View nữa và đặt tên là CategoryDetailView.swift. Và cũng làm đầy đủ thủ tục như file master. Code tham khảo như sau:

import SwiftUI

struct CategoryDetailView: View {
    
    var name: String
    
    init(name: String) {
        self.name = name
    }
    
    var body: some View {
        Text("Detail of \(name)")
            .navigationTitle(name)
    }
}

struct CategoryDetailView_Previews: PreviewProvider {
    static var previews: some View {
        CategoryDetailView(name: "ABC")
    }
}

1.3. Navigation

Ta cũng cần phải chỉnh sửa lại cho ListCategoriesView của chúng ta với một Navigation. Và cũng chính nhờ Navigation đó mà ta có thể di chuyển từ List sang Detail. Tham khảo code như sau.

var body: some View {
    NavigationView {
        List(categories, id: \.self) { category in
            Text(category)
        }
        .navigationTitle("Categories")
    }
}

Trong đó:

  • NavigationView được dùng làm đối tượng điều hướng
  • Title của NavigationBar sẽ được khai báo bằng việc gọi modifier .navigationTitle("Categories")

Cuối cùng, chúng ta sẽ dùng đối tượng NavigationLink để điều hướng từ màn hình này sang màn hình kia. Code ví dụ như sau:

var body: some View {
        NavigationView {
            List(categories, id: \.self) { category in
                NavigationLink(
                    destination: CategoryDetailView(name: category),
                    label: {
                        Text(category)
                    })
            }
            .navigationTitle("Categories")
        }
    }

Bạn hãy bấm Live Preview và cảm nhận kết qua nha.

2. Running on MacOS & iPadOS

Trước tiên, bạn hãy chỉnh sửa lại file App của project. Với mục đích đưa màn hình Master lên đầu tiên. Bạn truy cập vào file App ở Shared và thay ContentView bằng ListCategoriesView là ổn.

import SwiftUI

@main
struct TheCocktailApp: App {
    var body: some Scene {
        WindowGroup {
            ListCategoriesView()
        }
    }
}

2.1. MacOS

Ta đang design View với iOS. Và thử build ứng dụng lên MacOS xem như thế nào. Bạn hãy chọn lại scheme và build nha.

Giao diện của ứng dụng sẽ trông rất khác với iOS. Thậm chí còn khác suy nghĩ ban đầu của bạn. Khi hoạt động với MacOS cả Master & Detail đều xuất hiện ngay từ lúc đầu.

2.2. iPadOS

Và giao diện này sẽ hơi giống với việc bạn chạy app trên iPad. Bạn hãy Build với iPad và kiểm tra xem như thế nào.

  • Chế độ portrait

  • Chế độ landscape

Bạn cũng tự nhận ra sự tương đồng giữa các nền tảng trong cùng một hệ sinh thái rồi đấy.

Điều này có nghĩa là gì?

3. Adapts to the Platform

Đó chính là sự tương thích của SwiftUI cho từng nền tảng.

Về mặt giao diện, SwiftUI tự động điều chỉnh các đối tượng UI tương thích với nền tảng mà ứng dụng đang hoạt động. Ví dụ trên

  • Với iOS, đó là một màn hình với danh sách hiển thị. Người dùng kích vào mỗi item thì sẽ được điều hướng sang màn hình khác
  • Với MacOS, đó là một màn hình (window) với 1 sidebar là một danh sách. Detail sẽ ở phần bên cạnh
  • Còn với iPad (hay iPadOS), chúng sẽ kết hợp cả 2 đối với một chế độ.

Điều này có ý nghĩa gì?

  • Bạn chỉ cần học code một lần, hay viết code một lần. Và chúng sẽ hiển thị được với nhiều thiết bị
  • Nếu ứng dụng đơn giản thì bạn không cần quan tâm nhiều tới việc tuỳ biến code sao cho hợp lý. SwiftUI sẽ tự động làm việc đó.
  • Giảm tải đi thời gian phát triển ứng dụng, nhất là cho nhiều nền tảng

Tới được đây, mình hi vọng bạn đã cảm thấy được thế mạnh của SwiftUI mang lại với các nền tảng của Apple. Và biết đâu được, SwiftUI sẽ trở thành một chuẩn giao diện cho các nền khác Apple hay sao. Vì Apple đã cho Swift là mã nguồn mở từ khi nó được ra mắt rồi.

4. Design Views

Nhằm để thấy được sự khác nhau của giao diện với cùng một code SwiftUI khi chạy trên những nền tảng khác nhau của Apple. Chúng ta sẽ thực hiện việc demo bằng cách thiết kết thêm cho project những view mới.

4.1. Minimum width

Chắc ít nhiều bạn cũng đã sử dụng modifier .frame cho các SwiftUI View rồi. Trong số các tham số đó, thì minWidth , maxWidth , minHeight & maxHeight  có lẻ với bạn thì sẽ thấy nó ít tác dụng. Tuy nhiên, với môi trường là Multiplatform App thì đây là một trong những thuộc tính hay nhất.

Hình trên là ứng dụng của chúng ta khi chạy trên MacOS và lỡ tay kéo phần Master thu nhỏ lại quá. Và chúng ta mất nó luôn. Để khắc phục điều này ta sẽ dùng tới thuộc tính frame với tham số minWidth. Bạn update lại code của ListCategoriesView với modifier như sau.

var body: some View {
    NavigationView {
        List(categories, id: \.self) { category in
            NavigationLink(
                destination: CategoryDetailView(name: category),
                label: {
                    Text(category)
                })
        }
        .navigationTitle("Categories")
        .frame(minWidth: 300)
    }
    
}

Trong đó, bạn chỉ cần quan tâm tới frame(minWidth: 300). Nó sẽ định hình kích thước view của bạn. Ngoài minWidth thì chúng ta còn có maxWidth và cho chiều height nữa.

Build lại demo và xem kết quả nào.

Cho dù bị resize thế nào thì phần Master vẫn có một kích thức tối thiểu. Hi vọng, bạn sẽ tận dụng tối đa modifier trên cho các màn hình khác của Multiplatform App.

4.2. Master List

4.2.1. Cells

Ta sẽ làm lại Master với các cell (item) được define bằng một View riêng. Bạn tạo mới một file SwiftUI View và đặt tên là CategoryCell. Code ví dụ cho cell như sau:

import SwiftUI

struct CategoryCell: View {
    var item: Category
    var color = Color.black.opacity(0.5)
    @State var isActive = false
    
    init( item: Category) {
        self.item = item
    }
    
    var body: some View {
        ZStack(alignment: .bottom) {
            Image(item.thumbnail)
                .resizable()
                .frame(maxWidth: .infinity, minHeight: 100.0, maxHeight: 200.0)
                .clipped()
            Text(item.name)
                .frame(maxWidth: .infinity)
                .padding(.vertical, 5.0)
                .font(.title)
                .background(color)
                .foregroundColor(Color.white)
        }
        .clipShape(RoundedRectangle(cornerRadius: 10.0))
        .background(
            NavigationLink(
                destination: CategoryDetailView(name: item.name),
                isActive: $isActive,
                label: {
                    EmptyView()
                })
        )
        .onTapGesture {
            self.isActive.toggle()
        }
    }
}

struct CategoryCell_Previews: PreviewProvider {
    static var item = Category(name: "ABC", thumbnail: "img1")
    static var previews: some View {
        CategoryCell(item: item)
    }
}

Ta sẽ thêm các thiết kế cho cell như sau:

  • 1 thuộc tính item với kiểu dữ liệu là Category, chứa thông tin của cell
  • Giao diện bao gồm một Image & Text để hiển thị thông tin
  • Sự kiện khi người dùng tap vào cell thì sẽ di chuyển sang màn hình Detail.

4.2.2. Model

Về phần dữ liệu, bạn tạo thêm một file Swift và đặt tên là Category. Code ví dụ như sau:

struct Category: Identifiable {
    let id = UUID()
    var name: String
    var thumbnail: String
}

Quan trọng nhất là kế thừa protocol Identifiable. Nó giúp mỗi item trong array được định danh riêng biệt. Từ đó, đối tượng List sẽ tự động nhận biết vào re-use các cell cho phù hợp.

4.2.3. Build

Bạn mở file ListCategoriesView và thay đổi một tí cho List. Code ví dụ như sau:

struct ListCategoriesView: View {
    
    var categories = Category.getCategories()
    
    var body: some View {
        NavigationView {
            List(categories) { category in
                CategoryCell(item: category)
            }
            .frame(minWidth: 300.0)
            .navigationTitle("Categories")
        }
    }
}

Trong đó:

  • categories là array các Category. Ta dùng dummy data để làm dữ liệu hiển thị cho Master
  • Phần List thu gọn lại với array có sắn identifier
  • Điều hướng NaviagtionLink được đưa vào Cell

Ta build lại trên macOS để xem kết quả. Bạn cũng có thể build thêm trên iOS. Tuy nhiên, với iOS thì chúng ta quá quen rồi, không còn gì bất ngờ nữa.

Multiplatform App

Cuối cùng, bạn đã có một ứng dụng Master-Detail xịn sò trên MacOS rồi đó. Và cái nhìn đầu tiên của Multiplatform App cho sự khác như với Master-Detail trên iOS & MacOS là:

  • MacOS: Navigation sẽ hiển thị cả 2 view Master & Detail. Khi kích vào các cell trong Master thì Detail sẽ thay đổi. Ngoài ra, bạn có thể cung cấp một View Mặc định cho Detail lúc mới khởi tạo và chưa chọn cell nào.
  • iOS : sẽ chia ra 2 view riêng biệt. Một cho Master và một cho Detail. Khi kích vào cell trong Master thì Detail sẽ được push vào thông qua Navigation.

4.3. Tabbar

Để chứng kiến thêm sự khác nhau nữa của 2 nền tảng. Ta sẽ nâng cấp độ phức tạp của demo lên cấu trúc Tabbar. Trong đó:

  • Tabbar sẽ là View root của ứng dụng
  • Mỗi Tabbar sẽ là một Navigation Master-Detail

Bạn cần tạo mới một file SwiftUI View và đặt tên là Tabbar. Code cho Tabbar thì bạn tham khảo sau đây, cụ thể nó như thế nào thì chúng ta sẽ tìm hiểu ở phần tiếp theo của series.

struct Tabbar: View {
    var body: some View {
        // TABBAR
        TabView {
            // #1
            ListCategoriesView(title: "Cocktail")
            .tabItem {
                Label("Cocktail", systemImage: "heart.fill")
            }
            // #2
            ListCategoriesView(title: "Glass")
            .tabItem {
                Label("Glass", systemImage: "staroflife.circle")
            }
            // #3
            ListCategoriesView(title: "Alcoholic")
            .tabItem {
                Label("Alcoholic", systemImage: "atom")
            }
        }
    }
}

Để tiện cho việc nhận biết các Navigation của mỗi Categories thì mình thêm thuộc tính title và dùng nó để xét title cho NavigationBar. Và code update cho ListCategoriesView như sau:

struct ListCategoriesView: View {
    
    var categories = Category.getCategories()
    var title: String
    
    init(title: String) {
        self.title = title
    }
    
    var body: some View {
        NavigationView {
            List(categories) { category in
                CategoryCell(item: category)
            }
            .frame(minWidth: 300.0)
            .navigationTitle(title)
        }
    }
}

Cuối cùng, chúng ta sẽ cập nhật lại App File của project. Thay Tabbar cho ListCategoriesView.

@main
struct TheCocktailApp: App {
    var body: some Scene {
        WindowGroup {
            Tabbar()
        }
    }
}

Sau khi đã thêm các file và các view mới. Bạn tiến hành build ứng dụng lên iOS và MacOS nha.

  • iOS

Multiplatform App - iOS App

  • MacOS

Multiplatform App - MacOS App

Qua trên, bạn cũng nhân ra sự khác biệt về giao diện trên mỗi nền tảng cũng có lúc rất là lớn. Lần này, chúng ta không thể nào dùng chung một code SwiftUI để build chúng cho 2 nền tảng nữa rồi. Bây giờ, chúng ta cần tìm một lối đi mới cho Multiplatform App này.

5. Sidebar

Ta đã có design ứng dụng như trên. Tuy nhiên, về giao diện trên MacOS sẽ đem lại trải nghiệm người dùng không tốt bằng trên iOS. Do đó, ta sẽ thực hiện việc thay đổi tuỳ biến cho riêng macOS.

Trên macOS, chúng ta có một màn hình phụ nhỏ với tên là SideBar. Ta sẽ sử dụng nó để tối ưu giao diện ứng dụng.

5.1. Create

Bạn sẽ tạo mới 1 file SwiftUI View với tên là SideBar. Ngoài ra, vì view này chỉ dùng cho MacOS nên bạn chọn Target cho MacOS và đặt nó vào thư mục MacOS. Code tham khảo của nó như sau:

Bạn sẽ thêm một thuộc tính mới và mình đặt tên là sideBar. Code tham khảo như sau:

var sideBar: some View {
        List {
            NavigationLink(
                destination: ListCategoriesView(title: "Cocktail"),
                label: {
                    Label("Cocktail", systemImage: "heart.fill")
                })
            NavigationLink(
                destination: ListCategoriesView(title: "Glass"),
                label: {
                    Label("Glass", systemImage: "staroflife.circle")
                })
            NavigationLink(
                destination: ListCategoriesView(title: "Alcoholic"),
                label: {
                    Label("Alcoholic", systemImage: "atom")
                })
        }
        .frame(minWidth: 200)
        .listStyle(SidebarListStyle())
        .toolbar {
          // 4
          ToolbarItem {
            Button(action: toggleSideBar) {
              Label("Toggle Sidebar", systemImage: "sidebar.left")
            }
          }
        }
    }

Trong đó:

  • sideBar là một SwiftUI View với kiểu là some View
  • Ta cung cấp cho sideBar với nội dung là một đối tượng List
  • List này có 3 item. Chính là 3 Tab của Tabbar ở trên
  • Ta sẽ điều hướng khi kích vào 3 item đó tới 3 màn hình Master khác nhau
  • Bạn chú ý về listStyle(SidebarListStyle()) để xác định List của chúng ta là một SideBar
  • Về toolbar thì bạn chưa cần quan tâm.

5.2. Toolbar

Giờ thì chúng ta đi vào xem xét toolbar có những gì. Nó cũng khá giống với UIToolBar trong UIKit. Khi bạn muốn thêm các sự kiện vào thanh NavigationBar hoặc Toolbar.

Còn với phần sidebar này ta sẽ thêm 1 Button. Button này có nhiệm vụ ẩn hiện SideBar khi ứng dụng chạy trên MacOS. Bạn tiếp tục thêm đoạn code quản lý việc ẩn hiện SideBar như sau:

func toggleSideBar() {
  NSApp.keyWindow?.firstResponder?.tryToPerform(
    #selector(NSSplitViewController.toggleSidebar), with: nil)
}

(Cụ thể code đó như thế nào, chúng ta sẽ tìm hiểu ở phần sau của series nha. Giờ quá nhiều kiến thức được truyền tải tải rồi.)

5.3. Combine Views

Bây giờ, chúng ta sẽ kết hợp các phần trên lại để tạo giao diện theo ý muốn. Vẫn ở file Sidebar và chúng ta sẽ chỉnh sửa body như sau:

var body: some View {
    NavigationView {
        sideBar
        Text("Welcome to The Cocktail!")
            .foregroundColor(Color.white)
            .navigationTitle("Welcome")
    }
}

Trong đó:

  • Bạn có body là một NavigationView với 2 View con
  • sideBar sẽ hiển thị danh sách và nó nằm trong sideBar vì đã được xét style ở trên
  • Một màn hình detail phụ khi bắt đầu chạy ứng dụng. Lúc này chúng ta chưa chọn item nào trên Sidebar thì nó sẽ được hiển thị ở Detail

5.4. Build

Ta tiếp tục bằng việc build ứng dụng lên MacOS để kiểm tra xem SideBar hoạt động ra sao. Trước tiên, bạn cần cập nhật lại App File để có thể build được trên MacOS và chọn đúng SwiftUI View.

@main
struct TheCocktailApp: App {
    var body: some Scene {
        WindowGroup {
            #if os(macOS)
            Sidebar()
            #else
            Tabbar()
            #endif
        }
    }
}

(Bạn hãy sửa lại Target của Tabbar và di chuyển nó vào thư mục iOS. Vì lúc này nó chỉ có ý nghĩa cho iOS mà thôi)

Ta xem kết quả như sau:

  • Hiển thị SideBar

Multiplatform App - show SideBar

  • Ẩn SideBar

Multiplatform App - hide SideBar

Bây giờ, bạn đã có một ứng dụng Multiplatform App hoàn chỉnh với SwiftUI rồi. Nó có giao diện thích hợp với từng nền tảng khác nhau.

Tạm kết

  • Thiết kế hiển thị các View trên các nền tảng
  • Sự tính toán hợp lý về kích thước ứng dụng khi chạy trên mỗi nền tảng, tránh việc vỡ layout
  • Tạo ra sự khác biệt giữa giao diện để ứng dụng tương thích với mỗi nền tảng khác nhau
  • Sử dụng được SideBar cho MacOS và tuỳ biến SideBar
  • Sử dụng được Toolbar đơn giản

 

Okay! Tới đây, mình xin kết thúc bài viết về Design View cho Multiplatform App với SwiftUI. Và nếu có gì thắc mắc hay góp ý cho mình thì bạn có thể để lại bình luận hoặc gởi email theo trang Contact.

  • Bạn có thể checkout code tại đây.
  • Bài viết tiếp theo tại đây.

Cảm ơn bạn đã đọc bài viết này!

FacebookTweetPinYummlyLinkedInPrintEmailShares16

Related Posts:

  • feature_bg_swiftui_7
    Giới thiệu MapKit trên SwiftUI
  • Flutter
    Make color App Flutter
Tags: SwiftUI, SwiftUI Notes
Written by chuotfx

Hãy ngồi xuống, uống miếng bánh và ăn miếng trà. Chúng ta cùng nhau đàm đạo về đời, về code nhóe!

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Donate – Buy me a coffee!

Fan page

Fx Studio

Tags

Actor Advanced Swift AI api AppDistribution autolayout basic ios tutorial blog ci/cd closure collectionview combine concurrency crashlytics dart dart basic dart tour Declarative delegate deploy design pattern fabric fastlane firebase flavor flutter GCD gradients iOS MVVM optional Prompt engineering protocol Python rxswift safearea Swift Swift 5.5 SwiftData SwiftUI SwiftUI Notes tableview testing TravisCI unittest

Recent Posts

  • Role-playing vs. Persona-based Prompting
  • [Swift 6.2] Raw Identifiers – Đặt tên hàm có dấu cách, tại sao không?
  • Vibe Coding là gì?
  • Cách Đọc Sách Lập Trình Nhanh và Hiệu Quả Bằng GEN AI
  • Nỗ Lực – Hành Trình Kiến Tạo Ý Nghĩa Cuộc Sống
  • Ai Sẽ Là Người Fix Bug Khi AI Thống Trị Lập Trình?
  • Thời Đại Của “Dev Tay To” Đã Qua Chưa?
  • Prompt Engineering – Con Đường Để Trở Thành Một Nghề Nghiệp
  • Vấn đề Ảo Giác (hallucination) khi tương tác với Gen AI và cách khắc phục nó qua Prompt
  • Điều Gì Xảy Ra Nếu… Những Người Dệt Mã Trở Thành Những Người Bảo Vệ Cuối Cùng Của Sự Sáng Tạo?

You may also like:

  • Giới thiệu MapKit trên SwiftUI
    feature_bg_swiftui_7
  • Make color App Flutter
    Flutter

Archives

  • May 2025 (2)
  • April 2025 (1)
  • March 2025 (8)
  • January 2025 (7)
  • December 2024 (4)
  • September 2024 (1)
  • July 2024 (1)
  • June 2024 (1)
  • May 2024 (4)
  • April 2024 (2)
  • March 2024 (5)
  • January 2024 (4)
  • February 2023 (1)
  • January 2023 (2)
  • November 2022 (2)
  • October 2022 (1)
  • September 2022 (5)
  • August 2022 (6)
  • July 2022 (7)
  • June 2022 (8)
  • May 2022 (5)
  • April 2022 (1)
  • March 2022 (3)
  • February 2022 (5)
  • January 2022 (4)
  • December 2021 (6)
  • November 2021 (8)
  • October 2021 (8)
  • September 2021 (8)
  • August 2021 (8)
  • July 2021 (9)
  • June 2021 (8)
  • May 2021 (7)
  • April 2021 (11)
  • March 2021 (12)
  • February 2021 (3)
  • January 2021 (3)
  • December 2020 (3)
  • November 2020 (9)
  • October 2020 (7)
  • September 2020 (17)
  • August 2020 (1)
  • July 2020 (3)
  • June 2020 (1)
  • May 2020 (2)
  • April 2020 (3)
  • March 2020 (20)
  • February 2020 (5)
  • January 2020 (2)
  • December 2019 (12)
  • November 2019 (12)
  • October 2019 (19)
  • September 2019 (17)
  • August 2019 (10)

About me

Education, Mini Game, Digital Art & Life of coders
Contacts:
contacts@fxstudio.dev

Fx Studio

  • Home
  • About me
  • Contact us
  • Mail
  • Privacy Policy
  • Donate
  • Sitemap

Categories

  • Art (1)
  • Blog (44)
  • Code (11)
  • Combine (22)
  • Flutter & Dart (24)
  • iOS & Swift (102)
  • No Category (1)
  • RxSwift (37)
  • SwiftUI (80)
  • Tutorials (87)

Newsletter

Stay up to date with our latest news and posts.
Loading

    Copyright © 2025 Fx Studio - All rights reserved.