Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
131 views
in Technique[技术] by (71.8m points)

ios - Is it possible to position views on top of each other

I am building an Watch app where I want to overlay WKInterfaceImage with a group with a bunch of WKInterfaceLabel objects. Can't seem to be able to do this in StoryBoard editor.

Has anyone ever been able to achieve laying out views on top of each other for Watch App?

PS. I am aware of WKInterfaceGroup setBackgroundImage method. Since I want to do some animation inside WKInterfaceImage, setBackgroundImage is not going to woe for me

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

You can't layout WKInterfaceObjects on top of each other. You can render the labels over your image and then set it. You will have to render the labels for each frame of the animation. I do this in my watch app for buttons. I generate an image that is a large piece of my UI, I then generate each frame of the animations and overlay the button text for each frame. Then a cut up the image for each frame so that I can the animations on each of the buttons. When you use the app it looks like the image is animating under the buttons, when in actuality it is 4 different animations in 4 different buttons.

Edit

I figured I would add some more detail. Here is a screen capture of my app. I am guessing that you want to do something similar.

enter image description here

enter image description here

First in my storyboard you need to make sure that the spacing for your groups in zero.

enter image description here

To create this UI I use this helper class. I have edited this class to focus on just the needed parts.

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

Next in my WKInterfaceController class I do this to make the animations.

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 = (s

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...