是否可以将视图置于彼此之上

时间:2014-12-18 21:34:43

标签: ios watchkit

我正在构建一个Watch应用程序,我希望将WKInterfaceImage与一组带有一堆WKInterfaceLabel对象的组重叠。似乎无法在StoryBoard编辑器中执行此操作。

有没有人能够为Watch App找到彼此之间的观点?

PS。我知道WKInterfaceGroup的setBackgroundImage方法。因为我想在WKInterfaceImage中做一些动画,所以setBackgroundImage对我来说不会有祸害

2 个答案:

答案 0 :(得分:21)

您不能将WKInterfaceObjects布局在彼此之上。您可以在图像上渲染标签,然后进行设置。您必须为动画的每个帧渲染标签。我在我的手表应用程序中为按钮执行此操作。我生成的图像是我的UI的一大块,然后生成动画的每个帧并覆盖每个帧的按钮文本。然后剪切每帧的图像,以便我可以在每个按钮上设置动画。当您使用该应用程序时,它看起来像是按钮下的动画图像,实际上它是4个不同按钮中的4种不同的动画。

修改

我想我会添加更多细节。这是我的应用程序的屏幕截图。我猜你想要做类似的事情。

enter image description here

enter image description here

首先在我的故事板中,您需要确保组的间距为零。

enter image description here

要创建此UI,我使用此助手类。我已经编辑了这个课程,专注于所需的部分。

typedef struct
{
    CGRect top;
    CGRect left;
    CGRect right;
    CGRect bottom;
} ButtonRects;

@interface GPWatchMapImage ()

@property (readwrite, nonatomic) UIImage* topImage;
@property (readwrite, nonatomic) UIImage* bottomImage;
@property (readwrite, nonatomic) UIImage* leftImage;
@property (readwrite, nonatomic) UIImage* rightImage;

@property (readwrite, nonatomic) CGRect topRect;
@property (readwrite, nonatomic) CGRect bottomRect;
@property (readwrite, nonatomic) CGRect leftRect;
@property (readwrite, nonatomic) CGRect rightRect;


@property (readwrite, nonatomic) UIImage* fullImageWithoutArrows;

@property BOOL addedArrows;


@end

@implementation GPWatchMapImage

-(instancetype)init
{
    self = [super init];
    if (self)
    {

    }
    return self;
}



-(UIImage*)leftImage
{
    if (_leftImage == nil)
    {
        [self breakUpForButtons];
    }
    return _leftImage;
}

-(UIImage*)rightImage
{
    if (_rightImage == nil)
    {
        [self breakUpForButtons];
    }
    return _rightImage;
}

-(UIImage*)topImage
{
    if (_topImage == nil)
    {
        [self breakUpForButtons];
    }
    return _topImage;
}

-(UIImage*)bottomImage
{
    if (_bottomImage == nil)
    {
        [self breakUpForButtons];
    }
    return _bottomImage;
}

-(UIImage*)fullImageWithoutArrows
{
    [self fullImage]; //make sure we have the full image
    if (_fullImageWithoutArrows != nil)
    {
        return _fullImageWithoutArrows;
    }
    return _fullImage;
}

-(UIImage*)fullImage
{
    if (_fullImage == nil)
    {
        //This is the rect to create the image in
        CGRect rect = CGRectMake(0, 0, self.watchSize.width, self.watchSize.height);

        //This is how I generate map images.  You will need to do something else
        self.generatedMapInfo = [[GPCustomMapMaker instance] makeCustomMapFromConfig:self.mapConfig];
        _fullImage = self.generatedMapInfo.mapImage;

    }

    if (self.showMapArrows && !self.addedArrows)
    {
        //Add the arrows
        [self addButtonArrowsToFullImage];
    }


    return _fullImage;
}


