How to make something like iPhone Folders?

前端 未结 3 1565
一向
一向 2020-12-23 18:28

I\'m wanting to know if there\'s a way I can transform my view to look something like iPhone folders. In other words, I want my view to split somewhere in the middle and re

相关标签:
3条回答
  • 2020-12-23 18:51

    the basic thought will be to take a picture of your current state and split it somewhere. Then animate both parts by setting a new frame. I don't know how to take a screenshot programmatically so I can't provide sample code…

    EDIT: hey hey it's not looking great but it works ^^

    // wouldn't be sharp on retina displays, instead use "withOptions" and set scale to 0.0
    // UIGraphicsBeginImageContext(self.view.bounds.size);
    UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
    [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *f = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    
    CGRect fstRect = CGRectMake(0, 0, 320, 200);
    CGRect sndRect = CGRectMake(0, 200, 320, 260); // was 0,200,320,280
    
    
    CGImageRef fImageRef = CGImageCreateWithImageInRect([f CGImage], fstRect);
    UIImage *fCroppedImage = [UIImage imageWithCGImage:fImageRef];
    CGImageRelease(fImageRef);
    
    CGImageRef sImageRef = CGImageCreateWithImageInRect([f CGImage], sndRect);
    UIImage *sCroppedImage = [UIImage imageWithCGImage:sImageRef];
    CGImageRelease(sImageRef);
    
    
    UIImageView *first = [[UIImageView alloc]initWithFrame:fstRect];
    first.image = fCroppedImage;
    //first.contentMode = UIViewContentModeTop;
    UIImageView *second = [[UIImageView alloc]initWithFrame:sndRect];
    second.image = sCroppedImage;
    //second.contentMode = UIViewContentModeBottom;
    
    UIView *blank = [[UIView alloc]initWithFrame:CGRectMake(0, 0, 320, 460)];
    blank.backgroundColor = [UIColor darkGrayColor];
    
    [self.view addSubview:blank];
    [self.view addSubview:first];
    [self.view addSubview:second];
    
    [UIView animateWithDuration:2.0 animations:^{
        second.center = CGPointMake(second.center.x, second.center.y+75);
    }];
    

    You can uncomment the two .contentMode lines and the quality will improve but in my case the subview has an offset of 10px or so (you can see it by setting a background color to both subviews)

    //EDIT 2: ok found that bug. Had used the whole 320x480 screen, but had to cut off the status bar so it should be 320x460 and all is working great ;)

    0 讨论(0)
  • 2020-12-23 18:56

    I took relikd's code as a base and made it a bit more dynamic.

    You can specify split position and direction when calling the function and I added a boarder to the split images.

    #define splitAnimationTime 0.5
    - (void)split:(SplitDirection)splitDirection
     atYPostition:(int)splitYPosition
    withRevealedViewHeight:(int)revealedViewHeight{
    
        // wouldn't be sharp on retina displays, instead use "withOptions" and set scale to 0.0
        // UIGraphicsBeginImageContext(self.view.bounds.size);
        UIGraphicsBeginImageContextWithOptions(self.view.bounds.size, NO, 0.0);
        [self.view.layer renderInContext:UIGraphicsGetCurrentContext()];
        UIImage *f = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        CGRect fullScreenRect = [self getScreenFrameForCurrentOrientation];
    
        CGRect upperSplitRect = CGRectMake(0, 0,fullScreenRect.size.width, splitYPosition);
        CGRect lowerSplitRect = CGRectMake(0, splitYPosition, fullScreenRect.size.width, fullScreenRect.size.height-splitYPosition);
    
    
        CGImageRef upperImageRef = CGImageCreateWithImageInRect([f CGImage], upperSplitRect);
        UIImage *upperCroppedImage = [UIImage imageWithCGImage:upperImageRef];
        CGImageRelease(upperImageRef);
    
        CGImageRef lowerImageRef = CGImageCreateWithImageInRect([f CGImage], lowerSplitRect);
        UIImage *lowerCroppedImage = [UIImage imageWithCGImage:lowerImageRef];
        CGImageRelease(lowerImageRef);
    
    
        UIImageView *upperImage = [[UIImageView alloc]initWithFrame:upperSplitRect];
        upperImage.image = upperCroppedImage;
        //first.contentMode = UIViewContentModeTop;
    
        UIView *upperBoarder = [[UIView alloc]initWithFrame:CGRectMake(0, splitYPosition, fullScreenRect.size.width, 1)];
        upperBoarder.backgroundColor = [UIColor whiteColor];
        [upperImage addSubview:upperBoarder];
    
    
        UIImageView *lowerImage = [[UIImageView alloc]initWithFrame:lowerSplitRect];
        lowerImage.image = lowerCroppedImage;
        //second.contentMode = UIViewContentModeBottom;
    
        UIView *lowerBoarder = [[UIView alloc]initWithFrame:CGRectMake(0, 0, fullScreenRect.size.width, 1)];
        lowerBoarder.backgroundColor = [UIColor whiteColor];
        [lowerImage addSubview:lowerBoarder];
    
        int reveledViewYPosition = splitYPosition;
    
        if(splitDirection==SplitDirectionUp){
            reveledViewYPosition = splitYPosition - revealedViewHeight;
        }
    
    
        UIView *revealedView = [[UIView alloc]initWithFrame:CGRectMake(0, reveledViewYPosition, fullScreenRect.size.width, revealedViewHeight)];
        revealedView.backgroundColor = [UIColor scrollViewTexturedBackgroundColor];
    
    
        [self.view addSubview:revealedView];
        [self.view addSubview:upperImage];
        [self.view addSubview:lowerImage];
    
        [UIView animateWithDuration:splitAnimationTime animations:^{
            if(splitDirection==SplitDirectionUp){
                upperImage.center = CGPointMake(upperImage.center.x, upperImage.center.y-revealedViewHeight);
            } else { //assume down
                lowerImage.center = CGPointMake(lowerImage.center.x, lowerImage.center.y+revealedViewHeight);
            }
        }];
    }
    

    This means I can call it like this:

    [self split:SplitDirectionUp atYPostition:500 withRevealedViewHeight:200];
    

    I used these conveniance functions in the updated split function:

    - (CGRect)getScreenFrameForCurrentOrientation {
        return [self getScreenFrameForOrientation:[UIApplication sharedApplication].statusBarOrientation];
    }
    
    - (CGRect)getScreenFrameForOrientation:(UIInterfaceOrientation)orientation {
    
        UIScreen *screen = [UIScreen mainScreen];
        CGRect fullScreenRect = screen.bounds;
        BOOL statusBarHidden = [UIApplication sharedApplication].statusBarHidden;
    
        //implicitly in Portrait orientation.
        if(orientation == UIInterfaceOrientationLandscapeRight || orientation ==  UIInterfaceOrientationLandscapeLeft){
            CGRect temp = CGRectZero;
            temp.size.width = fullScreenRect.size.height;
            temp.size.height = fullScreenRect.size.width;
            fullScreenRect = temp;
        }
    
        if(!statusBarHidden){
            CGFloat statusBarHeight = 20;
            fullScreenRect.size.height -= statusBarHeight;
        }
    
        return fullScreenRect;
    }
    

    and this enum:

    typedef enum SplitDirection
    {
        SplitDirectionDown,
        SplitDirectionUp
    }SplitDirection;
    

    Adding a return to normaal function and adding the arrow would be a great addition.

    0 讨论(0)
  • 2020-12-23 19:00

    Instead of taking a snapshot of the view, you could use a separate view for each row of icons. You'll have to do a bit more work with repositioning stuff, but the rows won't be static when the folder is open (in other words, they'll keep redrawing as necessary).

    0 讨论(0)
提交回复
热议问题