我正在构建一个Watch应用程序,其中我要覆盖WKInterface
Image与一组WKInterfaceLabel对象.在StoryBoard编辑器中似乎无法做到这一点.
有没有人能够为Watch App设计出相互之间的观点?
PS.我知道WKInterfaceGroup setBackgroundImage方法.因为我想在WKInterfaceImage里面做一些动画,所以setBackgroundImage不会让我失望
解决方法
您无法将WKInterfaceObjects布置在彼此之上.您可以将标签渲染在图像上,然后进行设置.您将必须为动画的每个帧渲染标签.我在手表应用程序中执行此按钮.我生成一个我的UI的大块图像,然后生成动画的每一帧,并覆盖每个帧的按钮文本.然后剪切每个框架的图像,以便我可以在每个按钮上的动画.当您使用该应用程序时,它看起来像是在按钮下的动画,实际上它是4种不同的动画在4个不同的按钮.
编辑
我想我会添加一些更多的细节.这是我的应用程序的屏幕截图.我猜你想做类似的事情.
首先在我的故事板上,您需要确保您的组的间距为零.
要创建这个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,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.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.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,size.width,topHeight);
CGRect leftRect = CGRectMake(0,topHeight,img.size.width/2.0,middleHeight);
CGRect rightRect = CGRectMake(img.size.width/2.0,middleHeight);
CGRect bottomrect = CGRectMake(0,topHeight + middleHeight,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*(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};
}