-(void)addButtonArrowsToFullImage
{
    self.addedArrows = YES;

    ButtonRects rects = [self buttonRects];
    UIImage* img = self.fullImage;
    self.fullImageWithoutArrows = img;  //save for animations
    UIGraphicsBeginImageContext(img.size);

    UIColor* color = [UIColor colorWithRed:.4 green:.4 blue:.4 alpha:.6];

    //CGSize arrowSize = CGSizeMake(24, 4);
    CGSize arrowSize = CGSizeMake(48, 8);
    CGFloat edgeOffset = 26;
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    CGContextSetLineWidth(ctx, 6);
    CGContextSetLineJoin(ctx, kCGLineJoinRound);
    CGContextSetLineCap(ctx, kCGLineCapRound);
    CGContextSetStrokeColorWithColor(ctx, color.CGColor);

    [img drawAtPoint:CGPointMake(0, 0)];


    //Left arrow
    CGPoint leftCenter = CGPointMake(rects.left.origin.x + edgeOffset, rects.left.origin.y + rects.left.size.height/2);
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, leftCenter.x + arrowSize.height, leftCenter.y - arrowSize.width/2);
    CGContextAddLineToPoint(ctx, leftCenter.x, leftCenter.y);
    CGContextAddLineToPoint(ctx, leftCenter.x + arrowSize.height, leftCenter.y + arrowSize.width/2);
    CGContextStrokePath(ctx);

    CGPoint rightCenter = CGPointMake(rects.right.origin.x + rects.right.size.width - edgeOffset, rects.right.origin.y + rects.right.size.height/2);
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, rightCenter.x, rightCenter.y - arrowSize.width/2);
    CGContextAddLineToPoint(ctx, rightCenter.x + arrowSize.height, rightCenter.y);
    CGContextAddLineToPoint(ctx, rightCenter.x, rightCenter.y + arrowSize.width/2);
    CGContextStrokePath(ctx);


    CGPoint topCenter = CGPointMake(rects.top.origin.x + rects.top.size.width/2, rects.top.origin.y + edgeOffset);
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, topCenter.x - arrowSize.width/2, topCenter.y + arrowSize.height);
    CGContextAddLineToPoint(ctx, topCenter.x, topCenter.y);
    CGContextAddLineToPoint(ctx, topCenter.x + arrowSize.width/2, topCenter.y + arrowSize.height);
    CGContextStrokePath(ctx);

    CGPoint bottomCenter = CGPointMake(rects.bottom.origin.x + rects.bottom.size.width/2, rects.bottom.origin.y + rects.bottom.size.height - edgeOffset);
    CGContextBeginPath(ctx);
    CGContextMoveToPoint(ctx, bottomCenter.x - arrowSize.width/2, bottomCenter.y);
    CGContextAddLineToPoint(ctx, bottomCenter.x, bottomCenter.y + arrowSize.height);
    CGContextAddLineToPoint(ctx, bottomCenter.x + arrowSize.width/2, bottomCenter.y);
    CGContextStrokePath(ctx);


    UIImage* imgWithButtons = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    _fullImage = imgWithButtons;
}

-(UIImage*)subImageInRect:(CGRect)rect fromImage:(UIImage*)image
{
    UIGraphicsBeginImageContext(rect.size);

    [image drawInRect:CGRectMake(-rect.origin.x, -rect.origin.y, image.size.width, image.size.height)];

    UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return newImage;
}

-(ButtonRects)buttonRects
{
    UIImage* img = self.fullImage;
    CGSize size = self.watchSize;
    CGFloat topHeight = size.height * .25;
    CGFloat bottomHeight = size.height * .25;
    CGFloat middleHeight = size.height * .5;

    CGRect topRect = CGRectMake(0, 0, size.width, topHeight);
    CGRect leftRect = CGRectMake(0, topHeight, img.size.width/2.0, middleHeight);
    CGRect rightRect = CGRectMake(img.size.width/2.0, topHeight, img.size.width/2.0, middleHeight);
    CGRect bottomRect = CGRectMake(0, topHeight + middleHeight, size.width, bottomHeight);

    ButtonRects rects;
    rects.top = topRect;
    rects.bottom = bottomRect;
    rects.left = leftRect;
    rects.right = rightRect;

    return rects;
}

-(void)breakUpForButtons
{
    UIImage* img = self.fullImage;
    ButtonRects rects = [self buttonRects];

    _topImage = [self subImageInRect:rects.top fromImage:img];
    _leftImage = [self subImageInRect:rects.left fromImage:img];
    _rightImage = [self subImageInRect:rects.right fromImage:img];
    _bottomImage = [self subImageInRect:rects.bottom fromImage:img];
}

@end

接下来在我的WKInterfaceController类中,我这样做来制作动画。

typedef NS_ENUM(NSInteger, GPWatchImageAnimation)
{
    GPWatchImageAnimationNone,
    GPWatchImageAnimationSlideLeftToRight,
    GPWatchImageAnimationSlideRighToLeft,
    GPWatchImageAnimationSlideTopToBottom,
    GPWatchImageAnimationSlideBottomToTop,
    GPWatchImageAnimationZoomIn,
    GPWatchImageAnimationZoomOut
};

#define kNumImagesInMapAnimations 6
#define kMapAnimatinonDuration 0.4

