13

Of course, it's trivial to set a plain color for a background:

enter image description here

These days, instead of using "plain gray", it is popular to use a "fuzzy" or "cloudy" background, as a design feature in apps.

For example, here's a couple "fuzzy" backgrounds - it's just a plain color with perhaps some noise and maybe blur on that.

You can see backgrounds something like this all over, consider popular feed apps (whassapp etc). It's a "fad" of our day.

enter image description here

enter image description here

It occurred to me, it would be fantastic if you could do this in code in Swift

Note: starting with a PNG is not an elegant solution:

Hopefully it is possible to generate everything programmatically from scratch.

It would be great if the Inspector had a slider in the IBDesignable style, "Add faddish 'grainy' background..." - Should be possible in the new era!

4

6 回答 6

15

这会让你开始,基于我很久以前写的东西:

在此处输入图像描述

@IBInspectable特性:

  • noiseColor:噪点/颗粒颜色,应用于视图的backgroundColor
  • noiseMinAlpha: 随机噪声可以是的最小 alpha
  • noiseMaxAlpha: 随机噪声的最大 alpha
  • noisePasses: 应用噪波的次数,越多越慢,但会产生更好的噪波效果
  • noiseSpacing:随机噪声发生的频率,较高的间距意味着噪声将不那么频繁

解释:

当任何可设计的噪声属性更改时,视图将被标记为重绘。在绘图函数UIImage中生成(或从NSCache可用的情况下提取)。

在生成方法中,每个像素都被迭代,如果像素应该是噪声(取决于间距参数),则使用随机 Alpha 通道应用噪声颜色。这样做的次数与通过次数一样多。

.

// NoiseView.swift
import UIKit

let noiseImageCache = NSCache()

@IBDesignable class NoiseView: UIView {

    let noiseImageSize = CGSizeMake(128, 128)

