純SwiftUI實(shí)現(xiàn)PageView(無UIView轉(zhuǎn)接)

上文實(shí)現(xiàn)了使用UIScrollView轉(zhuǎn)接的PageView,但其性能有些弱

本文將介紹純SwiftUI實(shí)現(xiàn)的PageView


import Foundation
import SwiftUI

// new PageView in Pure SwiftUI

struct PageView<ViewBuilerContent: View>: View {
    
    @Binding var currentPage: CGFloat
    let contentGetter: () -> [ViewBuilerContent]
    
    init(currentPage: Binding<CGFloat>, @MyViewBuilder content: @escaping (() -> [ViewBuilerContent])) {
        _currentPage = currentPage
        contentGetter = content
    }
    
    private class PageCache {
        var size: CGSize = .zero
        var page: Int = 0
        var offset: CGSize = .zero
    }
    @State private var pageCache: PageCache = PageCache()
    @State private var bounceOffset: CGFloat = 0
    @State private var contentOffset: CGSize = .zero {
        didSet {
            if pageCache.size.width > 0 {
                currentPage = (contentOffset.width - bounceOffset) / pageCache.size.width
            }
        }
    }
    
    var body: some View {
        GeometryReader { geo in
            let contents = self.contentGetter()
            let size = geo.size
            
            let drag = DragGesture().onEnded { val in
                bounceOffset = 0
                // 處理左右兩邊缴川、pageEnabled邏輯
                let minOffset: CGFloat = 0
                let maxOffset: CGFloat = pageCache.size.width * CGFloat(pageCache.page - 1)
                if contentOffset.width < minOffset {
                    contentOffset.width = minOffset
                } else if contentOffset.width > maxOffset {
                    contentOffset.width = maxOffset
                } else {
                    let index = Int(contentOffset.width / pageCache.size.width + 0.5)
                    contentOffset.width = pageCache.size.width * CGFloat(index)
                }
                pageCache.offset = contentOffset
            }.onChanged { val in
                // 簡(jiǎn)單模擬彈力
                let k: CGFloat = 0.6
                let minOffset: CGFloat = 0
                let maxOffset: CGFloat = pageCache.size.width * CGFloat(pageCache.page - 1)
                if contentOffset.width < minOffset {
                    let delta = abs(minOffset - contentOffset.width)
                    bounceOffset = -delta * k
                } else if contentOffset.width > maxOffset {
                    let delta = abs(maxOffset - contentOffset.width)
                    bounceOffset = delta * k
                }
                
                // 簡(jiǎn)單處理滑動(dòng)
                let ch = val.translation
                contentOffset.width = pageCache.offset.width - ch.width
            }
            
            ForEach(0 ..< contents.count) { i in
                contents[i].frame(width: size.width, height: size.height).offset(x: CGFloat(i) * size.width, y: 0)
            }
            .offset(x: bounceOffset - contentOffset.width) // 注意平時(shí)scrollView的contentOffset和這個(gè)offset是相反的
            .animation(.easeInOut(duration: 0.2), value: contentOffset)
            .gesture(drag)
            .onAppear {
                pageCache.size = size
                pageCache.page = contents.count
            }
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末二跋,一起剝皮案震驚了整個(gè)濱河市流昏,隨后出現(xiàn)的幾起案子吞获,更是在濱河造成了極大的恐慌,老刑警劉巖刁绒,帶你破解...
    沈念sama閱讀 211,639評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件烤黍,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡嫂丙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,277評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門跟啤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人竿奏,你說我怎么就攤上這事腥放。” “怎么了秃症?”我有些...
    開封第一講書人閱讀 157,221評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵伍纫,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我莹规,道長(zhǎng),這世上最難降的妖魔是什么良漱? 我笑而不...
    開封第一講書人閱讀 56,474評(píng)論 1 283
  • 正文 為了忘掉前任母市,我火速辦了婚禮,結(jié)果婚禮上患久,老公的妹妹穿的比我還像新娘。我一直安慰自己返帕,他們只是感情好篙挽,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,570評(píng)論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著铣卡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪敞峭。 梳的紋絲不亂的頭發(fā)上州邢,一...
    開封第一講書人閱讀 49,816評(píng)論 1 290
  • 那天褪子,我揣著相機(jī)與錄音骗村,去河邊找鬼。 笑死胚股,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的缨伊。 我是一名探鬼主播进宝,決...
    沈念sama閱讀 38,957評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼党晋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起灾而,我...
    開封第一講書人閱讀 37,718評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤扳剿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后锡搜,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體敛劝,經(jīng)...
    沈念sama閱讀 44,176評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,511評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了像捶。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,646評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡释簿,死狀恐怖硼莽,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤行疏,帶...
    沈念sama閱讀 34,322評(píng)論 4 330
  • 正文 年R本政府宣布套像,位于F島的核電站,受9級(jí)特大地震影響夺巩,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜喳张,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,934評(píng)論 3 313
  • 文/蒙蒙 一美澳、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧人柿,春花似錦、人聲如沸江咳。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,755評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)甥雕。三九已至,卻和暖如春社露,著一層夾襖步出監(jiān)牢的瞬間挟阻,已是汗流浹背峭弟。 一陣腳步聲響...
    開封第一講書人閱讀 31,987評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坷备,地道東北人情臭。 一個(gè)月前我還...
    沈念sama閱讀 46,358評(píng)論 2 360
  • 正文 我出身青樓赌蔑,卻偏偏與公主長(zhǎng)得像竟秫,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子鸿摇,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,514評(píng)論 2 348

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