用Swift与OC混编制作iOS8风格菜单
来源:互联网 发布:php退出登录代码 编辑:程序博客网 时间:2024/06/11 03:20
一、开篇
众所周知Swift是苹果公司于2014年WWDC发布的新开发语言,它可以与Objective-C共同运行于Mac OS和iOS平台。但是由于iOS应用程序大多是由Objective-C完成的,在由OC过度到Swift的过程中,我们会不可避免地将Swift和OC混合编写Mac和iOS的应用程序。
这篇博文主要的内容就是,如何用以Swift语言为主的iOS应用程序调用一些开源的Objective-C类,并用一个实例来阐述是怎样完成的,如果您在看本文的过程中发现什么错误可以指出来。
下图是一个实例的最终模板,可以自己添加一些菜单的响应。这个菜单带有进入Menu的渐变动画以及模糊背景的功能,而这些功能的代码都是由OC实现并且在ViewController调用的(因为Swift较新,目前不会有什么开源的模块,不然我也不会写这篇技术博文了),那么我将展示如何用Swift语言调用该类
二、OC类
1.下面是CNPGridMenu.h的代码
#import <UIKit/UIKit.h>@class CNPGridMenuItem;@protocol CNPGridMenuDelegate;typedef void (^SelectionHandler)(CNPGridMenuItem *item);@interface CNPGridMenu : UICollectionViewController@property (nonatomic, assign) UIBlurEffectStyle blurEffectStyle;@property (nonatomic, weak) id <CNPGridMenuDelegate> delegate;@property (nonatomic, readonly) NSArray *menuItems;- (instancetype)initWithMenuItems:(NSArray *)items;@end@protocol CNPGridMenuDelegate <NSObject>@optional- (void)gridMenuDidTapOnBackground:(CNPGridMenu *)menu;- (void)gridMenu:(CNPGridMenu *)menu didTapOnItem:(CNPGridMenuItem *)item;@end@interface CNPGridMenuItem : NSObject@property (nonatomic, strong) NSString *title;@property (nonatomic, strong) UIImage *icon;@property (nonatomic, copy) SelectionHandler selectionHandler;@end@interface UIViewController (CNPGridMenu)@property (nonatomic, strong) CNPGridMenu *gridMenu;- (void)presentGridMenu:(CNPGridMenu *)menu animated:(BOOL)flag completion:(void (^)(void))completion;- (void)dismissGridMenuAnimated:(BOOL)flag completion:(void (^)(void))completion;@end</span></span></span>
2.接下来是CNPGridMenu.m的代码
#import "CNPGridMenu.h"#import <objc/runtime.h>#define CNP_IS_IOS8 ([[[UIDevice currentDevice] systemVersion] floatValue] >= 8.0)@protocol CNPGridMenuButtonDelegate <NSObject>- (void)didTapOnGridMenuItem:(CNPGridMenuItem *)item;@end@interface CNPGridMenuFlowLayout : UICollectionViewFlowLayout@end@interface CNPGridMenuCell : UICollectionViewCell@property (nonatomic, strong) CNPGridMenuItem *menuItem;@property (nonatomic, strong) UILabel *titleLabel;@property (nonatomic, strong) UIButton *circleButton;@property (nonatomic, strong) UIImageView *iconView;@property (nonatomic, strong) UIVisualEffectView *vibrancyView;@property (nonatomic, assign) UIBlurEffectStyle blurEffectStyle;@property (nonatomic, weak) id <CNPGridMenuButtonDelegate> delegate;@end@interface CNPGridMenuItem ()@end@interface CNPGridMenu () <CNPGridMenuButtonDelegate, UIGestureRecognizerDelegate>@property (nonatomic, strong) UIVisualEffectView *blurView;@property (nonatomic, strong) NSMutableArray *buttons;@property (nonatomic, strong) CNPGridMenuFlowLayout *flowLayout;@property (nonatomic, strong) UITapGestureRecognizer *backgroundTapGestureRecognizer;@end@implementation CNPGridMenu- (instancetype)initWithMenuItems:(NSArray *)items { self.flowLayout = [[CNPGridMenuFlowLayout alloc] init]; self = [super initWithCollectionViewLayout:self.flowLayout]; if (self) { _blurEffectStyle = UIBlurEffectStyleDark; _buttons = [NSMutableArray new]; _menuItems = items; } return self;}- (void)viewDidLoad { [super viewDidLoad]; self.collectionView.backgroundColor = [UIColor clearColor]; self.collectionView.delaysContentTouches = NO; [self.collectionView registerClass:[CNPGridMenuCell class] forCellWithReuseIdentifier:@"GridMenuCell"]; self.backgroundTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(didTapOnBackgroundView:)]; self.backgroundTapGestureRecognizer.numberOfTapsRequired = 1; UIBlurEffect *blurEffect = [UIBlurEffect effectWithStyle:self.blurEffectStyle]; self.blurView = [[UIVisualEffectView alloc] initWithEffect:blurEffect]; self.blurView.frame = self.view.bounds; [self.blurView addGestureRecognizer:self.backgroundTapGestureRecognizer]; self.collectionView.backgroundView = self.blurView;}- (UIStatusBarStyle)preferredStatusBarStyle { return self.blurEffectStyle == UIBlurEffectStyleDark ? UIStatusBarStyleLightContent : UIStatusBarStyleDefault;}#pragma mark - UICollectionView Delegate & DataSource- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath { CNPGridMenuCell * cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"GridMenuCell" forIndexPath:indexPath]; CNPGridMenuItem *item = [self.menuItems objectAtIndex:indexPath.row]; cell.delegate = self; cell.blurEffectStyle = self.blurEffectStyle; cell.menuItem = item; cell.iconView.image = item.icon; cell.titleLabel.text = item.title; return cell;}- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section { return self.menuItems.count;}#pragma mark - UITapGestureRecognizer Delegate -(void) didTapOnBackgroundView:(id)sender { if ([self.delegate respondsToSelector:@selector(gridMenuDidTapOnBackground:)]) { [self.delegate gridMenuDidTapOnBackground:self]; }}#pragma mark - CNPGridMenuItem Delegate- (void)didTapOnGridMenuItem:(CNPGridMenuItem *)item { if ([self.delegate respondsToSelector:@selector(gridMenu:didTapOnItem:)]) { [self.delegate gridMenu:self didTapOnItem:item]; }}@end@implementation CNPGridMenuItem@end@implementation CNPGridMenuCell- (void)setupCell { UIVisualEffect *vibrancyEffect = [UIVibrancyEffect effectForBlurEffect:[UIBlurEffect effectWithStyle:self.blurEffectStyle]]; self.vibrancyView = [[UIVisualEffectView alloc] initWithEffect:vibrancyEffect]; [self.contentView addSubview:self.vibrancyView]; self.circleButton = [[UIButton alloc] initWithFrame:CGRectZero]; [self.circleButton setBackgroundColor:[UIColor clearColor]]; self.circleButton.layer.borderWidth = 1.0f; self.circleButton.layer.borderColor = [UIColor whiteColor].CGColor; [self.circleButton addTarget:self action:@selector(buttonTouchDown:) forControlEvents:UIControlEventTouchDown]; [self.circleButton addTarget:self action:@selector(buttonTouchUpInside:) forControlEvents:UIControlEventTouchUpInside]; [self.circleButton addTarget:self action:@selector(buttonTouchUpOutside:) forControlEvents:UIControlEventTouchUpOutside]; [self.vibrancyView.contentView addSubview:self.circleButton]; self.iconView = [[UIImageView alloc] initWithFrame:CGRectZero]; self.iconView.tintColor = [UIColor whiteColor]; [self.iconView setContentMode:UIViewContentModeScaleAspectFit]; [self.vibrancyView.contentView addSubview:self.iconView]; self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; [self.titleLabel setFont:[UIFont systemFontOfSize:14]]; [self.titleLabel setTextColor:[UIColor whiteColor]]; [self.titleLabel setNumberOfLines:2]; [self.titleLabel setTextAlignment:NSTextAlignmentCenter]; [self.vibrancyView.contentView addSubview:self.titleLabel];}- (void)setBlurEffectStyle:(UIBlurEffectStyle)blurEffectStyle { _blurEffectStyle = blurEffectStyle; if (self.vibrancyView == nil) { [self setupCell]; }}- (void)layoutSubviews { [super layoutSubviews]; self.vibrancyView.frame = self.contentView.bounds; [self.circleButton setFrame:CGRectMake(10, 0, self.contentView.bounds.size.width-20, self.contentView.bounds.size.width-20)]; [self.circleButton.layer setCornerRadius:self.circleButton.bounds.size.width/2]; [self.iconView setFrame:CGRectMake(0, 0, 40, 40)]; self.iconView.center = self.circleButton.center; [self.titleLabel setFrame:CGRectMake(0, CGRectGetMaxY(self.circleButton.bounds), self.contentView.bounds.size.width, self.contentView.bounds.size.height - CGRectGetMaxY(self.circleButton.bounds))];}- (void)buttonTouchDown:(UIButton *)button { self.iconView.tintColor = [UIColor blackColor]; button.backgroundColor = [UIColor whiteColor];}- (void)buttonTouchUpInside:(UIButton *)button { self.iconView.tintColor = [UIColor whiteColor]; button.backgroundColor = [UIColor clearColor]; if ([self.delegate respondsToSelector:@selector(didTapOnGridMenuItem:)]) { [self.delegate didTapOnGridMenuItem:self.menuItem]; } if (self.menuItem.selectionHandler) { self.menuItem.selectionHandler(self.menuItem); }}- (void)buttonTouchUpOutside:(UIButton *)button { self.iconView.tintColor = [UIColor whiteColor]; button.backgroundColor = [UIColor clearColor];}@end#pragma mark - CNPGridMenuFlowLayout @implementation CNPGridMenuFlowLayout- (id)init{ if (self = [super init]) { self.itemSize = CGSizeMake(90, 110); self.minimumInteritemSpacing = 10; self.minimumLineSpacing = 10; self.scrollDirection = UICollectionViewScrollDirectionVertical; self.sectionInset = UIEdgeInsetsMake(10, 10, 10, 10); } return self;}-(NSArray*)layoutAttributesForElementsInRect:(CGRect)rect { NSArray* array = [super layoutAttributesForElementsInRect:rect]; UICollectionViewLayoutAttributes* att = [array lastObject]; if (att){ CGFloat lastY = att.frame.origin.y + att.frame.size.height; CGFloat diff = self.collectionView.frame.size.height - lastY; if (diff > 0){ UIEdgeInsets contentInsets = UIEdgeInsetsMake(diff/2, 0.0, 0.0, 0.0); self.collectionView.contentInset = contentInsets; } } return array;}@end#pragma mark - CNPGridMenu Categories@implementation UIViewController (CNPGridMenu)@dynamic gridMenu;- (void)presentGridMenu:(CNPGridMenu *)menu animated:(BOOL)flag completion:(void (^)(void))completion { [menu setModalPresentationStyle:UIModalPresentationCustom]; [menu setModalTransitionStyle:UIModalTransitionStyleCrossDissolve]; menu.modalPresentationCapturesStatusBarAppearance = YES; [self presentViewController:menu animated:flag completion:completion];}- (void)dismissGridMenuAnimated:(BOOL)flag completion:(void (^)(void))completion { [self dismissViewControllerAnimated:flag completion:completion];}- (void)setGridMenu:(CNPGridMenu *)gridMenu { objc_setAssociatedObject(self, @selector(gridMenu), gridMenu, OBJC_ASSOCIATION_RETAIN_NONATOMIC);}- (CNPGridMenu *)gridMenu { return objc_getAssociatedObject(self, @selector(gridMenu));}@end对于代码的内容我不作解释,毕竟这不是重点内容,有需要的可以拷贝下来自己研究。
三、在Swift语言的ViewController调用OC类
1.首先打开XCode6.0,新建一个Single View Application,点击Next
2.填写项目名称,语言选择Swift,点击Next,选择项目的路径,最后创建好项目
3.新建一个头文件的OC文件,把前面的代码拷贝到相应的文件里面,现在我们在ViewController.swift里面使用该类
4.下面是ViewController.swift中的关键代码,请注意:ShowMenu这个方法是与一个按钮绑定的,即按钮点击时的相应方法,按钮要先在storyboard中创建好,具体不多解释。还有图片没有给出来,你可以自己找一些图片来代替
@IBAction func ShowMenu(sender: AnyObject) { var laterToday = CNPGridMenuItem() laterToday.icon = UIImage(named: "LaterToday") laterToday.title = "Later Today" var thisEvening = CNPGridMenuItem() thisEvening.icon = UIImage(named: "ThisEvening") thisEvening.title = "This Evening" var tomorrow = CNPGridMenuItem() tomorrow.icon = UIImage(named: "Tomorrow") tomorrow.title = "Tomorrow" var thisWeekend = CNPGridMenuItem() thisWeekend.icon = UIImage(named: "ThisWeekend") thisWeekend.title = "This Weekend" var nextWeek = CNPGridMenuItem() nextWeek.icon = UIImage(named: "NextWeek") nextWeek.title = "Next week" var inAMonth = CNPGridMenuItem() inAMonth.icon = UIImage(named: "InMonth") inAMonth.title = "In A Month" var someday = CNPGridMenuItem() someday.icon = UIImage(named: "Someday") someday.title = "Someday" var desktop = CNPGridMenuItem() desktop.icon = UIImage(named: "Desktop") desktop.title = "Desktop" var pickDate = CNPGridMenuItem() pickDate.icon = UIImage(named: "PickDate") pickDate.title = "Pick Date" var GridMenu:CNPGridMenu = CNPGridMenu(menuItems: [laterToday, thisEvening, tomorrow, thisWeekend, nextWeek, inAMonth, someday, desktop, pickDate]) GridMenu.delegate = self self.presentGridMenu(GridMenu, animated: true, completion: { NSLog("Grid Menu Presented") }) } func gridMenuDidTapOnBackground(menu: CNPGridMenu!){ self.dismissGridMenuAnimated(true , completion: { NSLog("Grid Menu Dismissed With Background Tap") }) } func gridMenu(menu: CNPGridMenu!, didTapOnItem item: CNPGridMenuItem!) { self.dismissGridMenuAnimated(true, completion: { NSLog("Grid Menu Did Tap On Item: %@", item.title) }) }
这里使用NSLog有助于理解方法之间的联系
5.ViewController.swift需要继承一个CNPGridMenuDelegate协议
class ViewController: UIViewController, CNPGridMenuDelegate
四、Swift与OC混编必不可少的一步
如果你做到了以上几部,那么你肯定会发现,在使用CNPGridMenu的时候,没有代码提示,并且会提示错误,那是因为没有import这个类,那么如何引入该类呢?其实非常简单,在新建OC文件的时候,Xcode会提示你,是否创建一个桥接文件,或者你可以自己新建一个头文件,名字必须是 "项目名-Bridging-Header.h",然后在这个头文件里面就可以import了
#import "CNPGridMenu.h"
同时,我们必须配置这个桥接头文件的编译路径,在项目配置中找到build settings,搜索Bridging或者下拉找到Swift Compiler - Code Generation,setting中有一个Objective-C Bridging Header,设置它的值为刚才创建的头文件的路径,具体如下图:
经过这一步,我们就可以成功地编译运行这个iOS应用程序啦
- 用Swift与OC混编制作iOS8风格菜单
- iOS8开发~Swift(五)Swift与OC混编
- iOS8开发~Swift(五)Swift与OC混编
- Swift与OC混编
- OC与Swift混编
- OC与Swift混编
- OC与Swift混编
- OC与Swift混编
- OC与Swift混编
- OC与Swift混编
- oc与swift混编
- Swift与OC 混编
- Swift与OC混编
- OC与Swift混编
- OC与Swift混编
- swift 与oc 混编
- Swift与OC混编
- OC与swift混编
- i os 后台GPS 定位
- Linux 系统之find命令参数详解
- app store排名算法规则大揭秘
- android微信分享
- Codeforces Round #275 (Div. 1)B(线段树+位运算)
- 用Swift与OC混编制作iOS8风格菜单
- javaWeb day04 ( javaWeb基础 )
- C# 根据配置文件实例化类
- iOS 后台播放音乐
- Java线程(二):线程数据共享及ThreadLocal使用
- Windows下OpenCV的环境配置
- java连接数据方法jdbc:oracle,mysql,mongodb
- 奔五的人学IOS:swift练手与csdn,近期学习总结
- Android学习笔记8——用户界面之Activty