支持SwiftUI牙躺!Swift版圖片&視頻瀏覽器-JFHeroBrowser上線啦

前言

20220719_112821.GIF

iOS下類似的圖片瀏覽器不管是OC版本還是Swift版本目前已經(jīng)開源了不少恋腕。但是作為一個六七年的老iOS開發(fā)者,以及自己曾經(jīng)積累了的不少社交App經(jīng)驗焰手,還是忍不住基于自己的想法以及目前項目中類似的組件重新擼了一個糟描。毫無疑問,此次開源的JFHeroBrowser书妻,首選語言是Swift(完全Swift不包含任何OC代碼)蚓挤,偏向更Swifty的方式-面向協(xié)議處理數(shù)據(jù)模型,還有Swift進階枚舉用法驻子,命名空間等灿意,如果你想深入學(xué)習(xí)Swift,我相信本組件會讓你有不同的體驗,另外由于樓主同時也在開發(fā)Flutter,編碼方式上也是更"響應(yīng)式"崇呵。而且與大多數(shù)三方庫內(nèi)置ImageCache(大多是SDWebImage)不同缤剧,本組件,不包含內(nèi)置的ImageCache,但是如果您集成了本項目作為圖片瀏覽域慷,網(wǎng)絡(luò)圖這塊荒辕,您需要自行實現(xiàn)HeroNetworkImageProvider協(xié)議,可以使用Kingfisher或SDWebImage抑或是你項目中自行設(shè)計的圖片緩存汗销,完美解決組件耦合問題,具體使用參考下面用法抵窒。另外本組件支持多種資源格式弛针,如本地圖(UIImage),網(wǎng)絡(luò)圖(url),data(二進制),視頻(url)李皇,甚至你自行實現(xiàn)ImageVM也可以接入你想要的資源削茁。話不多說,我們來看具體使用方式掉房。

下載安裝地址

cocoaPods:

pod 'JFHeroBrowser', '1.3.2'

github:

https://github.com/JerryFans/JFHeroBrowser

Usage

首先初始化配置

如上面所說茧跋,在Appdelegate didFinish處自行接入HeroNetworkImageProvider。實現(xiàn)func downloadImage(with imgUrl: String, complete: Complete<UIImage>?)

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
        
        JFHeroBrowserGlobalConfig.default.networkImageProvider = HeroNetworkImageProvider.shared
        
//        JFHeroBrowserGlobalConfig.default.networkImageProvider = SDWebImageNetworkImageProvider.shared
        return true
    }

Kingfisher參考


extension HeroNetworkImageProvider: NetworkImageProvider {
    func downloadImage(with imgUrl: String, complete: Complete<UIImage>?) {
        KingfisherManager.shared.retrieveImage(with: URL(string: imgUrl)!, options: nil) { receiveSize, totalSize in
            guard totalSize > 0 else { return }
            let progress:CGFloat = CGFloat(CGFloat(receiveSize) / CGFloat(totalSize))
            complete?(.progress(progress))
        } downloadTaskUpdated: { task in

        } completionHandler: { result in
            switch result {
            case .success(let loadingImageResult):
                complete?(.success(loadingImageResult.image))
                break
            case .failure(let error):
                complete?(.failed(error))
                break
            }
        }
    }
}

class HeroNetworkImageProvider: NSObject {
    @objc static let shared = HeroNetworkImageProvider()
}

SDWebImage參考


extension SDWebImageNetworkImageProvider: NetworkImageProvider {
    func downloadImage(with imgUrl: String, complete: Complete<UIImage>?) {
        SDWebImageManager.shared.loadImage(with: URL(string: imgUrl)) { receiveSize, totalSize, url in
            guard totalSize > 0 else { return }
            let progress:CGFloat = CGFloat(CGFloat(receiveSize) / CGFloat(totalSize))
            complete?(.progress(progress))
        } completed: { image, data, error, _, isfinished, url in
            if let error = error {
                complete?(.failed(error))
            } else if let image = image {
                complete?(.success(image))
            } else {
                complete?(.failed(nil))
            }
        }
    }
}

class SDWebImageNetworkImageProvider: NSObject {
    @objc static let shared = SDWebImageNetworkImageProvider()
}

然后定義你需要瀏覽的ViewModule

目前支持HeroBrowserNetworkImageViewModule卓囚、HeroBrowserDataImageViewModule瘾杭、HeroBrowserLocalImageViewModule、HeroBrowserVideoViewModule四種類型ViewModule哪亿。理論上還可以定義AssetImageViewModule(支持從相冊瀏覽圖片)粥烁,在我另外一個未開源的相冊組件里面使用了,所以ViewModule的擴展非常方便使用者去擴展各種各樣的場景蝇棉,而且單一場景讨阻,由于某些特定場景比較不場景,我這只提供幾種常用的場景银萍。

