SwiftUI官方教程解讀

SwiftUI簡(jiǎn)介

SwiftUI是wwdc2019發(fā)布的一個(gè)新的UI框架芒涡,通過(guò)聲明和修改視圖來(lái)布局UI和創(chuàng)建流暢的動(dòng)畫(huà)效果峰尝。并且我們可以通過(guò)狀態(tài)變量來(lái)進(jìn)行數(shù)據(jù)綁定實(shí)現(xiàn)一次性布局订咸;Xcode 11 內(nèi)建了直觀的新設(shè)計(jì)工具canvus,在整個(gè)開(kāi)發(fā)過(guò)程中鸳玩,預(yù)覽可視化與代碼可編輯性能同時(shí)支持并交互缘琅,讓我們可以體驗(yàn)到代碼和布局同步的樂(lè)趣;同時(shí)支持和UIkit的交互

設(shè)計(jì)工具canvus
  • 開(kāi)發(fā)者可以在canvus中拖拽控件來(lái)構(gòu)建界面, 所編輯的內(nèi)容會(huì)立刻反應(yīng)到代碼上
  • 切換不同的視圖文件時(shí)canvus會(huì)切換到不同的界面
  • 點(diǎn)擊左下角的按鈕釘我們可以把視圖固定在活躍頁(yè)面
  • 選中canvus中的控件command+click可以調(diào)出inspect布局控件的屬性
  • 點(diǎn)擊右上角的+可以獲取新的控件并拖拽到對(duì)應(yīng)的位置
  • 在live狀態(tài)下我們可以在canvus中調(diào)試點(diǎn)擊等可交互效果 但不能縮放視圖大小
    每次修改或者增加屬性需要點(diǎn)擊resume刷新canvus
    landMarkDetail布局代碼見(jiàn)布局部分
文件結(jié)構(gòu)

創(chuàng)建一個(gè)SwiftUI文件,默認(rèn)生成兩個(gè)結(jié)構(gòu)體肘迎。一個(gè)實(shí)現(xiàn)view的協(xié)議,在body屬性里描述內(nèi)容和布局甥温;一個(gè)結(jié)構(gòu)體聲明預(yù)覽的view 并進(jìn)行初始化等信息,預(yù)覽view是控制器的view時(shí)可以顯示在多個(gè)模擬器設(shè)備妓布,是控件view時(shí)可以設(shè)置frame窿侈,預(yù)覽view是提供給canvus展示的,使用了#if DEBUG 指令,編譯器會(huì)刪除代碼,不會(huì)隨應(yīng)用程序一起發(fā)布

struct LandmarksList_Previews: PreviewProvider {
    static var previews: some View {
        ForEach(["iPhone SE", "iPhone XS Max"].identified(by: \.self)) { deviceName in
            LandmarkList()
                .previewDevice(PreviewDevice(rawValue: deviceName))
                .previewDisplayName(deviceName)
              //.previewLayout(.fixed(width: 300, height: 70)) 設(shè)置view控件大小
        }
        .environmentObject(UserData())
    }
}
#endif
布局

普通的view:將多個(gè)視圖組合并嵌入到堆棧中,這些堆棧將視圖水平秋茫、垂直或者前后組合在一起

VStack {  //這里的布局實(shí)現(xiàn)的是上圖canvus中l(wèi)andMarkDetail的效果
            MapView(coordinate: landmark.locationCoordinate)
                .frame(height: 300)//不傳width默認(rèn)長(zhǎng)度為整個(gè)界面
            CircleImage(image: landmark.image(forSize: 250))
                .offset(x: 0, y: -130)
                .padding(.bottom, -130)
            VStack(alignment: .leading) {
                Text(landmark.name)
                    .font(.title)
                HStack(alignment: .top) {
                    Text(landmark.park)
                        .font(.subheadline)
                    Spacer() //將水平的兩個(gè)控件撐開(kāi)
                    Text(landmark.state)
                        .font(.subheadline)
                }
            }
            .padding()
            Spacer()
        }

