Rickenbacker
👌. MVVM + RxSwift + Mediatror + MJRefresh + DZNEmptyDataSet + SkeletonView
English | 简体中文
This is a set of infrastructure based on MVVM + RxSwift
Features
At the moment, the most important features of Rickenbacker can be summarized as follows:
Adapter
This module is mainly to encapsulate the base class.
- BaseViewController: Support oc base class, public part.
- VMScrollViewController: Provide refresh and empty data display support for the list.
- VMTableViewController: List base class, internally responsive processing.
- VMViewController: You need to specify ViewModel or its subclasses as generics.
- ViewModel: Basic view model, Subclasses must inherit.
- NavigationBarHiddenable: Hide the protocol of NavigationBar.
CatHome
Resource module, which mainly deals with image resource and text resource reading.
- Read image resource:
R.image("base_black_back")
- Read text resource:
R.text("base_empty_title")
- Read color resource:
R.color("background")
BeeBox
Mainly collect RxSwift related useful method classes, etc.
Mediatror
-
This module mainly provides a design component intermediate layer.
-
There are two more representative schemes for designing the component middle layer:
- Based on the URL registration jump method, refer to Mushroom Street Open Source MGJRouter
- Mediator method based on Objective-C runtime, refer to CTMediator
-
Briefly talk about the advantages and differences between the two:
- The way of URL registration is very cumbersome to use and often is not necessary. First of all, you need to register the URL in advance for each page jump, which will involve a lot of string hard coding.
- Based on the runtime Mediator method, first of all, it does not need to register, which saves a lot of process of contrasting strings. Secondly, it is very easy to pass various parameters for inter-establishment communication.
-
Therefore, the final choice to provide the solution is also the
Mediator
method;
Test case:
if let vc = Mediator.Second_viewController(title: "biaoti") {
pushButton.rx.tap
.bind(to: rx.pushViewController(vc, animated: true))
.disposed(by: disposeBag)
}
- Componentized intermediate layer:
extension Mediator {
static func Second_viewController(title: String) -> UIViewController? {
self.perform(target: SecondTarget.self,
action: "setupSecondViewController",
module: "Rickenbacker_Example",
params: ["title": title])
}
}
class SecondTarget: NSObject {
/// Note prompt, `@objc` must be added here.
@objc func setupSecondViewController(_ params: NSDictionary) -> UIViewController? {
guard let title = params["title"] as? String else { return nil }
let vm = SecondViewModel.init(title: title)
let vc = SecondViewController.init(viewModel: vm)
return vc
}
}
HBDNavigationBar
This module is based on HBDNavigationBar secondary encapsulation of the underlying basic Navigation.
MJRefresh
This module is based on the refresh function of MJRefresh encapsulated UITableView.
- Inject refresh function, you only need to simply implement the
ViewModelHeaderable
protocol. - Inject load more functions, just simply implement the
ViewModelFooterable
protocol.
Test case:
extension MJRefreshViewModel: ViewModelHeaderable, ViewModelFooterable {
var enterBeginRefresh: Bool {
return false
}
// Automatic non-sensing pull-up refresh function
var footer: MJRefreshFooter {
let footer = MJRefreshAutoFooter()
footer.triggerAutomaticallyRefreshPercent = -5
return footer
}
}
Remarks: Of course, you can also customize
header
andfooter
according to your needs.
DZNEmptyDataSet
This module is based on the empty data display function of the DZNEmptyDataSet package UITableView.
- To inject empty data display function, you only need to simply implement the
ViewModelEmptiable
protocol.
Test case:
class EmptyViewModel: ViewModel, ViewModelEmptiable, ViewModelHeaderable {
let dataSource: BehaviorRelay<[String]> = BehaviorRelay(value: [])
func loadData() {
let driver = NetworkService().randomResult().asObservable()
driver.bind(to: dataSource).disposed(by: disposeBag)
driver.map { $0.isEmpty }.bind(to: isEmptyData).disposed(by: disposeBag)
driver.subscribe { _ in } onCompleted: {
self.refreshSubject.onNext(.endHeaderRefresh)
}.disposed(by: disposeBag)
}
}
- Here also supports custom style design, only need to implement
DZNEmptyDataSetSourceable
orDZNEmptyDataSetDelegateable
agreement, interfaces are directly toDZNEmptyDataSet
do turning processing.
Test case:
// Configure empty data display information
extension DZNEmptyDataSetViewController: DZNEmptyDataSetable {
func DZNEmptyDataSetImage(scrollView: UIScrollView) -> UIImage {
return R.image("base_network_error_black")
}
func DZNEmptyDataSetImageTintColor(scrollView: UIScrollView) -> UIColor? {
return UIColor.red
}
func DZNEmptyDataSetTitle(scrollView: UIScrollView) -> NSAttributedString? {
NSAttributedString(string: R.text("TEXT"))
}
func DZNEmptyDataSetDescription(scrollView: UIScrollView) -> NSAttributedString? {
NSAttributedString(string: R.text("测试网络异常展示"))
}
func DZNEmptyDataSetVerticalOffset(scrollView: UIScrollView) -> CGFloat {
return -77
}
}
CocoaPods
- If you want use this framework.☠️
pod 'Rickenbacker'
Remarks
The general process is almost like this, the Demo is also written in great detail, you can check it out for yourself.🎷
Tip: If you find it helpful, please help me with a star. If you have any questions or needs, you can also issue.
Thanks.🎇
About the author
- 🎷 E-mail address: [email protected] 🎷
- 🎸 GitHub address: yangKJ 🎸
License
Rickenbacker is available under the MIT license. See the LICENSE file for more info.