幾種ViewModule代碼示例

//視頻
let vm1 = HeroBrowserVideoViewModule(thumbailImgUrl: "http://image.jerryfans.com/bf.jpg", fileUrlPath: path, provider: HeroNetworkImageProvider.shared, autoPlay: false)
            list.append(vm1)
            
//本地圖(UIImage)

list.append(HeroBrowserLocalImageViewModule(image: img))

//data圖 (file Image支持轉(zhuǎn)二進制,或者flutter的Uin8List)

list.append(HeroBrowserDataImageViewModule(data: imageSource[i]))

//網(wǎng)絡(luò)圖 也是最常用場景

list.append(HeroBrowserNetworkImageViewModule(thumbailImgUrl: thumbs[i], originImgUrl: origins[i]))
            

然后是具體使用示例

瀏覽圖片

self是當(dāng)前控制器恤左,寫了一個hero的命名空間贴唇,viewModules就是上面一個個定義的viewModule示例,支持視頻或者不同圖片VM混搭也是可以的飞袋。

另外支持參數(shù):

  • pageControlType (默認(rèn)pageControl或者數(shù)字1/5類似)
  • heroView (也就是你要放大縮放那個imageView,如果不填就不會有縮放的效果戳气,就是一個alpha漸變)
  • heroBrowserDidLongPressHandle (長按回調(diào),可以做些保存圖片巧鸭、分享等動作)
  • imageDidChangeHandle (切換圖片后瓶您,上個頁面的imageView也要切換,才可以dissmiss回到相應(yīng)位置纲仍,如果不設(shè)置就是alpha效果)
  • enableBlurEffect 是否開啟毛玻璃背景呀袱,默認(rèn)開啟,false就是黑色背景郑叠。
 self.hero.browserPhoto(viewModules: list, initIndex: indexPath.item) {
            [
                .pageControlType(.pageControl),
                .heroView(cell.imageView),
                .heroBrowserDidLongPressHandle({ [weak self] heroBrowser,vm  in
                    self?.longPressHandle(vm: vm)
                }),
                .imageDidChangeHandle({ [weak self] imageIndex in
                    guard let self = self else { return nil }
                    guard let cell = self.collectionView.cellForItem(at: IndexPath(item: imageIndex, section: 0)) as? NetworkImageCollectionViewCell else { return nil }
                    let rect = cell.convert(cell.imageView.frame, to: self.view)
                    if self.view.frame.contains(rect) {
                        return cell.imageView
                    }
                    return nil
                })
            ]
        }

瀏覽單個視頻

效果:

20220719_112821.GIF

let vm = HeroBrowserVideoViewModule(thumbailImgUrl: "http://image.jerryfans.com/w_720_h_1280_d_41_89fd26217dc299a442363581deb75b90_iOS_0.jpg", videoUrl: "http://image.jerryfans.com/w_720_h_1280_d_41_2508b8aa06a2e30d2857f9bcbdfd1de0_iOS.mp4", provider: HeroNetworkImageProvider.shared, autoPlay: true)
        self.hero.browserVideo(viewModule: vm)

瀏覽混合資源(圖片+視頻夜赵,或多個視頻)

lazy var list: [HeroBrowserViewModuleBaseProtocol] = {
        var list: [HeroBrowserViewModuleBaseProtocol] = []
        let vm = HeroBrowserVideoViewModule(thumbailImgUrl: "http://image.jerryfans.com/w_720_h_1280_d_41_89fd26217dc299a442363581deb75b90_iOS_0.jpg", videoUrl: "http://image.jerryfans.com/w_720_h_1280_d_41_2508b8aa06a2e30d2857f9bcbdfd1de0_iOS.mp4", provider: HeroNetworkImageProvider.shared, autoPlay: true)
        list.append(vm)
        list.append(HeroBrowserLocalImageViewModule(image: UIImage(named: "template-1")!))
        if let path = Bundle.main.path(forResource: "bf.MOV", ofType: nil) {
            let vm1 = HeroBrowserVideoViewModule(thumbailImgUrl: "http://image.jerryfans.com/bf.jpg", fileUrlPath: path, provider: HeroNetworkImageProvider.shared, autoPlay: false)
            list.append(vm1)
        }
        return list
    }()

self.hero.browserMultiSoures(viewModules: self.list, initIndex: 1) {
            [
                .enableBlurEffect(false),
                .heroView(button.imageView),
                .imageDidChangeHandle({ [weak self] imageIndex in
                    guard let self = self else { return nil }
                    guard let btn = self.view.viewWithTag(imageIndex) as? UIButton else { return nil }
                    return btn.imageView
                })
            ]
        }

