2014-12-18 42 views
9

我正在构建一个Watch应用程序,我想用一群WKInterfaceLabel对象将WKInterfaceImage与一个组进行叠加。似乎无法在StoryBoard编辑器中执行此操作。是否可以将视图置于彼此的顶部

有没有人能够实现为观看应用程序布置彼此顶部的意见?

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

+1

WKinterfaceGroup *可以*做动画背景图片。使用'setBackgroundImageNamed:'和'startAnimatingWithImagesInRange:duration:repeatCount:' –

回答

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}; 
} 
+2

Stephen。这是一个非常有趣的方法。 我的工作是在中间有一些标签的圆形仪器。需要动画的部分是量具的圆形条。在考虑您将所有东西渲染为图像的方法时,我一直在考虑性能影响。尽管生成所有帧并不需要太多时间,但我可以想象,通过蓝牙将它们从手机传输到手表设备可能需要一些时间。你有没有洞察你的方法对性能的影响? –

+1

这也是我的担心。我没有办法知道表演会是什么。我可以运行在设备上生成动画帧的代码,但我不知道传输是什么样的。 –

+2

在Xcode 6.2 beta 4中,将扩展名的动画发送到手表非常缓慢。它看起来是太多的信息发送。 –

5

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

相关问题