    @IBInspectable var noiseColor: UIColor = UIColor.blackColor() {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable var noiseMinAlpha: CGFloat = 0 {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable var noiseMaxAlpha: CGFloat = 1 {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable var noisePasses: Int = 1 {
        didSet {
            noisePasses = max(0, noisePasses)
            setNeedsDisplay()
        }
    }
    @IBInspectable var noiseSpacing: Int = 1 {
        didSet {
            noiseSpacing = max(1, noiseSpacing)
            setNeedsDisplay()
        }
    }

    override func drawRect(rect: CGRect) {
        super.drawRect(rect)

        UIColor(patternImage: currentUIImage()).set()
        UIRectFillUsingBlendMode(bounds, .Normal)
    }

    private func currentUIImage() -> UIImage {

        //  Key based on all parameters
        let cacheKey = "\(noiseImageSize),\(noiseColor),\(noiseMinAlpha),\(noiseMaxAlpha),\(noisePasses)"

        var image = noiseImageCache.objectForKey(cacheKey) as! UIImage!

        if image == nil {
            image = generatedUIImage()

            #if !TARGET_INTERFACE_BUILDER
                noiseImageCache.setObject(image, forKey: cacheKey)
            #endif
        }

        return image
    }

    private func generatedUIImage() -> UIImage {

        UIGraphicsBeginImageContextWithOptions(noiseImageSize, false, 0)

        let accuracy: CGFloat = 1000.0

        for _ in 0..<noisePasses {
            for y in 0..<Int(noiseImageSize.height) {
                for x in 0..<Int(noiseImageSize.width) {
                    if random() % noiseSpacing == 0 {
                        let alpha = (CGFloat(random() % Int((noiseMaxAlpha - noiseMinAlpha) * accuracy)) / accuracy) + noiseMinAlpha
                        noiseColor.colorWithAlphaComponent(alpha).set()
                        UIRectFill(CGRectMake(CGFloat(x), CGFloat(y), 1, 1))
                    }
                }
            }
        }

        let image = UIGraphicsGetImageFromCurrentImageContext() as UIImage

        UIGraphicsEndImageContext()

        return image
    }
}
于 2015-10-01T14:30:58.263 回答
4

在斯威夫特 3

import UIKit

let noiseImageCache = NSCache<AnyObject, AnyObject>()

@IBDesignable class NoiseView: UIView {

    let noiseImageSize = CGSize(width: 128.0, height: 128.0)

    @IBInspectable var noiseColor: UIColor = UIColor.black {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable var noiseMinAlpha: CGFloat = 0 {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable var noiseMaxAlpha: CGFloat = 0.5 {
        didSet { setNeedsDisplay() }
    }
    @IBInspectable var noisePasses: Int = 3 {
        didSet {
            noisePasses = max(0, noisePasses)
            setNeedsDisplay()
        }
    }
    @IBInspectable var noiseSpacing: Int = 1 {
        didSet {
            noiseSpacing = max(1, noiseSpacing)
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {
        super.draw(rect)
        UIColor(patternImage: currentUIImage()).set()
        UIRectFillUsingBlendMode(bounds, .normal)
    }

    private func currentUIImage() -> UIImage {

        //  Key based on all parameters
        let cacheKey = "\(noiseImageSize),\(noiseColor),\(noiseMinAlpha),\(noiseMaxAlpha),\(noisePasses)"
        var image = noiseImageCache.object(forKey: cacheKey as AnyObject) as? UIImage

        if image == nil {
            image = generatedUIImage()

            #if !TARGET_INTERFACE_BUILDER
                noiseImageCache.setObject(image!, forKey: cacheKey as AnyObject)
            #endif
        }
        return image!
    }

    private func generatedUIImage() -> UIImage {
        UIGraphicsBeginImageContextWithOptions(noiseImageSize, false, 0)
        let accuracy: CGFloat = 1000.0
        for _ in 0..<noisePasses {
            for y in 0..<Int(noiseImageSize.height) {
                for x in 0..<Int(noiseImageSize.width) {
                    if Int(arc4random()) % noiseSpacing == 0 {
                        let alpha = (CGFloat(arc4random() % UInt32((noiseMaxAlpha - noiseMinAlpha) * accuracy)) / accuracy) + noiseMinAlpha
                        noiseColor.withAlphaComponent(alpha).set()
                        UIRectFill(CGRect(x: x, y: y, width: 1, height: 1))
                    }
                }
            }
        }
        let image = UIGraphicsGetImageFromCurrentImageContext()
        UIGraphicsEndImageContext()
        return image!
    }
}
于 2017-02-20T03:28:17.303 回答
2

您可以使用GPUImage轻松构建一些东西。它带有大量的模糊、噪声生成器和过滤器。您可以将它们按顺序连接在一起,并构建复杂的 GPU 加速效果。

给你一个好的起点。这是一个使用 GPUImage 执行您想要的操作的函数的快速脏原型。如果将“orUseNoise”设置为 YES,它将基于 perlin 噪声 INSTEAD 创建模糊图像。调整指出的值以更改所需的效果。

- (UIImage *)blurWithGPUImage:(UIImage *)sourceImage orUseNoise:(bool) useNoise {
    GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:sourceImage];

    GPUImageGaussianBlurFilter *gaussFilter = [[GPUImageGaussianBlurFilter alloc] init];
    [gaussFilter setBlurRadiusInPixels:6];                                      //<<-------TWEAK
    [gaussFilter setBlurPasses:1];                                              //<<-------TWEAK

    if(useNoise) {
        GPUImagePerlinNoiseFilter* perlinNouse = [[GPUImagePerlinNoiseFilter alloc] init];
        [perlinNouse setColorStart:(GPUVector4){1.0, 1.0, 1.0f, 1.0}];          //<<-------TWEAK
        [perlinNouse setColorFinish:(GPUVector4){0.5,0.5, 0.5f, 1.0}];          //<<-------TWEAK
        [perlinNouse setScale:200];                                             //<<-------TWEAK
        [stillImageSource addTarget:perlinNouse];
        [perlinNouse addTarget:gaussFilter];
    } else {
        [stillImageSource addTarget:gaussFilter];
    }

    [gaussFilter useNextFrameForImageCapture];
    [stillImageSource processImage];

    UIImage *outputImage = [gaussFilter imageFromCurrentFramebuffer];

    // Set up output context.
    UIGraphicsBeginImageContext(self.view.frame.size);
    CGContextRef outputContext = UIGraphicsGetCurrentContext();

    // Invert image coordinates
    CGContextScaleCTM(outputContext, 1.0, -1.0);
    CGContextTranslateCTM(outputContext, 0, -self.view.frame.size.height);

    // Draw base image.
    CGContextDrawImage(outputContext, self.view.frame, outputImage.CGImage);

    // Apply tint
    CGContextSaveGState(outputContext);
    UIColor* tint = [UIColor colorWithWhite:1.0f alpha:0.6];                    //<<-------TWEAK
    CGContextSetFillColorWithColor(outputContext, tint.CGColor);
    CGContextFillRect(outputContext, self.view.frame);
    CGContextRestoreGState(outputContext);

    // Output image
    outputImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    return outputImage;
}

这是一个简单的堆栈:

GPUImagePicture -> GPUImagePerlinNoiseFilter -> GPUImageGaussianBlurFilter

..用一些处理代码来正确地制作图像。

您可以尝试更改堆栈以使用许多其他过滤器中的一些。

注意:即使您使用噪点代替图像。您仍然需要提供图像,直到您剪掉该部分。

于 2015-09-30T03:27:26.280 回答
2

我们使用了很棒的组件KGNoise。它真的很容易使用。我认为它可以帮助你

KGNoise 将随机黑白像素生成为静态 128x128 图像,然后平铺以填充空间。随机像素的种子被选择为看起来最随机的值,这也意味着噪声在应用程序启动之间看起来是一致的。

于 2015-09-29T15:43:29.647 回答
1

我同意有关 GPUImage 的回答,并且由于您不想提供图像,因此可以像这样创建空白图像:

func createNoiseImage(size: CGSize, color: UIColor) -> UIImage {
    UIGraphicsBeginImageContext(size)
    let context = UIGraphicsGetCurrentContext()

    CGContextSetFillColorWithColor(context, color.CGColor)
    CGContextFillRect(context, CGRectMake(0, 0, size.width, size.height))

    let image = UIGraphicsGetImageFromCurrentImageContext()
    UIGraphicsEndImageContext();

    let filter = GPUImagePerlinNoiseFilter()
    return filter.imageByFilteringImage(image)
}

使用 GPUImage 的主要优势是速度。

于 2015-10-03T13:01:00.513 回答
0

虽然问题要求“程序化”解决方案,但我想到您尝试做的事情并称之为“模糊”听起来很像UIBlurEffectUIVisualEffectView并且UIVibrancyEffect是在 iOS 8 中引入的。

在此处输入图像描述

为了使用这些,您可以UIVisualEffectView在 Storyboard 场景上拖动 a 以将模糊或活力效果添加到屏幕的特定部分。

如果您想让整个场景出现在前一个场景之上的视觉效果,您应该配置以下内容:

  1. 将 View Controller 或 Presentation segue 设置为Presentation = Over Current Context并使“模糊”的背景颜色

在此处输入图像描述

  1. 将呈现的视图控制器的背景颜色设置为clearColor.

  2. 将呈现的视图控制器的全部内容嵌入到UIVisualEffectView

有了它,你可以得到这样的效果:

在此处输入图像描述

于 2015-10-01T02:08:00.607 回答