SwiftUI的支持

一開始的想法是通過官方的UIViewController轉(zhuǎn)換成SwiftUI的寫法,但實現(xiàn)中發(fā)現(xiàn)不少問題乡革,特別是轉(zhuǎn)場效果無從下手寇僧。如果要純SwiftUI代碼實現(xiàn)摊腋,看來只能使用SwiftUI布局的方式重寫,期待之后有空可以做個嘗試嘁傀。但是實際上兴蒸,HeroBrowser是通過modal的方式進場的,我們直接獲取rootViewController直接跳轉(zhuǎn)亦可细办,但是就是缺少縮放動畫橙凳,使用了默認(rèn)的alpha轉(zhuǎn)場,代碼如下蟹腾。本demo也提交到github了痕惋,有需要可以查閱。

20220719_111436.GIF

配置初始化代碼


class AppDelegate: NSObject, UIApplicationDelegate {
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
        JFHeroBrowserGlobalConfig.default.networkImageProvider = HeroNetworkImageProvider.shared
        return true
    }
}

@main
struct SwiftUIExampleApp: App {
    @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
    var body: some Scene {
        WindowGroup {
            ContentView()
        }
    }
}

//獲取頂層vc

let keyWindow = UIApplication.shared.connectedScenes
                        .map({ $0 as? UIWindowScene })
                        .compactMap({ $0 })
                        .first?.windows.first

let myAppRootVC : UIViewController? = keyWindow?.rootViewController

//從一個圖片 GridView 跳轉(zhuǎn)瀏覽

LazyVGrid(columns: columns) {
                    ForEach(1..<origins.count, id:\.self) { index in
                        ImageCell(index: index).frame(height: columns.count == 1 ? 300 : 150).onTapGesture {
                            var list: [HeroBrowserViewModule] = []
                            for i in 0..<origins.count {
                                list.append(HeroBrowserNetworkImageViewModule(thumbailImgUrl: thumbs[i], originImgUrl: origins[i]))
                            }
                            myAppRootVC?.hero.browserPhoto(viewModules: list, initIndex: index)
                        }
                    }
                }


附件地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末娃殖,一起剝皮案震驚了整個濱河市值戳,隨后出現(xiàn)的幾起案子氏身,更是在濱河造成了極大的恐慌捏卓,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件虱黄,死亡現(xiàn)場離奇詭異芬首,居然都是意外死亡赴捞,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評論 3 395
  • 文/潘曉璐 我一進店門郁稍,熙熙樓的掌柜王于貴愁眉苦臉地迎上來赦政,“玉大人,你說我怎么就攤上這事耀怜』肿牛” “怎么了?”我有些...
    開封第一講書人閱讀 165,083評論 0 355
  • 文/不壞的土叔 我叫張陵财破,是天一觀的道長掰派。 經(jīng)常有香客問我,道長左痢,這世上最難降的妖魔是什么靡羡? 我笑而不...
    開封第一講書人閱讀 58,763評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮俊性,結(jié)果婚禮上略步,老公的妹妹穿的比我還像新娘。我一直安慰自己定页,他們只是感情好纳像,可當(dāng)我...
    茶點故事閱讀 67,785評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著拯勉,像睡著了一般竟趾。 火紅的嫁衣襯著肌膚如雪憔购。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,624評論 1 305
  • 那天岔帽,我揣著相機與錄音玫鸟,去河邊找鬼。 笑死犀勒,一個胖子當(dāng)著我的面吹牛屎飘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播贾费,決...
    沈念sama閱讀 40,358評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼钦购,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了褂萧?” 一聲冷哼從身側(cè)響起押桃,我...
    開封第一講書人閱讀 39,261評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎导犹,沒想到半個月后唱凯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,722評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡谎痢,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年磕昼,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片节猿。...
    茶點故事閱讀 40,030評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡票从,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出滨嘱,到底是詐尸還是另有隱情峰鄙,我是刑警寧澤,帶...
    沈念sama閱讀 35,737評論 5 346
  • 正文 年R本政府宣布九孩,位于F島的核電站先馆,受9級特大地震影響发框,放射性物質(zhì)發(fā)生泄漏躺彬。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,360評論 3 330
  • 文/蒙蒙 一梅惯、第九天 我趴在偏房一處隱蔽的房頂上張望宪拥。 院中可真熱鬧,春花似錦铣减、人聲如沸她君。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽缔刹。三九已至球涛,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間校镐,已是汗流浹背亿扁。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留鸟廓,地道東北人从祝。 一個月前我還...
    沈念sama閱讀 48,237評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像引谜,于是被迫代替她去往敵國和親牍陌。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,976評論 2 355

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