最多 5 步包含子视图本身的创建,但如果您只对从第 5 步读取的拖动事件感兴趣,这与 panGestureRecognizer 有关。
创建一个自定义 UIView,我还创建了一个委托协议,用于在子视图上发生操作时通知 viewController。根据您的子视图的复杂程度,您可能需要为此创建一个同名的 xib 文件。从现在开始,我们称它为 filterView。
在 filterView 上创建两个方法,如“隐藏”和“显示”。如果你不想有一个按钮(即带箭头的小按钮,我称之为dropdownButton)来关闭和打开filterView,你可以跳过这一步,但我强烈建议实现它们。您要做的就是将 filterView.frame.origin.y 动画化为
如果需要,我还可以发送该动画的代码。
3. 打开 UIViewController 的 xib 文件并添加一个 UIView,这样只有它的下拉按钮可见。单击视图并使用界面构建器中最右侧的窗格将其类更改为 filterView。在此步骤中,如果您正确执行了所有操作,您应该能够在页面底部看到您的 filtersView 的提示。如果不是,filterView.xib 文件可能没有正确连接到 filterView 源代码文件。
4. 在 ViewController 中导入 FilterView 并作为 IBOutlet 连接并合成它。如果您编写了委托协议,请实施委托协议。如果您在 filterView 上有按钮,稍后您将需要它。委托协议应包括可选消息,例如
-(void) featuresButtonTappedOnFilterView: (FilterView *) filterView;
并且在实现中你应该在 viewController 中做你必须做的事情,比如打开另一个 viewController。
5. 在 viewControllers xib 文件上创建一个panGestureRecognizer并将其添加到您的 filterView。PanGestureRecognizer 是一个手势识别器,它将处理拖动事件。起初,整个 filterView 将能够通过单击其上的任何点来拖动,我们稍后会谈到。将 gestureRecognizer 连接为 IBOutlet 并创建一个 IBAction(最好使用更好的名称),例如:
-(IBAction)_panRecogPanned:(id)sender;
在 ViewController 的 viewDidLoad 方法中不要忘记将委托设置为:
[_panRecog setDelegate:self];
6. 实施其他状态以获得更多权力。但 stateChanged 一开始就足够了。
- (IBAction)_panRecogPanned:(id)sender {
switch ([(UIPanGestureRecognizer*)sender state]) {
case UIGestureRecognizerStateBegan: { } break;
case UIGestureRecognizerStateChanged: {
if ( [((UIPanGestureRecognizer *)sender) locationInView:_filterView].y > dropDownButton.frame.height )
return; // Only drag if the user's finger is on the button
CGPoint translation = [_panRecog translationInView:filterView];
//Note that we are omitting translation.x, otherwise the filterView will be able to move horizontally as well. Also note that that MIN and MAX were written for a subview which slides down from the top, they wont work on your subview.
CGRect newFrame = _panRecog.view.frame;
//newFrame.origin.y = MIN (_panRecog.view.frame.origin.y + translation.y, FILTER_OPEN_ORIGIN_Y);
//newFrame.origin.y = MAX (newFrame.origin.y, FILTER_INITIAL_ORIGIN_Y);
newFrame.origin.y = _panRecog.view.frame.origin.y + translation.y;
_panRecog.view.frame = newFrame;
[_panRecog setTranslation:CGPointMake(0, 0) inView:self.view];
} break;
//Remember the optional step number 2? We will use hide/ show methods now:
case UIGestureRecognizerStateEnded:
case UIGestureRecognizerStateCancelled: {
//CGPoint velocity = [_panRecog velocityInView:_panRecog.view];
//Bonus points for using velocity when deciding what to do when if the user lifts his finger
BOOL open;
/*
if (velocity.y < -600.0) {
open = NO;
}
else if (velocity.y >= 600.0) {
open = YES;
} else
*/
if ( _panRecog.view.frame.origin.y > (FILTER_OPEN_ORIGIN_Y + FILTER_INITIAL_ORIGIN_Y) / 2 ) {
open = YES;
}
else {
open = NO;
}
if (open == YES) {
[_filterView show];
}
else {
[_filterView hide];
}
} break;
default:
break;
}
}
注意:我的过滤器视图位于页面顶部而不是底部,因为子视图将移出页面边框。注释掉 MAX 和 MIN 语句来解决这个问题,我懒得自己写了。代码在复制和粘贴后被修改,它可能(并且可能会)包含拼写错误。