SwiftUIミニマリストチュートリアル39:ColourAtlaカラーカードアプリを作成する

この章では、カラーカードの使用方法URLSessionContextMenu作成方法を学習しますColourAtlaApp

プロジェクトの背景

長い間、繁体字中国語の色には特別な支持がありました。

いくつかの情報を閲覧していると、ブロガーがリリースしたカラーカードの概念について話しているカラーマッチングコンテンツをいくつか見ました。ある程度の理解と学習の後、カラーマッチングアプリを作成したいと思いました

まだApp完全には開発されていませんが、開発者の助けになることを願って、完成した機能構築方法のいくつかをここで共有しますSwiftUI

それで、それ以上の苦労なしに、始めましょう。

プロジェクト建設

まず、という名前の新しいSwiftUIプロジェクトを作成しますColourAtla

1.png

ページビルド

ページの構成を簡単に分析してみましょう。TitleタイトルとカラーカードListリストで構成されています。次に、カラーカードリストで1枚のカラーカードを長押しすると、フローティングウィンドウ効果が得られます。

基本的なコンポーネントを理解した後、コンテンツを1つずつ作成していきましょう。

タイトル構成

OpaqueTypes1つ目は、不透明(OPAQUE)型の方法を使用して作成したヘッダーセクションViewです。例:

//MARK: 标题

private var CardTitleView: some View {
    Text("世界最高级的颜色")
        .font(.system(size: 17))
        .fontWeight(.bold)
}

2.png

上記のコードでは、プライベートビューを宣言してから、CardTitleView必要なタイトルをText作成し、いくつかの修飾子を使用してコンテンツを調和させています。

カラーエクステンション

タイトルを作成したら、カラーカードリストを作成しましょう。カラーカードを作成する前に、16進数のカラー値を使用するために、既存のColorカラー作成方法Extensionを拡張してみましょう。例:

我们创建一个新的Swift文件,命名为ColorHexString

import SwiftUI

extension Color {
    static func rgb(_ red: CGFloat, green: CGFloat, blue: CGFloat) -> Color {
        return Color(red: red / 255, green: green / 255, blue: blue / 255)
    }
    static func Hex(_ hex: UInt) -> Color {
        let r: CGFloat = CGFloat((hex & 0xFF0000) >> 16)
        let g: CGFloat = CGFloat((hex & 0x00FF00) >> 8)
        let b: CGFloat = CGFloat(hex & 0x0000FF)
        return rgb(r, green: g, blue: b)
    }
}

3.png

上述代码中,我们给Color进行了Extension扩展。

我们通过接收一个UInt十六进制颜色值,然后把它转换成RGB颜色值,这样我们只需要输入十六进制颜色值,Color就可以转换为可以使用的RGB颜色值了。

单张色卡

接下来,我们回到ContentView文件,先来构建单张色卡。示例:

// MARK: 卡片视图

struct CardViewExamples: View {

    var body: some View {
        ZStack(alignment: Alignment(horizontal: .center, vertical: .center), content: {

            // 背景卡片
            Rectangle()
                .fill(Color.Hex(0xFF0000))
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: 110)
                .cornerRadius(8)

            HStack {
                VStack(alignment: .leading, spacing: 10) {

                    //颜色名称
                    Text("中国红")
                        .fontWeight(.bold)
                        .foregroundColor(Color.white)
                        .font(.system(size: 17))
                    // 颜色值
                    Text("#FF0000")
                        .fontWeight(.bold)
                        .foregroundColor(Color.white)
                        .font(.system(size: 14))
                }
                Spacer()
            }.padding()
        })
    }
}

4.png

上述代码中,我们使用Struct构造体创建视图的方式构建了单张色卡的内容。

在单张色卡,我们构建了一个Rectangle矩形作为背景,然后填充了一个“中国红”,顺便调整了它的大小和圆角。

依此再构建了两个Text,作为颜色名称颜色值,最后使用ZStack将三个元素组成一个整体。

为什么需要使用Struct构造体的方式,而不使用OpaqueTypes不透明类型的方法,这是因为我们构建的色卡之后需要提取参数出来,然后在ContentView视图中遍历多张色卡,因此使用Struct构造体的方式创建视图。

参数抽离

接下拉,为了更加方便地遍历出多张色卡,我们将相同的参数进行抽离替换。

在色卡列表中,我们抽离色卡背景色、色卡颜色名称、色卡颜色值3个参数,示例:

var cardBGColor: Color
var cardColorName: String
var cardColorRBG: String

抽离出参数后,由于我们没有给CardViewExamples构造体中的参数赋值,因此我们在ContentView视图调用时需要补充参数对应的参数值。

CardViewExamples(cardBGColor: Color.Hex(0xFF0000), cardColorName: "中国红", cardColorRBG: "#FF0000")

5.png

悬浮窗口

单张色卡完成后,我们来尝试完成长按色卡唤起悬浮窗口并实现复制颜色值

在之前的章节中,我们学习过ContextMenu上下文菜单的使用,在这里我们依旧使用的是ContextMenu上下文菜单构建悬浮窗口。示例:

