【问题标题】:Drag separator to resize UIViews拖动分隔符来调整 UIViews 的大小
【发布时间】:2013-05-29 16:33:27
【问题描述】:

实现一个界面的最佳方式是什么,该界面由由一条线分隔的 UIView 组成,并且该线可以调整视图的大小?

以最简单的形式,它可能如下所示:

----------------
|              |  
| View A       |
|              |
|--------------|  < line which can be moved up and down, resizing the views
|              |  
| View B       |   
|              |  
---------------- 

它可以有更多的浏览量。

我的第一个想法是使用Touches 之类的东西使该行成为可拖动的 UIView,它会根据其位置调整视图的大小,但我确信必须有一个更优雅的解决方案。

【问题讨论】:

  • 答案会有所不同,具体取决于您是否使用自动布局和约束,或者这是否是一个非自动布局问题(即您支持 6.0 之前的 iOS 版本)。但简单的想法是创建一个UIPanGestureRecognizer,它会根据您拖动到的位置调整图像的大小。

标签: ios objective-c uiview uigesturerecognizer


【解决方案1】:

首先,定义一个手势,检测你是否从边框开始,如果手势改变,则移动所述边框:

#import <UIKit/UIGestureRecognizerSubclass.h>

- (void)viewDidLoad
{
    [super viewDidLoad];

    // I use long press gesture recognizer so it's recognized immediately

    UILongPressGestureRecognizer *gesture = [[UILongPressGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];
    gesture.minimumPressDuration = 0.0;
    gesture.allowableMovement = CGFLOAT_MAX;
    gesture.delegate = self;
    [self.containerView addGestureRecognizer:gesture];
}

- (void)handlePan:(UILongPressGestureRecognizer *)gesture
{
    static NSArray *matches;
    static CGPoint firstLocation;

    if (gesture.state == UIGestureRecognizerStateBegan)
    {
        firstLocation = [gesture locationInView:gesture.view];
        matches = [BorderBeingDragged findBordersBeingDraggedForView:gesture.view fromLocation:firstLocation];
        if (!matches)
        {
            gesture.state = UIGestureRecognizerStateFailed;
            return;
        }
    }
    else if (gesture.state == UIGestureRecognizerStateChanged)
    {
        CGPoint location    = [gesture locationInView:gesture.view];
        CGPoint translation = CGPointMake(location.x - firstLocation.x, location.y - firstLocation.y);
        [BorderBeingDragged dragBorders:matches translation:translation];
    }
}

// if your subviews are scrollviews, you might need to tell the gesture recognizer
// to allow simultaneous gestures

- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
{
    return TRUE;
}

其次,定义一个BordersBeingDragged类,用于检测边界和改变边界:

typedef enum NSInteger {
    kBorderTypeNone   = 0,
    kBorderTypeLeft   = 1 << 0,
    kBorderTypeRight  = 1 << 1,
    kBorderTypeTop    = 1 << 2,
    kBorderTypeBottom = 1 << 3
} BorderType;

@interface BorderBeingDragged : NSObject

@property (nonatomic, weak) UIView *view;
@property (nonatomic) BorderType borderTypes;
@property (nonatomic) CGRect originalFrame;

@end

static CGFloat const kTolerance = 15.0;

@implementation BorderBeingDragged

+ (NSArray *)findBordersBeingDraggedForView:(UIView *)view fromLocation:(CGPoint)point
{
    NSMutableArray *matches = nil;

    for (UIView *subview in view.subviews)
    {
        BorderType types = kBorderTypeNone;
        CGRect frame = subview.frame;

        // test top and bottom borders

        if (point.x >= (frame.origin.x - kTolerance) &&
            point.x <= (frame.origin.x + frame.size.width + kTolerance))
        {
            if (point.y >= (frame.origin.y - kTolerance) && point.y <= (frame.origin.y + kTolerance))
                types |= kBorderTypeTop;
            else if (point.y >= (frame.origin.y + frame.size.height - kTolerance) && point.y <= (frame.origin.y + frame.size.height + kTolerance))
                types |= kBorderTypeBottom;
        }

        // test left and right borders

        if (point.y >= (frame.origin.y - kTolerance) &&
            point.y <= (frame.origin.y + frame.size.height + kTolerance))
        {
            if (point.x >= (frame.origin.x - kTolerance) && point.x <= (frame.origin.x + kTolerance))
                types |= kBorderTypeLeft;
            else if (point.x >= (frame.origin.x + frame.size.width - kTolerance) && point.x <= (frame.origin.x + frame.size.width + kTolerance))
                types |= kBorderTypeRight;
        }

        // if we found any borders, add it to our array of matches

        if (types != kBorderTypeNone)
        {
            if (!matches)
                matches = [NSMutableArray array];

            BorderBeingDragged *object = [[BorderBeingDragged alloc] init];
            object.borderTypes   = types;
            object.view          = subview;
            object.originalFrame = frame;

            [matches addObject:object];
        }
    }

    return matches;
}

+ (void)dragBorders:(NSArray *)matches translation:(CGPoint)translation
{
    for (BorderBeingDragged *object in matches)
    {
        CGRect newFrame = object.originalFrame;

        if (object.borderTypes & kBorderTypeLeft)
        {
            newFrame.origin.x   += translation.x;
            newFrame.size.width -= translation.x;
        }
        else if (object.borderTypes & kBorderTypeRight)
        {
            newFrame.size.width += translation.x;
        }

        if (object.borderTypes & kBorderTypeTop)
        {
            newFrame.origin.y    += translation.y;
            newFrame.size.height -= translation.y;
        }
        else if (object.borderTypes & kBorderTypeBottom)
        {
            newFrame.size.height += translation.y;
        }

        object.view.frame = newFrame;
    }
}

@end

【讨论】:

  • 谢谢。如果视图 A 和 B 是滚动视图,这会起作用吗?或者整个 containerView 上的 UILongPressGestureRecognizer 会干扰滚动视图正常运行的能力(滚动和缩放)?
  • @cannyboy 向包含滚动视图的视图添加手势是有问题的。一种解决方案是允许同时使用手势(就像我修改后的答案一样)。但是,如果滚动视图的内容偏移量不是CGPointMake(0.0, 0.0),即您已经滚动了子视图,您会得到一个有点奇怪的效果。因此,如果您正在调整子视图的大小,您可能想尝试将contentOffset 设置为CGPointMake(0.0, 0.0)。可能还有其他方法。你应该玩弄它。
【解决方案2】:

您确实需要使 line-view 可拖动,但它不需要很复杂。

  1. viewAviewB 放入containerView
  2. 将平移手势识别器添加到为单点触摸配置的containerView,并将其代理设置为您的控制器。
  3. UIGestureRecognizerDelegate 协议实现gestureRecognizerShouldBegin:,并且仅在触摸线视图附近时才允许它开始。
  4. 在手势处理程序中获取containerView 中的触摸位置,并为viewAviewB 设置线视图位置和帧

差不多了。

【讨论】:

    【解决方案3】:

    我建议其他行为: 1.在线按住2秒 2. 出现一些你要拖动的imageView

    【讨论】:

      【解决方案4】:

      最简单的方法是在视图中添加手势识别器并根据平移调整它们的大小。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-06-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-10-26
        相关资源
        最近更新 更多