MUKit
安装
要运行示例项目,请克隆仓库,并首先从 Example 目录运行 pod install
MUKit 通过 CocoaPods 提供。要安装它,只需在 Podfile 中添加以下行即可
pod "MUKit"
MUNavigation 去掉 titleLabel 和 titleView 属性,并增加实时改变导航栏效果
MUSignal 去掉重写的 touchesBegan: withEvent: || touchesEnded: withEvent: || hitTest: withEvent: 方法以避免和其它框架冲突
MUImageCache 2.0
1.优化接口
2.修复时不时闪退问题
3.去掉Icon接口,实用价值太低
4.简化架构
5.提供渐进显示图片接口
核心【MUSignal、MUTableViewManager、MUNavigation】
简书】
【MUKit原理介绍和讲解
MUKit.h
MUKit.h不仅包含框架的大部分头文件,还包含大量提高效率的宏。例如,判断系统版本、加载本地图片、转字符串、实例化一个类、iPhone型号、版本号等。
MUSignal - 添加事件还在用(addGestureRecognizer:/addTarget:action:forControlEvents:))?一个Click_MUSignal(#需要x响应事件的控件名称){//相应的业务代码}就能搞定!!!!!! ~> pod 'MUKit/Signal'
MUTableViewManager - UITabelView的delegate和dataSource方法不嫌烦吗?不就一个block的事儿 ~> pod 'MUKit/TableViewManager'
MUNavigation - 那些总需要(设置样式/复原样式)的导航(UINaviationController/UINavigationBar)框架就不能智能一点? ~> pod 'MUKit/Navigation'
MUScrollManager - UISCrollView(UITableView/UICollectionView)的嵌套滚动真有这么复杂?两行代码不可以解决? ~> pod 'MUKit/ScrollManager'
MUEPaymentManager - 配置第三方(微信/支付宝)支付还敢再简单一点吗? ~> pod 'MUKit/EPaymentManager'
MUShared - 不想使用第三方分享框架,不想数据被收集?为什么不试试这个呢? ~> pod 'MUKit/Shared'
MUNetworking - 数据都请求回来了,就不会主动生成数据模型? ~> pod 'MUKit/Networking'
MUImageCache - 图片下载回来,还要再画个圆角,画个圆角还被说离屏渲染影响性能? 这锅我不背。 ~> pod 'MUKit/ImageCache'
MUPhotoPreview - 有了模型,还要从模型中提取URL(图片地址)才能显示图片?简单点,实现的方式简单点 ~> pod 'MUKit/PhotoPreview'
MUTextKit - 富文本,你有Facebook写得好吗? ~> pod 'MUKit/MUTextKit'
MULevitate - 悬浮球/悬浮按钮,还可以拖动哦 ~> pod 'MUKit/Levitate'
MUSegmentView 分段视图 ~> pod 'MUKit/MUSegmentView'
MUTag 标签控件 ~> pod 'MUKit/Tag'
ASDK】TextKit部分。
MUTextKit -富文本框架,其源代码核心来自Facebook 【区别
. 取消长按高亮文本(没实现)
. 支持Autolayout(类似UIButton 、UILabel)
PhotoPreview -简单易用的图片浏览器
原理:通过轮播图的循环机制实现,以节省内存。
MUPhotoPreviewController *controller = [MUPhotoPreviewController new];//初始化
controller.currentIndex = 1;//指定开始图片浏览的索引
controller.configuredImageBlock = ^(UIImageView *imageView, NSUInteger index, id model ,NSString **caption) {
[imageView setImageURL:model placeHolderImageName:@"1024_s"];//下载网络图片
};
controller.modelArray = @[
];//图片模型数组
[self.navigationController pushViewController:controller animated:YES];//显示
----如果需要对图片进行额外操作如保存、分享,可自定义菜单功能---------
UIButton *button = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 22, 22)];
button.titleStringMu = @"保存";
[button addTarget:self action:@selector(Carousel) forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *leftItem = [[UIBarButtonItem alloc]initWithCustomView:button];
UIButton *button1 = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 22, 22)];
button1.titleStringMu = @"分享";
UIBarButtonItem *rightItem = [[UIBarButtonItem alloc]initWithCustomView:button1];
controller.toolbar.items = @[leftItem,rightItem];
MUImageCache 2.0 -图像缓存的其他解决方案,参考[FlyImage]。
2.0 优化
1.优化接口
2.修复时不时闪退问题
3.去掉Icon接口,实用价值太低
4.简化架构
5.提供渐进显示图片接口
6.支持mmap内存映射,高效的I/O操作,减少一次文件拷贝操作
7.减少内存占用;
支持Byte Alignment字节对其,渲染过程中,避免执行CA::Render::copy_image内存操作
8.优化图片下载管理
9.支持GIF解码
10.支持图片绘制圆角,并避免调用( layer.cornerRadius;
layer.masksToBounds)
11.降低图片下载时占用内存过大(具体可对比SDWebImage下载图片时的内存使用情况)
使用方法
/**
*
*
* @param imageURLString originalURL
*/
- (void)setImageURLString:(NSString*)imageURLString;
/**
* Download images and render them with the below order:
* 1. imageURLString
* 2. placeHolderImageName
*
* These images will be saved into [FlyImageCache shareInstance]
*/
- (void)setImageURLString:(NSString*)imageURLString
placeHolderImageName:(NSString*)imageName;
/**
* Download images and render them with the below order:
* 1. imageURLString
* 2. placeHolderImageName
* 3. cornerRadius
*
* These images will be saved into [MUImageCache shareInstance]
*/
- (void)setImageURLString:(NSString*)imageURLString
placeHolderImageName:(NSString*)imageName
cornerRadius:(CGFloat)cornerRadius;
/**
* Download images and render them with the below order:
* 1. imageURLString
* 2. placeHolderImageName
* 3. cornerRadius
* 4. 渐进显示图片,适合大图显示
* These images will be saved into [MUImageCache shareInstance]
*/
- (void)setProgressImageURLString:(NSString*)imageURLString
placeHolderImageName:(NSString*)imageName
cornerRadius:(CGFloat)cornerRadius;
MUSignal - 重新定义事件实现及回调方式
优势
1.取代传统事件的定义-实现方式
2.取代子视图回调至父视图、cell(UITableViewCell/UICollectionViewCell)、controller的回调事件
3.只需在view/cell/controller里实现Click_MUSignal(switchSite){}就可以接受事件,switchSite是需要触发事件的控件属性名称
传统的事件实现方式
/**UIView 类*/
UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapedLabel:)];
[label addGestureRecognizer:tapGesture];
/**UIControl 类 */
UIButton *button = [UIButton new];
[button addTarget:self action:@selector(clickedButton:) forControlEvents:UIControlEventTouchUpInside];
事件回调方式
事件回调的方式普遍采用的是delegate、通知、block、kvo等几种方式,但这些方式都相对来说繁琐一些,需要手动移除监听避免循环引用
原理:通过runtime和响应链(响应链)动态获取控件的属性名称并执行对应的响应方法。该框架并未截取原生事件的响应链,而是额外增加了一条响应链。支持纯代码和xib。Signal响应方法的优先级为:view(控件所在的视图)>cell(控件所在的UITableViewCell或UICollectionViewCell)>UIViewController(控件所属的控制器),即Signal响应方法有且仅有一个执行。UIViewController是Signal默认实现响应方法的对象。Signal的事件实现方式: 控件触发信号的条件
具体用法请参考源码中的MUSignal(信号)
MUTableViewManager 一行代码无需写烦人的delegate和dataSource
MUTableViewManager的优势:
- 隐藏UITableView的delegate和dataSource,无需手动处理
- 自动计算和缓存行高,无需任何额外设置
- 自动解析模型,根据传入的数据,自动解析为每一个cell对应的model,无需手动处理
区别:UITableView+FDTemplateLayoutCell框架的缓存机制是通过NSDictionary数组,把NSIndexPath作为key,对应NSIndexPath的cell的高度作为value来缓存高度。而MUTableViewManager的缓存机制是通过runtime把高度缓存在cell对应的model里,当model销毁时对应的高度也会被销毁,无需额外写一套机制来处理。
//初始化
MUTableViewManager *tableViewManger = [[MUTableViewManager alloc]initWithTableView:self.tableView registerCellNib:NSStringFromClass([MUKitDemoTableViewCell class]) subKeyPath:@“result”];
//传递模型
tableViewManger = [@[@"分组模型数据例子",@"动态计算行高例子"] mutableCopy];
//赋值
tableViewManger.renderBlock = ^UITableViewCell *(UITableViewCell *cell, NSIndexPath *indexPath, id model, CGFloat *height) {
cell.textLabel.text = [NSString stringWithFormat:@"%@",model];
return cell;
};
具体用法请参考源码中的MUTableviewManager(MVVM TableView)
MUNavigation 轻量 简单 易用 的导航框架
MUNavigation 导航框架原理(与其它导航框架的区别)
MUNavigation的原理是不直接对Navigation bar操作,而是把navigation bar的样式存储在UIViewController里,当UIViewController调用-(void)viewWillAppear:(BOOL)animated时,一次性设置当前UIViewController的navigation bar样式,这样每个UIViewController的navigation bar样式就是相互独立的,互不影响。当UIViewController没有设置任何Navigation bar样式时,他就会取UIViewController的UINavigationController(全局设置)的Navigation bar样式,作为当前UIViewController的Navigation bar样式。UIViewController只需设置一次Navigation bar的样式代码,无需考虑UIViewController间的Navigation bar样式影响。大量节省代码和时间,集中精力处理业务。MUNavigation里只有一个UIViewController (MUNavigation)分类文件,里面可以配置一些属性。
@property(nonatomic, assign)BOOL navigationBarTranslucentMu;//透明导航栏
@property(nonatomic, assign)CGFloat navigationBarAlphaMu;//透明度
@property(nonatomic, assign)BOOL navigationBarHiddenMu;//隐藏导航栏
@property(nonatomic, strong)UIColor *navigationBarBackgroundColorMu;//背景颜色
@property(nonatomic, strong)UIImage *navigationBarBackgroundImageMu;//背景图片
@property(nonatomic, assign)BOOL navigationBarShadowImageHiddenMu;//隐藏阴影线
@property(nonatomic, strong)UIColor *titleColorMu;//标题颜色
@property(nonatomic, strong)UIColor *navigationBarTintColor;//控件颜色
@property(nonatomic, assign)UIStatusBarStyle statusBarStyleMu;//电池电量条,没有导航控制器的情况下使用
@property(nonatomic, assign)UIBarStyle barStyleMu;//电池电量条,有导航控制器的情况下使用
@property(nonatomic, strong)UIImage *backIndicatorImageMu;//返回按钮图片
@property(nonatomic, assign)BOOL showBackBarButtonItemText;//是否显示返回按钮文字
@property(nonatomic, assign ,readonly)CGFloat navigationBarAndStatusBarHeight;//导航条和电池电量条高度
@property(nonatomic, readonly)UILabel *titleLabel;//自定义标题
@property(nonatomic, strong)UIView *titleViewMu;//自定义titleView
@property(nonatomic, strong)UIFont *titleFontMu;//标题字体
@property(nonatomic, assign)CGFloat navigationBarTranslationY;//导航在y轴方向上偏移距离
属性虽然看起来有点多,但其实都是UINavigationBar和UIController的一些常用属性。实际用起来也很简单,如下代码所示就对一个UINavigationController内的所有UIViewController的UINavigationBar样式做了统一处理。
navigationController.barStyleMu = UIBarStyleBlack;//设置电池电量条的样式
navigationController.navigationBarBackgroundImageMu = [UIImage imageFromColorMu:[UIColor colorWithRed:250./255. green:25./255. blue:64./255. alpha:1.]];//导航条的图片
navigationController.navigationBarTintColor = [UIColor whiteColor];//返回按钮箭头颜色
navigationController.titleColorMu = [UIColor whiteColor];//标题颜色
self.window.rootViewController = navigationController;
如果想控制单个UIViewController的样式,在viewDidLoad中通过分类配置想要的效果即可
@implementation DemoController
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationBarHiddenMu = YES;//隐藏
self.statusBarStyleMu = UIStatusBarStyleDefault;//更改电池电量条样式
}
如果想使用类似京东、淘宝等APP全屏侧滑的导航方法只需初始化即可
MUNavigationController *navigationController = [[MUNavigationController alloc]initWithRootViewController:[UIViewController new]];
具体用法请参考源码中的MUNavigation(导航框架案例)
MUImagePickerManager-简单易用
MUImagePickerManager *controller = [MUImagePickerManager new];
controller.allowsMultipleSelection = YES;//单选或多选
controller.mediaType = MUImagePickerMediaTypeVideo;//选择图片或视频
// controller.navigationBarBackgroundImageMu = [UIImage imageFromColorMu:[UIColor whiteColor]];
controller.maximumNumberOfSelection = 12;
// [controller takePhotoPresentIn:self allowedEditedImage:YES selectedImage:^(UIImage *origanlImage, UIImage *editedImage) {
// NSLog(@"image====%@=======editt======%@",origanlImage,editedImage);
// }];
[controller presentInViewController:self];
weakify(self)
controller.didFinishedPickerImages = ^(NSArray<__kindof UIImage *> *images) {//选择完成
normalize(self)
for (UIImage *image in images) {
NSLog(@"image====%@",image);
}
};
controller.didFinishedPickerVideos = ^(NSArray *videoURLs) {//选择视频回调的URL
normalize(self)
for (NSString *url in videoURLs) {
NSLog(@"url====%@",url);
}
};
MUPopupView(仿QQ下拉菜单)-简单易用
MUPopupView *popupView = [[MUPopupView alloc]initWithItemButton:item modelArray:@[@{@"text":@"修改分组名称",@"image":@"modify"},@{@"text":@"添加分组",@"image":@"New-addition"}]];//初始化
popupView.renderCellBlock = ^(UITableViewCell *cell, id model, NSIndexPath *indexPath) {//菜单样式
NSDictionary *dict = model;
cell.textLabel.text = dict[@"text"];
cell.textLabel.font = [UIFont systemFontOfSize:12.];
cell.imageView.image = [UIImage imageNamed:dict[@"image"]];
};
popupView.selectedCellBlock = ^(id model, NSIndexPath *indexPath) {//选择菜单后
if (indexPath.row == 0) {
}else{
}
};
[popupView showView];
MUKeyboard(仿微信键盘)
MUCheckbox-迷你的小控件 有了它再也不需要求UI切图了
typedef NS_ENUM(NSUInteger ,MUCheckmarkStyle){
/// ■
MUCheckmarkStyleSquare = 1,
/// ●
MUCheckmarkStyleCircle,
/// ╳
MUCheckmarkStyleCross,
/// ✓
MUCheckmarkStyleTick
};
typedef NS_ENUM(NSUInteger ,MUBorderStyle){
/// ▢
MUBorderStyleSquare = 1,
/// ◯
MUBorderStyleCircle,
};
@property (nonatomic,strong)IBInspectable UIColor *uncheckedBorderColor;//未选时边框的颜色
@property (nonatomic,strong)IBInspectable UIColor *checkedBorderColor;//选中时边框的颜色
/// **Default:** The current tintColor.
@property (nonatomic,strong)IBInspectable UIColor *checkmarkColor;//选中时内部样式的颜色
MURefresh-迷你的刷新控件 主要配合MUTableViewManager使用,当然也可以单独使用
这款刷新控件与其它不同之处的地方在于,第一次下拉刷新是自动触发,而且不会显示刷新的状态和效果,但会执行刷新方法。当手动下拉刷新时,你才会看到刷新状态.这样设计的目的是不需要重复写请求链接。
//MURefresh
//下拉控件样式
self.tableViewManager.refreshHeaderComponent.textColor = [UIColor redColor];//刷新成功后的提示文字颜色
self.tableViewManager.refreshHeaderComponent.styleColor = [UIColor greenColor];//刷新控件颜色
self.tableViewManager.refreshHeaderComponent.animationStyle = MUReplicatorLayerAnimationStyleCircle;//刷新样式,可以不设置
weakify(self)
[self.tableViewManager addHeaderRefreshing:^(MURefreshComponent *refresh) {
normalize(self)
[refresh endRefreshingWithText:@"数据加载成功" completion:^{
self.tableViewManager.modelArray = [self CustomerModelArray];
}];
}];
//上拉刷新
//上拉控件使用默认样式
[self.tableViewManager addFooterRefreshing:^(MURefreshComponent *refresh) {
//延时3s再结束刷新
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[refresh endRefreshingWithText:@"没有更多数据了" completion:^{
}];
});
}];
ScrollManager -解决UIScrollView嵌套滚动的另一种方案,简单、易用、无侵入性
想要做到无侵入性首先需要解决UIScrollView的delegate问题。例如在UITableView嵌套UICollectionView的一般解决方案中,会在同一个文件中处理它们的delegate和dataSource问题,并且监听scrollViewDidScroll:方法。代码如下
-(void)scrollViewDidScroll:(UIScrollView *)scrollView{
if (scrollView == self.nestScrollViewMU) {
if (!self.arrivedTop) {//没有到达顶部
scrollView.contentOffset = CGPointZero;
}
if (scrollView.contentOffset.y < 0) {
scrollView.contentOffset = CGPointZero;
self.arrivedTop = NO;
}
}
if (scrollView == self.originalScrollView) {
if (scrollView.contentOffset.y >= self.offsetMU) {//到达顶部,可以滚动
scrollView.contentOffset = CGPointMake(0, self.offsetMU);
self.arrivedTop = YES;//到达顶部
}else{
if(self.arrivedTop&&self.nestScrollViewMU.contentSize.height>CGRectGetHeight(self.nestScrollViewMU.bounds)+self.marginHeight) {
scrollView.contentOffset = CGPointMake(0, self.offsetMU);
}
}
}
}
如果是使用MUScrollManager,那么你需要做的就两步,而且不会影响已经设置的delegate和dataSource
1.定义一个MUScrollManager属性,如下
@property (nonatomic,strong) MUScrollManager *manager;
2.初始化一个MUScrollManager实例,如下
self.manager = [[MUScrollManager alloc]initWithScrollView:tableView nestedScrollView:nestTableView offset:284.];//这个实例化说明的意思是nestTableView嵌套在tableView上,并且当tableView偏移了284的时候,nestTableView才会滚动
MUNetworking 网络框架原理(与其他框架的区别)
MUNetworking 的优势在于可以自动将响应数据转换为相应的模型,无需手动处理。这可以节省大量代码,将精力集中在处理业务上。目前有许多基于 AFNetworking 二次封装的网络框架,但大多数的核心功能都集中在请求缓存上,几乎没有处理参数和响应数据基本需求的框架。如果你正在寻找提高效率的工具,这个应该是你的首选。(如果有比这更简单、更高效的工具,请告诉我 ^_^)。
MUNetworking 主要包含两个模型:MUNetworkingModel(数据模型)和 MUParameterModel(参数模型),这两个模型都遵循 YYModel 协议。使用时需要生成两个类,分别继承 MUNetworkingModel 和 MUParameterModel。例如:MUModel:MUNetworkingModel,MUParaModel:MUParameterModel。在 MUModel 中进行如下配置:
#import "MUNetworkingModel.h"
#import "MUParaModel.h"
@interface MUModel : MUNetworkingModel
MUNetworkingModelInitialization(MUModel,MUParaModel)//含义是,把当前模型类,参数类传递给网络框架
@property (nonatomic,copy) NSString *Extend;//这是你需要转换的模型字段
@property (nonatomic,copy) NSString *PayMoney;//这是你需要转换的模型字段
@end
然后在你调起请求前的其它地方配置网络框架参数如在AppDelegate里配置
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
//配置模型类名、参数模型类名、域名、证书、数据格式
[MUModel GlobalConfigurationWithModelName:@"MUModel" parameterModel:@"MUParaModel" domain:@“www.blueberry.com” Certificates:nil dataFormat:@{@"Success":@"Success",@"Status":@"ret",@"Data":@"Content",@"Message":@"Result"}];
//全局监听网络请求状态
[MUModel GlobalStatus:nil networkingStatus:^(NSUInteger status) {
if (status == 401) {//token失效
//CommonTips(@"登录已失效,请重新登录")
[self login];需要重新登录
}
}];
}
具体用法请参考源码中的 MUNetworking(网络框架示例)
MUPayment
封装了Alipay和WeChatPay,只需添加对应的黑白名单以及模式名称和继承MULoadingModel类进行如下初始化
if (self = [super init]) {
self.AppDelegateName = @"MUKitDemoAppDelegate";
self.alipayID = @"支付宝支付得ID";
self.alipayScheme = @"mualipayment";
self.weChatPayID = @"申请的微信ID";
self.weChatPayScheme = @"wx7163dbd76eac21a9";
self.QQID = @"申请的QQID";
self.weiboID = @"申请的微博ID";
}
return self;
}
最后在你需要支付的地方调用 MUEPaymentManager 类方法直接请求数据,而无需在 APPdelegate 中写任何代码
[MUEPaymentManager muEPaymentManagerWithAliPay:privateKey result:^(NSDictionary *resultDict) {
}];
[MUEPaymentManager muEPaymentManagerWithWeChatPay:^(PayReq *req) {
} result:^(PayResp *rseq) {
}];
MUShared
在继承 MULoadingModel 类进行如下初始化后,可以直接通过 MUSharedManager 类方法将内容分享到微信好友、朋友圈、QQ好友、QQ空间和微博,无需在 APPdelegate 中写任何代码。
具体参考示例中的 signal 文件
MUPopupController
具体效果请参考 STPopup,唯一的区别是添加了一个可以与其他 controller 交互的结果 block,以及在文本编辑模式下调整 MUPopupController 的偏移高度。
MUCarouselView
具体效果请参考 SPCarouselView,区别在于增加了竖直方向滚动和文字轮播效果。
MUAdaptiveView
这是一个上传图片的常用效果。
具体的效果和使用方式,建议下载demo参考
作者
Jeykit,[邮箱地址隐藏]
需求
许可
MUKit遵循MIT许可。更多信息请参见LICENSE文件。