开发者

mask text inside uitextview/uiwebview

finally I choose to devote some time to find a way/implementation to mask text inside UITextView/UIWebView. By now what I'm able to do is: - add some custom background - add a uitextview/uiwebview with some text - add an UIImageView (with a covering png) or a CAGradientLayer to create a simple mask effect (*) Of course this is not a 开发者_StackOverflow中文版magic bullet and require at least one more layer (the one pointed out with *). Furthermore it's not so good when you have a full transparent background 'cause everyone can recognize the extra view/layer used to fade away the text. I searched all over google but still not found a good solution (I've found about mask an image, blah blah)... Any tips? Thanks in advance, marcio

PS maybe a screenshot will be more straightforward, here you're! http://grab.by/KzS


Yes! I finally got it. I don't know if it's the Apple's way but it works. Maybe they have the opportunity to employ some private apis. Anyway this is a sort of pseudo-algorithm on how I got it works:

1) get a screenshot of the window

2) crop the desired rect with CGImageCreateWithImageInRect

3) apply a gradient mask (stolen from Apple' sample code on Reflections)

4) create an UIImageView with the freshly created image

I also noted that it doesn't affect the performances even on the lowest devices. Hope it will be helpful! And this is a crop of the result (link text)

I've promised to myself to implement a category just to make it better. Until now the code is quite spread in different classes. Just to make a sample (supported only landscape orientation, see the transform below, supported only top mask). In this case I overrided didMoveToWindow of the table that needs to be masked:

- (void)didMoveToWindow {
    if (self.window) {

        UIImageView *reflected = (UIImageView *)[self.superview viewWithTag:TABLE_SHADOW_TOP];
        if (!reflected) {
            UIImage *image = [UIImage screenshot:self.window];

            //
            CGRect croppedRect = CGRectMake(480-self.frame.size.height, self.frame.origin.x, 16, self.frame.size.width);
            CGImageRef cropImage = CGImageCreateWithImageInRect(image.CGImage, croppedRect);
            UIImage *reflectedImage = [UIImage imageMaskedWithGradient:cropImage];
            CGImageRelease(cropImage);

            UIImageView *reflected = [[UIImageView alloc] initWithImage:reflectedImage];
            reflected.transform = CGAffineTransformMakeRotation(-(M_PI/2));
            reflected.tag = TABLE_SHADOW_TOP;
            CGRect adjusted = reflected.frame;
            adjusted.origin = self.frame.origin;
            reflected.frame = adjusted;
            [self.superview addSubview:reflected];
            [reflected release];
        }
    }
}

and this is the uiimage category:

CGImageRef CreateGradientImage(int pixelsWide, int pixelsHigh)
{
    CGImageRef theCGImage = NULL;

    // gradient is always black-white and the mask must be in the gray colorspace
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceGray();

    // create the bitmap context
    CGContextRef gradientBitmapContext = CGBitmapContextCreate(NULL, pixelsWide, pixelsHigh,
                                                               8, 0, colorSpace, kCGImageAlphaNone);

    // define the start and end grayscale values (with the alpha, even though
    // our bitmap context doesn't support alpha the gradient requires it)
    CGFloat colors[] = {0.0, 1.0, 1.0, 1.0};

    // create the CGGradient and then release the gray color space
    CGGradientRef grayScaleGradient = CGGradientCreateWithColorComponents(colorSpace, colors, NULL, 2);
    CGColorSpaceRelease(colorSpace);

    // create the start and end points for the gradient vector (straight down)
    CGPoint gradientStartPoint = CGPointZero;
    //  CGPoint gradientStartPoint = CGPointMake(0, pixelsHigh);
    CGPoint gradientEndPoint = CGPointMake(pixelsWide/1.75, 0);

    // draw the gradient into the gray bitmap context
    CGContextDrawLinearGradient(gradientBitmapContext, grayScaleGradient, gradientStartPoint,
                                gradientEndPoint, kCGGradientDrawsAfterEndLocation);
    CGGradientRelease(grayScaleGradient);

    // convert the context into a CGImageRef and release the context
    theCGImage = CGBitmapContextCreateImage(gradientBitmapContext);
    CGContextRelease(gradientBitmapContext);

    // return the imageref containing the gradient
    return theCGImage;
}

CGContextRef MyCreateBitmapContext(int pixelsWide, int pixelsHigh)
{
    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();

    // create the bitmap context
    CGContextRef bitmapContext = CGBitmapContextCreate (NULL, pixelsWide, pixelsHigh, 8,
                                                        0, colorSpace,
                                                        // this will give us an optimal BGRA format for the device:
                                                        (kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
    CGColorSpaceRelease(colorSpace);

    return bitmapContext;
}

+ (UIImage *)imageMaskedWithGradient:(CGImageRef)image {

    UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation;
    DEBUG(@"need to support deviceOrientation: %i", deviceOrientation);

    float width  = CGImageGetWidth(image);
    float height = CGImageGetHeight(image);

    // create a bitmap graphics context the size of the image
    CGContextRef mainViewContentContext = MyCreateBitmapContext(width, height);

    // create a 2 bit CGImage containing a gradient that will be used for masking the 
    // main view content to create the 'fade' of the reflection.  The CGImageCreateWithMask
    // function will stretch the bitmap image as required, so we can create a 1 pixel wide gradient
    CGImageRef gradientMaskImage = CreateGradientImage(width, 1);

    // create an image by masking the bitmap of the mainView content with the gradient view
    // then release the  pre-masked content bitmap and the gradient bitmap
    CGContextClipToMask(mainViewContentContext, CGRectMake(0.0, 0.0, width, height), gradientMaskImage);
    CGImageRelease(gradientMaskImage);

    // draw the image into the bitmap context
    CGContextDrawImage(mainViewContentContext, CGRectMake(0, 0, width, height), image);

    // create CGImageRef of the main view bitmap content, and then release that bitmap context
    CGImageRef reflectionImage = CGBitmapContextCreateImage(mainViewContentContext);
    CGContextRelease(mainViewContentContext);

    // convert the finished reflection image to a UIImage 
    UIImage *theImage = [UIImage imageWithCGImage:reflectionImage];

    // image is retained by the property setting above, so we can release the original
    CGImageRelease(reflectionImage);

    return theImage;

}

Hope it helps.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