0

I'll start off showing you what I need the end product to look like.

Final Product

I'm using a cocoapod called BAFluidView that basically simulates the motion of fluid in a container. The developer provided a guide(see the "Use As a Layer" section) showing how you could add a mask to the fluidView's layer for an effect.

So far, I can mask the fluiview with any UIImage I add to the project. I am, however, facing a problem trying to add a white border around the outline of the water droplet and could use any help I can get.

Thanks very much!

Immanuel
  • 70
  • 8
  • How "dynamic" do you need this to be? That is, can't you create the outlined water droplet image, and then use the BAFluidView code to "fill the inside"? – DonMag Mar 31 '17 at 19:13
  • @DonMag you mean create the outline water droplet image with Photoshop or Illustrator? – Immanuel Mar 31 '17 at 20:33
  • Sure... how is it being created now? – DonMag Mar 31 '17 at 20:38
  • @DonMag well right now, I'm doing it programmatically by adding a mask to the fluidView's layer. – Immanuel Mar 31 '17 at 21:31
  • Yes... but what is creating the mask? Is it an image? Are you drawing the droplet with a bezier path? – DonMag Mar 31 '17 at 21:55
  • @DonMag sorry about that, yeah it's an image – Immanuel Mar 31 '17 at 21:56
  • 1
    OK... so... can you edit the image so it has a white border around the "mask" area? – DonMag Mar 31 '17 at 22:05
  • @DonMag if I just add a white border to the original image of the water droplet, wouldn't it just go clear when I set it as the mask? I should say the image has a transparent(empty) background and the water droplet is fully opaque – Immanuel Mar 31 '17 at 22:23
  • bit of a delay, but I posted *one* approach in the answer below... – DonMag Apr 02 '17 at 17:50
  • Potential duplicate of [How to draw CALayer border around its mask?](https://stackoverflow.com/questions/15832831/how-to-draw-calayer-border-around-its-mask) – Cœur Sep 18 '18 at 08:45

1 Answers1

1

This is what I would call the "brute force" method. Create an image to use as the mask and create a second image to use as the outline.

Note: these images have alpha channels, so it may not be clear unless/until you download them. The checkerboard images shows how they look in GIMP.

Mask Image (which I took from the BAFluidView example):

enter image description here - enter image description here

White outline image (trust me, it's here... just click below):

enter image description here - enter image description here

and the code:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.


    // load mask and outline
    UIImage *maskingImage = [UIImage imageNamed:@"blueDrop"];
    UIImage *outlineImage = [UIImage imageNamed:@"whiteOutlineThin"];

    // define rect equal to size of mask image
    CGRect rfv = CGRectMake(0, 0, maskingImage.size.width, maskingImage.size.height);

    // instantiate BAFluidView
    BAFluidView *fluidView = [[BAFluidView alloc] initWithFrame:rfv startElevation:@0.3];
    fluidView.fillColor = [UIColor colorWithHex:0x092eee];
    [fluidView fillTo:@0.90];
    [fluidView startAnimation];

    // if you want the "droplet" filled with a color
    //  fluidView.backgroundColor = [UIColor yellowColor];

    // instantiate a couple CALayer objects
    CALayer *maskingLayer = [CALayer layer];
    CALayer *outlineLayer = [CALayer layer];

    // set size to match mask
    maskingLayer.frame = rfv;
    outlineLayer.frame = rfv;

    // set mask layer content to mask image
    [maskingLayer setContents:(id)[maskingImage CGImage]];

    // give the mask layer to BAFluidView
    [fluidView.layer setMask:maskingLayer];

    // set outline layer content to outline image
    [outlineLayer setContents:(id)[outlineImage CGImage]];

    // create a "container" view
    UIView *containerView = [[UIView alloc] initWithFrame:rfv];

    // add the outline layer
    [containerView.layer addSublayer:outlineLayer];

    // add the BAFluidView
    [containerView addSubview:fluidView];

    // add the container view to the screen / main view
    [self.view addSubview:containerView];

    // position the view with constraints...
    containerView.translatesAutoresizingMaskIntoConstraints = NO;

    [containerView.widthAnchor constraintEqualToConstant:rfv.size.width].active = YES;
    [containerView.heightAnchor constraintEqualToConstant:rfv.size.height].active = YES;
    [containerView.centerXAnchor constraintEqualToAnchor:self.view.centerXAnchor].active = YES;
    [containerView.centerYAnchor constraintEqualToAnchor:self.view.centerYAnchor].active = YES;

}

Screen-cap of the result:

enter image description here

You could automate it, and make the process a bit more "elegant" and flexible, by using just the Mask image and generating the outline on-the-fly via code - scale the mask image up by a little bit and then mask it with the original sized image, for example.

DonMag
  • 69,424
  • 5
  • 50
  • 86
  • Wow, the brute-force solution is great! Thank you very much for taking the time to help me out! I'd like to try and get it working by generating the outline via code, however, and have a question. To mask the scaled-up image with the original image, I'd have to invert the original image so that the opaque part is transparent and the transparent part is opaque. Am I right in thinking that? – Immanuel Apr 03 '17 at 05:11
  • There are a number of approaches to this... For this example, if the mask you are using *is* the water drop, then a simple "scale up / clip out" to create a new UIImage with the outline will work fine. If it's more complex, simply stretching the image may not give you the results you want, and instead creating an additional outline (plus `@2x @3x` versions) in an image-editor would be the way to go. A better route might be to use a vector / path based mask, which you could stroke and fill. – DonMag Apr 03 '17 at 15:30
  • It might take a little bit of time for me to figure out how to clip out the smaller image from the scaled-up image but in the meantime I'll just use the brute-force method. Thanks again so much for your help! – Immanuel Apr 04 '17 at 06:51