列表的布局:要求數(shù)據(jù)是可被標(biāo)識(shí)的
(1)唯一標(biāo)識(shí)每個(gè)元素的主鍵路徑

 List(landmarkData.identified(by: \.id)) { landmark in
            LandmarkRow(landmark: landmark)
        }

(2)數(shù)據(jù)類型實(shí)現(xiàn)Identifiable protocol,持有一個(gè)id 屬性

struct Landmark: Hashable, Codable, Identifiable {
    var id: Int  //
    var name: String
    fileprivate var imageName: String
    fileprivate var coordinates: Coordinates
    var state: String
    var park: String
    var category: Category
}
  List(landmarkData) { landmark in
            LandmarkRow(landmark: landmark)
        }  //直接傳數(shù)據(jù)源
導(dǎo)航

添加導(dǎo)航欄是將其嵌入到NavigationView中,點(diǎn)擊跳轉(zhuǎn)的控件包裝在navigationButton中,以設(shè)置到目標(biāo)視圖的換位史简。navigationBarTitle設(shè)置導(dǎo)航欄的標(biāo)題,navigationBarItems設(shè)置導(dǎo)航欄右邊的item

  NavigationView {//顯示導(dǎo)航view
            List {
                  //SwiftUI里面的類似switch的控件,可以在list中直接組合布局
                 Toggle(isOn: $showFavoritesOnly) {
                    Text("Favorites only")
                 }
                ForEach(landmarkData) { landmark in
                    if !self.showFavoritesOnly || landmark.isFavorite {
                         //跳轉(zhuǎn)到地標(biāo)詳細(xì)頁(yè)面
                        NavigationButton(destination: LandmarkDetail(landmark: landmark)) {
                            LandmarkRow(landmark: landmark)
                        }
                    }
                }
            }
            .navigationBarTitle(Text("Landmarks"))//導(dǎo)航標(biāo)題
        }
    }

實(shí)現(xiàn)modal出一個(gè)view

  .navigationBarItems(trailing:
               //點(diǎn)擊navigationBarItems modal出profileHost頁(yè)面
                PresentationButton(
                    Image(systemName: "person.crop.circle")
                        .imageScale(.large)
                        .accessibility(label: Text("User Profile"))
                        .padding(),
                    destination: ProfileHost()
                )
            )

程序運(yùn)行是從sceneDelegate定義的根視圖開(kāi)始的圆兵, UIhostingController 是UIViewController的子類

動(dòng)畫(huà)效果

SwiftUI包括帶有預(yù)定義或自定義的基本動(dòng)畫(huà) 以及彈簧和流體動(dòng)畫(huà)跺讯,可以調(diào)整動(dòng)畫(huà)速度,設(shè)置延遲殉农,重復(fù)動(dòng)畫(huà)等等
可以通過(guò)在一個(gè)動(dòng)畫(huà)修改器后面添加另一個(gè)動(dòng)畫(huà)修改器來(lái)關(guān)閉動(dòng)畫(huà)

  • 轉(zhuǎn)場(chǎng)動(dòng)畫(huà)
    系統(tǒng)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)調(diào)用: hikeDetail(hike.hike).transition(.slide)
    自定義的轉(zhuǎn)場(chǎng)動(dòng)畫(huà):把轉(zhuǎn)場(chǎng)動(dòng)畫(huà)作為AnyTransition類的類型屬性 (方便點(diǎn)語(yǔ)法設(shè)置豐富自定義動(dòng)畫(huà))
extension AnyTransition {
    static var moveAndFade: AnyTransition {
        let insertion = AnyTransition.move(edge: .trailing)
            .combined(with: .opacity)
        let removal = AnyTransition.scale()
            .combined(with: .opacity)
        return .asymmetric(insertion: insertion, removal: removal)
    }
}