// 长按复制颜色值
    .contextMenu {
        Button(action: {
            UIPasteboard.general.string = cardColorName
            }, label: {
                Text("复制颜色值")
                })
            }
            .padding(.horizontal)

6.png

上述代码中,我们使用ContextMenu上下文菜单创建了悬浮窗口。

当我们长按单张色卡时,我们就把cardColorName卡片颜色值的内容复制到剪切板中,这样我们就实现了通过长按复制色卡颜色值的交互。

数据模型

模型创建

完成单张色卡创建后,我们需要根据单张色卡的内容遍历多张色卡,通用的方式是创建模型数组,再根据模型数组结合网络请求,获得放在服务端的Json数据,然后再在本地渲染

我们创建一个Swift文件,命名为Model.swift

import SwiftUI

struct CardModel:Decodable {
    var cardBGColor: UIn
    var cardColorName: String
    var cardColorRBG: String
}

9.png

上述代码中,我们创建了一个结构体CardModel,遵循Decodable协议。

Decodable协议,用于将JSON对象解析为结构体或类,这样我们就可以通过网络请求获得JSON对象,然后通过Decodable协议解析在本地。

由于我们的色卡背景颜色是十六进制的颜色值,因此cardBGColor参数需要声明为UInt类型,其他cardColorNamecardColorRBG都是String字符串类型。

我们回到ContentView文件中,首先我们先获得定义好的CardModel结构体。

@State var cardItems: [CardModel] = []

然后,我们使用OpaqueTypes不透明类型的方法创建一个卡片视图,我们将CardListView视图展示在ContentView中展示。

// MARK: 色卡列表视图

private var CardListView: some View {
    ScrollView(.vertical, showsIndicators: false, content: {
        ForEach(cardItems, id: \.cardColorRBG) { item in
            VStack(spacing: 20) {
                CardViewExamples(cardBGColor: Color.Hex(item.cardBGColor), cardColorName: item.cardColorName, cardColorRBG: item.cardColorRBG)
            }
        }
    })
}

10.png

这样,色卡列表视图的框架就创建好了。

但是我们在预览时没有看到色卡,这是因为我们的色卡列表视图只是搭建了框架,但是没有数据,下面我们来完成数据部分

Json数据

色卡框架搭建好后,我们在云端创建好Json数据。

[
{"cardBGColor":16711680,"cardColorRBG":"#FF0000","cardColorName":"中国红"},
{"cardBGColor":15226919,"cardColorRBG":"#E85827","cardColorName":"爱马仕橙"},
{"cardBGColor":16439902,"cardColorRBG":"#FADA5E","cardColorName":"拿破里黄"},
{"cardBGColor":35980,"cardColorRBG":"#008C8C","cardColorName":"马尔斯绿"},
{"cardBGColor":3175035,"cardColorRBG":"#30727B","cardColorName":"不来梅蓝"},
{"cardBGColor":6901074,"cardColorRBG":"#694D52","cardColorName":"莫兰迪色"},
{"cardBGColor":5338771,"cardColorRBG":"#517693","cardColorName":"马耳他蓝"},
{"cardBGColor":12199,"cardColorRBG":"#002FA7","cardColorName":"克菜因蓝"}
]

11.png

上述代码中,我们在某平台创建了Json数据,并且获得了可以访问Json数据的API接口。

我们将API接口地址复制,并在ContentView中声明一个常量存储它。

let JsonURL = "https://api.npoint.io/dc5a1718e0e958613ade"

网络请求

APIインターフェースを使用して、ローカルカラーカードリストビューフレームワークも確立されます。次のステップは、ネットワーク要求部分を完了することです。

// MARK: 网络请求

func getColors() {
    let session = URLSession(configuration: .default)
    session.dataTask(with: URL(string: JsonURL)!) { data, _, _ in
        guard let jsonData = data else { return }
        do {
            let colors = try JSONDecoder().decode([CardModel].self, from: jsonData)
            self.cardItems = colors
        } catch {
            print(error)
        }
    }
    .resume()
}

12.png

上記のコードでは、ネットワークリクエストメソッドを作成しますgetColors。公式のURLSessionネットワークリクエストフレームワークを使用して、URLアドレスのデータを取得し、データJsonURLJSONDecoder解析して配列内のパラメータとjsonデータを照合します。CardModel照合後、データを保存します。cardItemsの 。

ContentViewビューが表示されたときにgetColorsメソッドを呼び出します。

.onAppear(perform: {
    getColors()
})

シミュレータで実行操作をクリックして、効果をプレビューします。

13.png

読み込み中

ネットワークリクエストには時間がかかるColourAtlaため、カラーカードのエクスペリエンスを向上させるためにAppカラーカードリストビューがロードされていない場合のデフォルトの表示としてビューを追加できます。例:Loading

if cardItems.isEmpty {
    Spacer()
    ProgressView()
    Spacer()
} else {
    CardListView
}

14.png

最後に全体的な効果をプレビューします。

15.png

この章は以上です。

是非、お試しください!

このコラムがお役に立てば、いいね、コメント、フォローしてください〜

ナゲッツテクノロジーコミュニティのクリエイター署名プログラムの募集に参加しています。リンクをクリックして登録し、送信してください。

おすすめ

転載: juejin.im/post/7116043069673177118