我尝试使用Objective-C在我的应用中实现iOS风格的控制中心 - 实际上,如果用户选择的话,我希望在现有视图上有一个向下滑动的视图。在默认情况下,较低的视图(即视图下方)应该是可见的。
我已经看了一下,并且已经实施了一个粗略的实现,利用this YouTube视频中的Swift代码 - 但仍然发现难以完成此操作。还有一个基于本教程的Git项目(DragSlideView),但我似乎在运行时遇到了除教程/ Git项目(在Swift中)中显示的其他问题。感谢大家能指出我在这里做错了什么......
代码粘贴在下面(以及正在发生的事情的屏幕截图)。
总之,问题在于,当我开始滑动/向下拖动视图时,一个非常慢而且没有“快速”和两个,它往往会水平偏离外面屏幕。
感谢您的投入!
ViewController.m:
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *nibContents = [[NSBundle mainBundle] loadNibNamed:@"ControlCenterView" owner:self options:nil];
self.resultsView = [nibContents lastObject];
// self.resultsView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
[self.controlCenterView setFrame:CGRectMake(0,
0 + self.navigationController.navigationBar.bounds.size.height + 20 - (self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height - 20 - TOOLBAR_HEIGHT),
self.view.bounds.size.width,
(self.view.bounds.size.height - self.navigationController.navigationBar.bounds.size.height - 20 - TOOLBAR_HEIGHT))]; // 20 is the height of the thin section above the navigation bar on the screen.
[self.view addSubview:self.controlCenterView];
[self.controlCenterView setupView];
}
ControlCenterView.m:
- (instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
self.backgroundColor = [UIColor greenColor]; // Testing...
// [self setFrame:self.bounds];
// self.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleBottomMargin;
return self;
}
- (void)setupView
{
if (self) {
self.panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
self.panGestureRecognizer.cancelsTouchesInView = NO;
[self.panGestureRecognizer setDelegate:self]; // Need for this TBC?
[self addGestureRecognizer:self.panGestureRecognizer];
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.superview];
self.animator.delegate = self; // Need for this TBC?
self.dynamicItem = [[UIDynamicItemBehavior alloc] initWithItems:@[self]];
self.dynamicItem.allowsRotation = NO;
self.dynamicItem.elasticity = 0.3;
CGPoint snapPoint = {self.superview.frame.size.width / 2, -self.superview.frame.size.height / 2};
self.snap = [[UISnapBehavior alloc] initWithItem:self snapToPoint:snapPoint];
[self.animator addBehavior:self.snap];
self.gravity = [[UIGravityBehavior alloc] initWithItems:@[self]];
self.gravity.gravityDirection = CGVectorMake(0, -1);
self.container = [[UICollisionBehavior alloc] initWithItems:@[self]];
// self.container.translatesReferenceBoundsIntoBoundary = YES;
[self configureContainer];
[self.animator addBehavior:self.gravity];
[self.animator addBehavior:self.dynamicItem];
[self.animator addBehavior:self.container];
}
}
- (void)configureContainer
{
// CGFloat boundaryWidth = self.bounds.size.width;
// CGFloat boundaryHeight = self.bounds.size.height;
CGFloat boundaryWidth = [UIScreen mainScreen].bounds.size.width;
CGFloat boundaryHeight = [UIScreen mainScreen].bounds.size.height - TOOLBAR_HEIGHT; // TOOLBAR_HEIGHT is 48.
[self.container addBoundaryWithIdentifier:@"upper" fromPoint:CGPointMake(0, -self.frame.size.height + 64 + 5) toPoint:CGPointMake(boundaryWidth, -self.frame.size.height + 64 + 30)]; // 64 is the height of the navigation bar + the height of the thin section above it on the screen (thus 44 + 20). 30 is the distance constraint between the bottom of the grey handle and the bottom of the controlCenterView.
[self.container addBoundaryWithIdentifier:@"lower" fromPoint:CGPointMake(0, boundaryHeight) toPoint:CGPointMake(boundaryWidth, boundaryHeight)];
// [self.container addBoundaryWithIdentifier:@"left" fromPoint:CGPointMake(0, -self.frame.size.height + 64 + 5) toPoint:CGPointMake(0, boundaryHeight)];
// [self.container addBoundaryWithIdentifier:@"right" fromPoint:CGPointMake(boundaryWidth, -self.frame.size.height + 64 + 30) toPoint:CGPointMake(boundaryWidth, boundaryHeight)];
}
- (IBAction)handlePan:(id)sender
{
CGFloat velocity = [sender velocityInView:self.superview].y;
CGRect movement = self.frame;
movement.origin.x = ORIGIN_X;
movement.origin.y = movement.origin.y + (velocity * 0.05);
if ([sender state] == UIGestureRecognizerStateEnded) {
[self panGestureEnded];
}
else if ([sender state] == UIGestureRecognizerStateBegan) {
[self snapToBottom];
}
else {
[self.animator removeBehavior:self.snap];
self.snap = [[UISnapBehavior alloc] initWithItem:self snapToPoint:CGPointMake(CGRectGetMidX(movement), CGRectGetMidY(movement))];
[self.animator addBehavior:self.snap];
}
}
- (void)panGestureEnded
{
[self.animator removeBehavior:self.snap];
CGPoint velocity = [self.dynamicItem linearVelocityForItem:self];
if (fabsf(velocity.y) > 250) {
if (velocity.y < 0) {
[self snapToTop];
}
else {
[self snapToBottom];
}
}
else {
CGFloat superViewHeight = self.superview.bounds.size.height;
if (superViewHeight) {
if (self.frame.origin.y > superViewHeight / 2) {
[self snapToBottom];
}
else {
[self snapToTop];
}
}
}
}
- (void)snapToBottom
{
self.gravity.gravityDirection = CGVectorMake(0, 2.5);
}
- (void)snapToTop
{
self.gravity.gravityDirection = CGVectorMake(0, -2.5);
}