...

-(void)updateMapImageWithAnimation:(GPWatchImageAnimation)animation
{
    GPWatchMapImage* previousImage = self.currentMapImage;

    //This gets the size of the full image that you want    
    CGSize size = [self mapSize];
    self.currentMapImage = [[GPWatchMapImage alloc] init];
    self.currentMapImage.watchSize = size;

        //Check if we have a previous image to animate from
        if (previousImage != nil && animation != GPWatchImageAnimationNone)
        {
            NSDictionary* animatedImage = [self animateFromImage:previousImage toImage:self.currentMapImage withAnimation:animation];
            [self.mapTopImage setImage:[animatedImage objectForKey:@"top"]];
            [self.mapLeftImage setImage:[animatedImage objectForKey:@"left"]];
            [self.mapRightImage setImage:[animatedImage objectForKey:@"right"]];
            [self.mapBottomImage setImage:[animatedImage objectForKey:@"bottom"]];

            [self.mapTopImage startAnimatingWithImagesInRange:NSMakeRange(0, kNumImagesInMapAnimations) duration:kMapAnimatinonDuration repeatCount:1];
            [self.mapLeftImage startAnimatingWithImagesInRange:NSMakeRange(0, kNumImagesInMapAnimations) duration:kMapAnimatinonDuration repeatCount:1];
            [self.mapRightImage startAnimatingWithImagesInRange:NSMakeRange(0, kNumImagesInMapAnimations) duration:kMapAnimatinonDuration repeatCount:1];
            [self.mapBottomImage startAnimatingWithImagesInRange:NSMakeRange(0, kNumImagesInMapAnimations) duration:kMapAnimatinonDuration repeatCount:1];
        }
        else
        {
            [self.mapTopImage setImage:self.currentMapImage.topImage];
            [self.mapLeftImage setImage:self.currentMapImage.leftImage];
            [self.mapRightImage setImage:self.currentMapImage.rightImage];
            [self.mapBottomImage setImage:self.currentMapImage.bottomImage];
        }

}