HikeDetail(hike: hike).transition(.moveAndFade)調(diào)用轉(zhuǎn)場(chǎng)動(dòng)畫(huà)刀脏;move(edge:)方法是讓視圖從同一邊滑出來(lái)以及消失;asymmetric(insertion:removal:)設(shè)置出現(xiàn)和小時(shí)的不同的動(dòng)畫(huà)效果

  • 阻尼動(dòng)畫(huà)
var animation: Animation {  //定義成存儲(chǔ)屬性方便調(diào)用
        Animation.spring(initialVelocity: 5)//重力效果,值越大,彈性越大
            .speed(2)//動(dòng)畫(huà)時(shí)間,值越大動(dòng)畫(huà)速度越快
            .delay(0.03 * Double(index))
    }
  • 基礎(chǔ)動(dòng)畫(huà)
                Button(action: //點(diǎn)擊按鈕顯示一個(gè)view帶轉(zhuǎn)場(chǎng)的動(dòng)畫(huà)效果
                    withAnimation {
                        self.showDetail.toggle()
                    }
                }) {
                    Image(systemName: "chevron.right.circle")
                        .imageScale(.large)
                        //旋轉(zhuǎn)90度
                        .rotationEffect(.degrees(showDetail ? 90 : 0))
                        //.animation(nil) //關(guān)閉前面的旋轉(zhuǎn)90度的動(dòng)畫(huà)效果超凳,只顯示下面的動(dòng)畫(huà)
                       //選中的時(shí)候放大為原來(lái)的1.5倍
                        .scaleEffect(showDetail ? 1.5 : 1)
                        .padding()
                      //  .animation(.basic()) 實(shí)現(xiàn)簡(jiǎn)單的基礎(chǔ)動(dòng)畫(huà)
                        //.animation(.spring()) 阻尼動(dòng)畫(huà)
                    
                }

給圖片按鈕加動(dòng)畫(huà)效果愈污, 對(duì)應(yīng)的會(huì)有旋轉(zhuǎn)和縮放會(huì)有動(dòng)畫(huà);加到action時(shí)轮傍,即使點(diǎn)擊完成后的顯示沒(méi)有給image的可做動(dòng)畫(huà)屬性加動(dòng)畫(huà)效果暂雹,全部都有動(dòng)畫(huà),包含旋轉(zhuǎn)縮放和轉(zhuǎn)場(chǎng)動(dòng)畫(huà)

數(shù)據(jù)流

利用SwiftUI環(huán)境中的存儲(chǔ) 创夜,把自定義數(shù)據(jù)對(duì)象綁定到view 杭跪,SwiftUI監(jiān)視到可綁對(duì)象任何影響視圖的更改并在更改后顯示正確的視圖

  • 自定義綁定類型
    聲明為綁定類型 BindableObject ,PassthroughSubject是Combine框架的消息發(fā)布者, SwiftUI通過(guò)這個(gè)消息發(fā)布者訂閱對(duì)象,并在數(shù)據(jù)發(fā)生變化的時(shí)候更新任何需要刷新的視圖
import Combine
import SwiftUI
final class UserData: BindableObject {
    let didChange = PassthroughSubject<UserData, Never>()
    
    var showFavoritesOnly = false {
        didSet {
            didChange.send(self)
        }
    }

    var landmarks = landmarkData {
        didSet {
            didChange.send(self)
        }
    }
}

當(dāng)客戶機(jī)需要更新數(shù)據(jù)的時(shí)候,可綁定對(duì)象通知其訂閱者
eg:當(dāng)其中一個(gè)屬性發(fā)生更改時(shí),在屬性的didset里面通過(guò)didchange發(fā)布者發(fā)布更改

  • 綁定屬性
    (1)state
@State var profile = Profile.default

狀態(tài)是隨時(shí)間變化影響頁(yè)面布局內(nèi)容和行為的值
給定類型的持久值驰吓,視圖通過(guò)該持久值讀取和監(jiān)視該值涧尿。狀態(tài)實(shí)例不是值本身;它是讀取和修改值的一種方法。若要訪問(wèn)狀態(tài)的基礎(chǔ)值檬贰,請(qǐng)使用其值屬性姑廉。
(2)binding

