适配器(Adapter)模式
适配器可以让一些接口不兼容的类一起工作。它包装一个对象然后暴漏一个标准的交互接口。
如果你熟悉适配器设计模式,苹果通过一个稍微不同的方式来实现它-苹果使用了协议的方式来实现。你可能已经熟悉UITableViewDelegate, UIScrollViewDelegate, NSCoding 和 NSCopying协议。举个例子,使用NSCopying协议,任何类都可以提供一个标准的copy方法。
如何使用适配器模式
前面提到的水平滚动视图如下图所示:
为了开始实现它,在工程导航视图中右键点击View组,选择New File...使用iOS\Cocoa Touch\Objective-C class 模板创建一个类。命名这个新类为HorizontalScroller,并且设置它是UIView的子类。
打开HorizontalScroller.h文件,在@end 行后面插入如下代码:
Objective-c代码
@protocolHorizontalScrollerDelegate <NSObject>
// methods declaration goes in here
@end
上面的代码定义了一个名为HorizontalScrollerDelegate的协议,它采用Objective-C 类继承父类的方式继承自NSObject协议。去遵循NSObject协议或者遵循一个本身实现了NSObject协议的类 是一条最佳实践,这使得你可以给HorizontalScroller的委托发送NSObject定义的消息。你不久会意识到为什么这样做是重要的。
在@protocol和@end之间,你定义了委托必须实现以及可选的方法。所以增加下面的方法:
Objective-c代码
@required
// ask the delegate how many views he wants to present inside the horizontal scroller
- (NSInteger)numberOfViewsForHorizontalScroller:(HorizontalScroller*)scroller;
// ask the delegate to return the view that should appear at <index>
- (UIView*)horizontalScroller:(HorizontalScroller*)scroller viewAtIndex:(int)index;
// inform the delegate what the view at <index> has been clicked
- (void)horizontalScroller:(HorizontalScroller*)scroller clickedViewAtIndex:(int)index;
@optional
// ask the delegate for the index of the initial view to display. this method is optional
// and defaults to 0 if it's not implemented by the delegate
- (NSInteger)initialViewIndexForHorizontalScroller:(HorizontalScroller*)scroller;
这里你既有必需的方法也有可选方法。必需的方法要求委托必须实现它,因为它提供一些必需的数据。在这里,必需的是视图的数量,指定索引位置的视图,以及用户点击视图后的行为,可选的方法是初始化视图;如果它没有实现,那么HorizontalScroller将缺省用第一个索引的视图。
下一步,你需要在HorizontalScroller类中引用新建的委托。但是委托的定义是在类的定义之后的,所以在类中它是不可见的,怎么办呢?
解决方案就是前置声明委托协议以便编译器(和Xcode)知道协议的存在。如何做?你只需要在@inte易做图ce行前面增加下面的代码即可:
@protocolHorizontalScrollerDelegate;
继续在HorizontalScroller.h文件中,在@inte易做图ce 和@end之间增加如下的语句:
Objective-c代码
@property (weak) id<HorizontalScrollerDelegate> delegate;
- (void)reload;
这里你声明属性为weak.这样做是为了防止循环引用。如果一个类强引用它的委托,它的委托也强引用那个类,那么你的app将会出现内存泄露,因为任何一个类都不能释放调分配给另一个类的内存。
id意味着delegate属性可以用任何遵从HorizontalScrollerDelegate的类赋值,这样可以保障一定的类型安全。
reload方法在UITableView的reloadData方法之后被调用,它重新加载所有的数据去构建水平滚动视图。
用如下的代码取代HorizontalScroller.m的内容:
Objective-c代码
#import "HorizontalScroller.h"
// 1
#define VIEW_PADDING 10
#define VIEW_DIMENSIONS 100
#define VIEWS_OFFSET 100
// 2
@inte易做图ceHorizontalScroller () <UIScrollViewDelegate>
@end
// 3
@implementationHorizontalScroller
{
UIScrollView *scroller;
}
@end
让我们来对上面每个注释块的内容进行一一分析:
1. 定义了一系列的常量以方便在设计的时候修改视图的布局。水平滚动视图中的每个子视图都将是100*100,10点的边框的矩形.
2. HorizontalScroller遵循UIScrollViewDelegate协议。因为HorizontalScroller使用UIScrollerView去滚动专辑封面,所以它需要用户停止滚动类似的事件
3.创建了UIScrollerView的实例。
下一步你需要实现初始化器。增加下面的代码:
Objective-c代码
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self)
{
scroller = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, frame.size.width, frame.size.height)];
scroller.delegate = self;
[self addSubview:scroller];
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(scrollerTapped:)];
[scroller addGestureRecognizer:tapRecognizer];
}
return self;
}
滚动视图完全充满了HorizontalScroller。UITapGestureRecognizer检测滚动视图的触摸事件,它将检测专辑封面是否被点击了。如果专辑封面被点击了,它会通知HorizontalScroller的委托。
现在,增加下面的代码:
Objective-c代码
- (void)scrollerTapped:(UITapGestureRecognizer*)gesture
{
CGPoint location = [gesture locationInView:gesture.view];
// we can't use an enumerator here, because we don't want to enumerate over ALL of the UIScrollView subviews.
// we want to enumerate only the subviews that we added
for (int index=0; index<[self.delegate numberOfViews
补充:移动开发 , IOS ,