-(NSDictionary*)animateFromImage:(GPWatchMapImage*)fromImage toImage:(GPWatchMapImage*)toImage withAnimation:(GPWatchImageAnimation)animation
{
    NSMutableArray* topAnimatedImages = [[NSMutableArray alloc] initWithCapacity:kNumImagesInMapAnimations];
    NSMutableArray* bottomAnimatedImages = [[NSMutableArray alloc] initWithCapacity:kNumImagesInMapAnimations];
    NSMutableArray* leftAnimatedImages = [[NSMutableArray alloc] initWithCapacity:kNumImagesInMapAnimations];
    NSMutableArray* rightAnimatedImages = [[NSMutableArray alloc] initWithCapacity:kNumImagesInMapAnimations];

    CGSize size = fromImage.fullImage.size;
    for (int step = 0; step < kNumImagesInMapAnimations; step++)
    {
        UIGraphicsBeginImageContext(size);

        //render this step
        if (animation == GPWatchImageAnimationSlideLeftToRight)
        {
            CGFloat stepSize = (size.width/2)/kNumImagesInMapAnimations;
            CGPoint fromPoint = CGPointMake(-(step+1)*stepSize, 0);
            CGPoint toPoint = CGPointMake(size.width/2 - (step+1)*stepSize, 0);
            [fromImage.fullImageWithoutArrows drawAtPoint:fromPoint];
            [toImage.fullImageWithoutArrows drawAtPoint:toPoint];
        }
        else if (animation == GPWatchImageAnimationSlideRighToLeft)
        {
            CGFloat stepSize = (size.width/2)/kNumImagesInMapAnimations;
            CGPoint fromPoint = CGPointMake((step+1)*stepSize, 0);
            CGPoint toPoint = CGPointMake(-size.width/2 + (step+1)*stepSize, 0);
            [fromImage.fullImageWithoutArrows drawAtPoint:fromPoint];
            [toImage.fullImageWithoutArrows drawAtPoint:toPoint];
        }
        else if (animation == GPWatchImageAnimationSlideTopToBottom)
        {
            CGFloat stepSize = (size.height/2)/kNumImagesInMapAnimations;
            CGPoint fromPoint = CGPointMake(0, (step+1)*stepSize);
            CGPoint toPoint = CGPointMake(0, -size.height/2 + (step+1)*stepSize);
            [fromImage.fullImageWithoutArrows drawAtPoint:fromPoint];
            [toImage.fullImageWithoutArrows drawAtPoint:toPoint];
        }
        else if (animation == GPWatchImageAnimationSlideBottomToTop)
        {
            CGFloat stepSize = (size.height/2)/kNumImagesInMapAnimations;
            CGPoint fromPoint = CGPointMake(0, -(step+1)*stepSize);
            CGPoint toPoint = CGPointMake(0, size.height/2 - (step+1)*stepSize);
            [fromImage.fullImageWithoutArrows drawAtPoint:fromPoint];
            [toImage.fullImageWithoutArrows drawAtPoint:toPoint];
        }
        else if (animation == GPWatchImageAnimationZoomOut)
        {
            CGFloat yStepSize = (size.height/2)/kNumImagesInMapAnimations;
            CGFloat xStepSize = (size.width/2)/kNumImagesInMapAnimations;
            //CGRect fromRect = CGRectMake((step + 1)*xStepSize, (step + 1)*yStepSize, size.width - 2*(step + 1)*xStepSize, size.height - 2*(step + 1)*yStepSize);
            CGRect toRect = CGRectMake(-size.width/2 + (step+1)*xStepSize, -size.height/2 + (step+1)*yStepSize, size.width + 2*(kNumImagesInMapAnimations - step - 1)*xStepSize, size.height + 2*(kNumImagesInMapAnimations - step - 1)*yStepSize);
            [toImage.fullImageWithoutArrows drawInRect:toRect];

            //double alpha = (double)(kNumImagesInMapAnimations - step - 1)/(double)kNumImagesInMapAnimations;
            //CGContextSetAlpha(UIGraphicsGetCurrentContext(), alpha);
            //[fromImage.fullImageWithoutArrows drawInRect:fromRect];
            //CGContextSetAlpha(UIGraphicsGetCurrentContext(), 1.0);
        }
        else if (animation == GPWatchImageAnimationZoomIn)
        {
            if (step == kNumImagesInMapAnimations -1)
            {
                [toImage.fullImageWithoutArrows drawAtPoint:CGPointMake(0, 0)];
            }
            else
            {
                CGFloat yStepSize = (size.height/2)/kNumImagesInMapAnimations;
                CGFloat xStepSize = (size.width/2)/kNumImagesInMapAnimations;
                CGRect fromRect = CGRectMake(-(step + 1)*xStepSize, -(step + 1)*yStepSize, size.width + 2*(step + 1)*xStepSize, size.height + 2*(step + 1)*yStepSize);
                //CGRect toRect = CGRectMake(-size.width/2 + (step+1)*xStepSize, -size.height/2 + (step+1)*yStepSize, size.width + 2*(kNumImagesInMapAnimations - step - 1)*xStepSize, size.height + 2*(kNumImagesInMapAnimations - step - 1)*yStepSize);
                [fromImage.fullImageWithoutArrows drawInRect:fromRect];
                //[toImage.fullImageWithoutArrows drawInRect:fromRect];
            }
        }
        else
        {
            [toImage.fullImageWithoutArrows drawAtPoint:CGPointMake(0, 0)];
        }

        UIImage* stepImg = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();


        //Get each of the pieces of the image
        GPWatchMapImage* mapImage = [[GPWatchMapImage alloc] init];
        mapImage.showMapArrows = self.showMapArrows;
        mapImage.fullImage = stepImg;
        mapImage.watchSize = [self mapSize];
        [topAnimatedImages addObject:mapImage.topImage];
        [bottomAnimatedImages addObject:mapImage.bottomImage];
        [leftAnimatedImages addObject:mapImage.leftImage];
        [rightAnimatedImages addObject:mapImage.rightImage];
    }

    UIImage* topAnimatedImage = [UIImage animatedImageWithImages:topAnimatedImages duration:kMapAnimatinonDuration];
    UIImage* bottomAnimatedImage = [UIImage animatedImageWithImages:bottomAnimatedImages duration:kMapAnimatinonDuration];
    UIImage* leftAnimatedImage = [UIImage animatedImageWithImages:leftAnimatedImages duration:kMapAnimatinonDuration];
    UIImage* rightAnimatedImage = [UIImage animatedImageWithImages:rightAnimatedImages duration:kMapAnimatinonDuration];
    return @{@"top": topAnimatedImage, @"bottom": bottomAnimatedImage, @"left": leftAnimatedImage, @"right": rightAnimatedImage};
}

答案 1 :(得分:5)

在InterfaceBuilder中:您可以使用组并从资产中设置Backgroundimage。 然后,当您将WKInterfaceImage添加到该组时,您可以使用两个图层(如果两个图层足够您)。