作者:ani_di
版权所有,转载务必保留此链接 http://blog.csdn.net/ani_di
FPPopover是一个实现Popover控件的开源项目,比标准控件要强大一些。虽然如此,但是在定制边框弹框时,还是遇到了问题:border=NO并且arrowDirection = FPPopoverNoArrow时多出了一个头。
因此需要动手修改。好在这份源代码不长,修改代码的时候还可以欣赏一番。
ARCMacors.h这个头文件定义了很多宏,基本上就是把支持arc的代码按照不支持arc的方式些,以便适应老版本。 很简单,不多说。这份头文件可以复用。
FPPopoverControllerFPPopover主要就3个类,这个是Controller。里面主要由2个view:touchView和contentView。touchView和contentView分别用于事件捕获和内容展示。
init函数有两个-(id)initWithViewController:(UIViewController*)viewController,-(id)initWithViewController:(UIViewController*)viewController。其实主要工作在后一个里面。
-(id)initWithViewController:(UIViewController*)viewControllerinit里面主要是初始化_touchView和_contentView。_touchView的初始化总结为以下
_touchView = [[FPTouchView alloc] initWithFrame:self.view.bounds]; _touchView.backgroundColor = [UIColor clearColor]; _touchView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; _touchView.clipsToBounds = NO; [_touchView setTouchedOutsideBlock:^{ [bself dismissPopoverAnimated:YES]; }];
Line 1构造FPTouchView,大小等于self.view.bounds。但这时self.view.bounds还没有大小,不过不要紧,后面setupView会重新修改。
Line 2、3设置背景色和自动调整时大小时的属性,这里是保持宽高不变。
Line 4设置不剪裁子view。默然是NO,此行意义不大。 Line 5设置点击到外面的事件,默认关闭view。touchView主要就是检测在view外和里面的touch事件。
_contentView也比较简单
self.contentSize = CGSizeMake(200, 300); //default size _contentView = [[FPPopoverView alloc] initWithFrame:CGRectMake(0, 0, self.contentSize.width, self.contentSize.height)]; [_contentView addContentView:_viewController.view]; _contentView.title = _viewController.title;
_contentView主要继承外部controller的title和view。在FPPopverView中,这两部分是独立开显示的。
-(void)setupViewsetupView函数就是具体设置view的的大小。
self.view.frame = CGRectMake(0, 0, [self parentWidth], [self parentHeight]); _touchView.frame = self.view.bounds;
touchView和self.view都等于parent bound。一般情况下,它的parent view是后面的AppDelegate的view,即全屏大小。后面可以看到,这样设置最后怎么区分touch inside和outside。
contentView的大小在-(CGRect)bestArrowDirectionAndFrameFromView:(UIView*)v设置,相对复杂一些。这里不深究计算方式。
setupView在很多地方都被调用过:在viewDidLoad、手动present、屏幕旋转、键盘显示等。虽然重复调用的次数比较多,但减轻了代码负担。
由于setupView调用的地方很多,必须调用setNeedsDisplay强制刷新,否则不会立即显示。
-(void)presentPopoverFromPoint:(CGPoint)fromPoint这个函数主要的作用是设置_parentView。Line 7找到第一个window的第一个view,把自己的view加到里面。 根据事件的响应链window1->controller->views->window2...,self.view,即touchView会比现有的其他view更快响应。
[self.view removeFromSuperview]; NSArray *windows = [UIApplication sharedApplication].windows; if(windows.count > 0) { _parentView=nil; _window = [windows objectAtIndex:0]; //keep the first subview if(_window.subviews.count > 0) { _parentView = [_window.subviews objectAtIndex:0]; [_parentView addSubview:self.view]; [_viewController viewDidAppear:YES]; } }
因为在init里面的bounds是0,因此没有真正显示出来。这里手动显示非常简单,设置好真实的frame即可。代码里还加了一点点小动画。
[self setupView]; self.view.alpha = 0.0; [UIView animateWithDuration:0.2 animations:^{ self.view.alpha = self.alpha; }];-(void)dismissPopover
要隐藏一个view方法很多,一般有两种方案:1. 设透明值;2. removeFromSuperview。 在这里用的方案2。这样可以排除self.view潜在的影响,效率方面也会提升一点。 另外有setupView,再次显示出来也不难。
FPTouchViewFPTouchView对象只有一个作用:判断点击操作的位置。
-(UIView*)hitTest:(CGPoint)point withEvent:(UIEvent *)event { UIView *subview = [super hitTest:point withEvent:event]; if(UIEventTypeTouches == event.type) { BOOL touchedInside = subview != self; if(!touchedInside) { for(UIView *s in self.subviews) { if(s == subview) { //touched inside touchedInside = YES; break; } } } if(touchedInside && _insideBlock) { _insideBlock(); } else if(!touchedInside && _outsideBlock) { _outsideBlock(); } } return subview; }
最重要的是下面几段代码。
BOOL touchedInside = subview != self; if(!touchedInside) { for(UIView *s in self.subviews) { if(s == subview) { //touched inside touchedInside = YES; break; } } }
如果hitTest返回的是自身,则一定是在弹窗外部;如果不是,则判断是不是自己的子view。 在 FPPopoverController 的初始化方法里面,_contentView是 _touchView的子view。
基类的hitTest返回事件位于当前View最远的view(PS:这样才能让最后添加的view最先接收到事件), 如果没有这返回nil。 _touchView本身的frame等于第一个window的第一个view(参见 presentPopoverFromPoint), 一般这个view等于窗口大小。
作者这里代码很奇怪。判断子view的条件是 touchedInside == NO;而满足此条件则 subview == self。 那么检测self在self.subviews又是为何?
FPTouchedOutsideBlock & FPTouchedInsideBlock
这两个block是作者提供出来的回调。不同于以往的delegate模式,这里用的是block。
FPTouchedOutsideBlock在 FPPopoverController 用于关闭视图。所以修改这个时要注意一下。
这里面大部分代码都是用Quartz画外面的边框。计算orign稍微复杂一点,画tint的代码比较多。
回到以前最开始的问题是在border=NO并且arrowDirection = FPPopoverNoArrow时多出了一个头。 不知道这是一个bug还是一个特性,反正不是我想要的需求。从上面的分析,解决这个问题应该从FPPopoverView的drawRect下手。
由于边框都是在drawRect中实现的,所以我的非常简单
- (void)drawRect:(CGRect)rect { [super drawRect:rect]; if (self.border == NO && self.arrowDirection == FPPopoverNoArrow) return; // Keep others unchange }
效果如下
实现的功能:
转载请注明出处:http://blog.csdn.net/louiswangbing/article/details/12173911
fastboot是啥这里就不多说了,百度一下很多资料。
作为一个强大的刷机必备工具,我实在是不忍心不把它给分离出以便单独编译或者交叉编译给arm-linux。
有兴趣的可以一起研究一下:
https://github.com/louiskoo/fastboot-separated_from_android_4.2