序文
ナゲッツテクノロジーコミュニティのクリエイター署名プログラムの募集に参加しています。リンクをクリックして登録し、送信してください。
OCバージョンであろうとSwiftバージョンであろうと、iOSでの同様の画像ブラウザは多くのオープンソースになっています。しかし、6〜7年の古いiOS開発者として、そして私が蓄積したソーシャルアプリの経験として、私は現在のプロジェクトで自分のアイデアや同様のコンポーネントに基づいて新しいものを再作成せざるを得ませんでした。このオープンソースJFHeroBrowserの優先言語がSwift(完全にSwiftにはOCコードが含まれていない)であることは間違いありません。また、Swiftの高度な列挙の使用法、名前空間だけでなく、より迅速な方法でプロトコル指向のデータモデル処理を優先します。 、など、Swiftを深く学びたい場合は、このコンポーネントによって別の体験が得られると思います。また、地主もFlutterを開発しているため、コーディング方法もより「応答性」が高くなります。また、ほとんどのサードパーティライブラリの組み込みImageCache(主にSDWebImage)とは異なり、このコンポーネントには組み込みImageCacheが含まれていませんが、このプロジェクトを画像ブラウジング、ネットワークマップとして統合する場合は、HeroNetworkImageProviderプロトコルを自分で実装する必要があります。プロジェクトでKingfisher、SDWebImage、または自己設計の画像キャッシュを使用できます。これにより、コンポーネントの結合の問題が完全に解決されます。具体的な使用法については、次の使用法を参照してください。さらに、このコンポーネントは、ローカルマップ(UIImage)、ネットワークマップ(url)、データ(バイナリ)、ビデオ(url)などのさまざまなリソース形式をサポートしており、ImageVMを自分で実装した場合でも、リソースにアクセスできます。欲しいです。余計な手間をかけずに、使い方を見てみましょう。
アドレスをダウンロードしてインストールします
cocoaPods:
pod 'JFHeroBrowser', '1.3.2'
github:
使用法
最初に構成を初期化します
如上面所说,在Appdelegate didFinish处自行接入HeroNetworkImageProvider。实现func downloadImage(with imgUrl: String, complete: Complete?)
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支持转二进制,或者flutter的Uin8List)
list.append(HeroBrowserDataImageViewModule(data: imageSource[i]))
//网络图 也是最常用场景
list.append(HeroBrowserNetworkImageViewModule(thumbailImgUrl: thumbs[i], originImgUrl: origins[i]))
然后是具体使用示例
浏览图片
self是当前控制器,写了一个hero的命名空间,viewModules就是上面一个个定义的viewModule示例,支持视频或者不同图片VM混搭也是可以的。
另外支持参数:
-
pageControlType (默认pageControl或者数字1/5类似)
-
heroView (也就是你要放大缩放那个imageView,如果不填就不会有缩放的效果,就是一个alpha渐变)
-
heroBrowserDidLongPressHandle (长按回调,可以做些保存图片、分享等动作)
-
imageDidChangeHandle (切换图片后,上个页面的imageView也要切换,才可以dissmiss回到相应位置,如果不设置就是alpha效果)
-
enableBlurEffect 是否开启毛玻璃背景,默认开启,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
})
]
}
浏览单个视频
效果:
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をSwiftUIに変換することでしたが、実装で多くの問題が見つかりました。特に、遷移効果を開始することができませんでした。純粋なSwiftUIコードを実装したい場合は、SwiftUIレイアウトを使用して書き直すことしかできないようです。後で、時間があれば試してみるのを楽しみにしています。しかし実際には、HeroBrowserはモーダルを介してフィールドに入ります。rootViewControllerを直接取得して直接ジャンプできますが、ズームアニメーションがなく、デフォルトのアルファ遷移を使用します。コードは次のとおりです。このデモはgithubにも送信されており、必要に応じて確認できます。
初期化コードを構成する
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 跳转浏览
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)
}
}
}
添付アドレス
-
プロジェクトGitHubアドレス:JFHeroBrowser
-
SwiftUIExamplegithub.com/JerryFans/J… _
終わり
ナゲッツテクノロジーコミュニティのクリエイター署名プログラムの募集に参加しています。リンクをクリックして登録し、送信してください。