@Binding var profile: Profile//向子視圖傳遞數(shù)據(jù)

(3)environmentObject :

@EnvironmentObject var userData: UserData

存儲(chǔ)在當(dāng)前環(huán)境中的數(shù)據(jù),跨視圖傳遞翁涤,在初始化持有對(duì)象的時(shí)候使用environmentObject(_:)賦值可以和前面的自定義綁定類型一起使用

let window = UIWindow(frame: UIScreen.main.bounds)
         window.rootViewController = UIHostingController(rootView: CategoryHome().environmentObject(UserData()))
  • 綁定行為
    是對(duì)可變狀態(tài)或數(shù)據(jù)的引用桥言,用$的前綴訪問(wèn)狀態(tài)變量或者其屬性之一實(shí)現(xiàn)綁定控件 也可以訪問(wèn)綁定屬性來(lái)實(shí)現(xiàn)綁定
與UIkit的交互

表示UIkit的view和controller 需要?jiǎng)?chuàng)建遵UIViewRepresentable或者UIViewControllerRepresentable協(xié)議的結(jié)構(gòu)體,SwiftUI管理他們的生命周期并在需要的時(shí)候更新
實(shí)現(xiàn)協(xié)議方法:

//創(chuàng)建展示的UIViewController,調(diào)用一次
func makeUIViewController(context: Self.Context) -> Self.UIViewControllerType
//將展示的UIViewController更新到最新的版本
 func updateUIViewController(_ uiViewController: Self.UIViewControllerType, context: Self.Context)
//創(chuàng)建協(xié)調(diào)器
 func makeCoordinator() -> Self.Coordinator

在結(jié)構(gòu)體內(nèi)嵌套定義一個(gè)coordinator類迷雪。SwiftUI管理coordinator并把它提供給context ,在makeUIView(context:)之前調(diào)用這個(gè)makeCoordinator()方法創(chuàng)建協(xié)調(diào)器,以便在配置視圖控制器的時(shí)候可以訪問(wèn)coordinator對(duì)象
我們可以使用這個(gè)協(xié)調(diào)器來(lái)實(shí)現(xiàn)常見(jiàn)的Cocoa模式虫蝶,例如委托章咧、數(shù)據(jù)源和通過(guò)目標(biāo)操作響應(yīng)用戶事件

這里以用UIPageViewController實(shí)現(xiàn)輪播圖為例,要注意其中的更新頁(yè)面的邏輯~

pageview作為主view能真,組合一個(gè)PageControl 和 PageViewController實(shí)現(xiàn)圖片輪播效果
PageView: @State var currentPage = 1 定義綁定屬性 赁严,$currentPage實(shí)現(xiàn)綁定到PageViewController
PageViewController: @Binding var currentPage: Int 定義綁定屬性,在更新的方法updateUIViewController里面綁定顯示粉铐,點(diǎn)擊pagecontrol的更新頁(yè)面時(shí)pageviewcontroller可以更新到最新的頁(yè)面
pagecontrol: @Binding var currentPage: Int定義綁定屬性 疼约,updateUIView 綁定顯示,pageview滑動(dòng)更新頁(yè)面 pagecontrol可以更新到正確的顯示

struct PageView<Page: View>: View {
    var viewControllers: [UIHostingController<Page>]
    @State var currentPage = 1

    init(_ views: [Page]) {//傳入的view用SwiftUI的controller包裝好后面?zhèn)鹘opagecontroller
        self.viewControllers = views.map { UIHostingController(rootView: $0) }
    }

    var body: some View {
        ZStack(alignment: .bottomTrailing) {//將currentpage綁定起來(lái)了
            PageViewController(controllers: viewControllers, currentPage: $currentPage)
            PageControl(numberOfPages: viewControllers.count, currentPage: $currentPage)
                .padding()
             //Text("Current Page: \(currentPage)").padding(.trailing,30)
        }
    }
}
import SwiftUI
import UIKit
struct PageViewController: UIViewControllerRepresentable {
    var controllers: [UIViewController]
    @Binding var currentPage: Int

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }
    func makeUIViewController(context: Context) -> UIPageViewController {
        let pageViewController = UIPageViewController(
            transitionStyle: .scroll,
            navigationOrientation: .horizontal)
        pageViewController.dataSource = context.coordinator
        pageViewController.delegate = context.coordinator

        return pageViewController
    }
    func updateUIViewController(_ pageViewController: UIPageViewController, context: Context) {
       //pageviewcontroller綁定currentpage顯示當(dāng)前的頁(yè)面蝙泼,pageView變化的時(shí)候程剥,page更新頁(yè)面
        pageViewController.setViewControllers(
            [controllers[currentPage]], direction: .forward, animated: true)

    }
    class Coordinator: NSObject, UIPageViewControllerDataSource, UIPageViewControllerDelegate {
        var parent: PageViewController

        init(_ pageViewController: PageViewController) {
            self.parent = pageViewController
        }
      //左滑顯示控制
        func pageViewController(
            _ pageViewController: UIPageViewController,
            viewControllerBefore viewController: UIViewController) -> UIViewController? {
            guard let index = parent.controllers.firstIndex(of: viewController) else {
                return nil
            }
            if index == 0 {
                return parent.controllers.last
            }
            return parent.controllers[index - 1]
        }
       // 右滑動(dòng)顯示控制
        func pageViewController(
            _ pageViewController: UIPageViewController,
            viewControllerAfter viewController: UIViewController) -> UIViewController? {
            guard let index = parent.controllers.firstIndex(of: viewController) else {
                return nil
            }
            if index + 1 == parent.controllers.count {
                return parent.controllers.first
            }
            return parent.controllers[index + 1]
        }
        func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) {
            if completed,
                let visibleViewController = pageViewController.viewControllers?.first,
                let index = parent.controllers.firstIndex(of: visibleViewController) {
               //當(dāng)view滑動(dòng)停止的時(shí)候告訴pageview當(dāng)前頁(yè)面的index(數(shù)據(jù)變化 pageview更新pagecontrol的展示)
                parent.currentPage = index
            }
        }
    }
}
struct PageControl: UIViewRepresentable {
    var numberOfPages: Int
    @Binding var currentPage: Int

    func makeCoordinator() -> Coordinator {
        Coordinator(self)
    }

    func makeUIView(context: Context) -> UIPageControl {
        let control = UIPageControl()
        control.numberOfPages = numberOfPages
        control.addTarget(
            context.coordinator,
            action: #selector(Coordinator.updateCurrentPage(sender:)),
            for: .valueChanged)

        return control
    }

    func updateUIView(_ uiView: UIPageControl, context: Context) {
        uiView.currentPage = currentPage
    }

    class Coordinator: NSObject {
        var control: PageControl

        init(_ control: PageControl) {
            self.control = control
        }

        @objc
        func updateCurrentPage(sender: UIPageControl) {
            control.currentPage = sender.currentPage
        }
    }
}

\color{rgb(150,90,150)}{QA}: 當(dāng)我們編輯一部分用戶數(shù)據(jù)的時(shí)候,我們不希望在編輯數(shù)據(jù)完成的時(shí)候影響到其他的頁(yè)面 那么我們需要?jiǎng)?chuàng)建一個(gè)副本數(shù)據(jù)汤踏, 當(dāng)副本數(shù)據(jù)編輯完成的時(shí)候 用副本數(shù)據(jù)更新真正的數(shù)據(jù)织鲸, 使相關(guān)的頁(yè)面變化 這部分的內(nèi)容參見(jiàn)demo中profiles的部分舔腾;對(duì)于畫(huà)圖的部分demo中也有非常酷炫的示例搂擦,詳情參見(jiàn) HikeGraph稳诚、Badge(徽章)

參考資料

Apple官網(wǎng)教程 :https://developer.apple.com/tutorials/swiftui/creating-and-combining-views
demo下載
SwiftUI documentation

作者簡(jiǎn)介

就職于甜橙金融(翼支付)信息技術(shù)部,負(fù)責(zé) iOS 客戶端開(kāi)發(fā)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末瀑踢,一起剝皮案震驚了整個(gè)濱河市扳还,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌橱夭,老刑警劉巖氨距,帶你破解...
    沈念sama閱讀 217,907評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異徘钥,居然都是意外死亡衔蹲,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,987評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門呈础,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)舆驶,“玉大人,你說(shuō)我怎么就攤上這事而钞∩沉” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,298評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵臼节,是天一觀的道長(zhǎng)撬陵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)网缝,這世上最難降的妖魔是什么巨税? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,586評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮粉臊,結(jié)果婚禮上草添,老公的妹妹穿的比我還像新娘。我一直安慰自己扼仲,他們只是感情好远寸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,633評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著屠凶,像睡著了一般驰后。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上矗愧,一...
    開(kāi)封第一講書(shū)人閱讀 51,488評(píng)論 1 302
  • 那天灶芝,我揣著相機(jī)與錄音,去河邊找鬼。 笑死监署,一個(gè)胖子當(dāng)著我的面吹牛颤专,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播钠乏,決...
    沈念sama閱讀 40,275評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼栖秕,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了晓避?” 一聲冷哼從身側(cè)響起簇捍,我...
    開(kāi)封第一講書(shū)人閱讀 39,176評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎俏拱,沒(méi)想到半個(gè)月后暑塑,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,619評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡锅必,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,819評(píng)論 3 336
  • 正文 我和宋清朗相戀三年事格,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片搞隐。...
    茶點(diǎn)故事閱讀 39,932評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡驹愚,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出劣纲,到底是詐尸還是另有隱情逢捺,我是刑警寧澤,帶...
    沈念sama閱讀 35,655評(píng)論 5 346
  • 正文 年R本政府宣布癞季,位于F島的核電站劫瞳,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏绷柒。R本人自食惡果不足惜志于,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,265評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望废睦。 院中可真熱鬧伺绽,春花似錦、人聲如沸郊楣。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,871評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)净蚤。三九已至,卻和暖如春输硝,著一層夾襖步出監(jiān)牢的瞬間今瀑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,994評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留橘荠,地道東北人屿附。 一個(gè)月前我還...
    沈念sama閱讀 48,095評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像哥童,于是被迫代替她去往敵國(guó)和親挺份。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,884評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • SwiftUI簡(jiǎn)介 SwiftUI是wwdc2019發(fā)布的一個(gè)新的UI框架贮懈,通過(guò)聲明和修改視圖來(lái)布局UI和創(chuàng)建流暢...
    iridescentzc閱讀 7,864評(píng)論 1 16
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒(méi)有地址/指針的概念1.2> 泛型1.3> 類型嚴(yán)謹(jǐn) 對(duì)...
    cosWriter閱讀 11,101評(píng)論 1 32
  • 翻譯自“Collection View Programming Guide for iOS” 0 關(guān)于iOS集合視...
    lakerszhy閱讀 3,864評(píng)論 1 22
  • 寫(xiě)這篇文章是因?yàn)槟昵澳旰蠖紴楹糜押退瞎氖虑閾?dān)憂著匀泊。好友年芳33,好不容易和談了2年多的男友結(jié)婚朵你「髌福可結(jié)婚不到仨月...
    李聘2023閱讀 175評(píng)論 0 1
  • 俗話說(shuō)男怕入錯(cuò)行躲因,女怕嫁錯(cuò)郎〖缮担“捍舐觯枯石爛心不變”早已成古董。這句話也已經(jīng)不再適合現(xiàn)在的社會(huì)芯勘, 在婚姻關(guān)系中箱靴,女性一...
    時(shí)間的沙灘閱讀 840評(píng)論 0 0