-2

I'm implementing a "fake" border using a view with a background color so that the border doesn't cover another view. (as per this answer and the following code)

UIView *backgroundView = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 200, 200)];
backgroundView.backgroundColor = [UIColor blackColor]; /* I want this to be clear except for the part outside bView */
backgroundView.clipsToBounds = NO;

UIView *bView = [[UIView alloc] initWithFrame:CGRectInset(backgroundView.bounds, 3, 3)];
bView.backgroundColor = [UIColor redColor];  /* I want this to be clear */

UIView *cView = [[UIView alloc] initWithFrame:CGRectMake(-50, -50, 100, 100)];
cView.backgroundColor = [UIColor yellowColor];
[bView addSubview:cView];

[backgroundView addSubview:bView];

[self.window addSubview:backgroundView];

How can I have backgroundView be clear(transparent) except for the border and bview be completely transparent? If I set both color to clear, I will lose my border. I am using swift unlike the code example.

Thanks

This is what I actually want. The big box needs to be transparent except for the fake black border around it so that the text (and everything behind it) can show up.

enter image description here

Community
  • 1
  • 1
Ayrad
  • 3,996
  • 8
  • 45
  • 86
  • It's not clear what you're going for... This is the result of that code: http://donmag.com/a/FakeBorder.png How, exactly, do you want that to look? – DonMag Mar 09 '17 at 19:23
  • DonMag. Instead of the red, that part that is currently red, I would like it to be transparent all the way through but keeping the black 'fake' border. also thanks for explaining why you downvoted ! – Ayrad Mar 10 '17 at 14:09
  • (I didn't downvote...) but, next question is, do you specifically want it to be done with views and subviews? Or, would a mask work for you? – DonMag Mar 10 '17 at 14:20
  • a mask would work but since there will be many of these views in an AR app I would prefer the option that has less calculations and processing – Ayrad Mar 10 '17 at 14:24
  • I still don't get it. What is the screen shot? Is that what you _want_ or is it the _problem_? If it's the problem, what _do_ you want? (If the screen shot is what you want, it's trivial to attain: three views, the "border" view, the yellow view, and the white view, layered back to front in that order.) – matt Mar 10 '17 at 15:38
  • @matt, the screenshot is what I'm trying to achieve. The white box needs to be transparent, and so the black box needs to be transparent too except for the part outside the white box so that the the text and anything behind the two box shows up. – Ayrad Mar 10 '17 at 15:49
  • No, wait. I still don't understand. If "the white box needs to be transparent" then the screenshot is _not_ what you're trying to achieve, since the white box in the screenshot is not transparent; it is, uh, white. So please make a drawing of what you _really_ want to achieve, because up to now this has been completely incomprehensible, and the screenshot just makes it worse. – matt Mar 10 '17 at 15:51
  • I see now how the white color could have been confusing. Updated the image. – Ayrad Mar 10 '17 at 16:05
  • Okay, so why is this hard? As I said in my earlier comments, the layer order is (back to front): black-border view; yellow view; clear view. The only problem is that the black-border view is not _solid_ black; it is a view that draws itself as a black border. So is that the only problem, that you do not know how to do that???? – matt Mar 10 '17 at 16:25
  • hey matt, I was wondering if there was some sort of function that would put a 'hole" (cut out everything inside the black border in order to show what's behind it. It's not drawing shapes that is hard I was just looking for input on a nice way of achieving the result. Thanks for your attempts at helping though. – Ayrad Mar 10 '17 at 16:36

2 Answers2

1

Well, I can't give you definitive performance data, but I would expect this to give you better performance than multiple views to create a "fake" border...

class myView: UIView {

    override func draw(_ rect: CGRect) {

        UIColor.black.set()

        let context = UIGraphicsGetCurrentContext()
        context?.stroke(rect.insetBy(dx: 1.5, dy: 1.5), width: 3.0)

    }

}

let backgroundView = myView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
backgroundView.backgroundColor = UIColor.clear

let cView = UIView(frame: CGRect(x: -50, y: -50, width: 100, height: 100))
cView.backgroundColor = UIColor.yellow

backgroundView.addSubview(cView)

self.view.addSubview(backgroundView)

Of course, if you really want to do this with subviews to create the frame, this will also do the job. It adds 4 subviews to the background view, one for each side of the rectangle:

let backgroundView = UIView(frame: CGRect(x: 100, y: 100, width: 200, height: 200))
backgroundView.backgroundColor = UIColor.clear
backgroundView.clipsToBounds = false

let bgvFrame = backgroundView.bounds

let leftEdge = UIView(frame: CGRect(x: 0, y: 0, width: 3, height: bgvFrame.size.height))
leftEdge.backgroundColor = UIColor.black

let topEdge = UIView(frame: CGRect(x: 0, y: 0, width: bgvFrame.size.width, height: 3))
topEdge.backgroundColor = UIColor.black

let rightEdge = UIView(frame: CGRect(x: bgvFrame.size.width - 3, y: 0, width: 3, height: bgvFrame.size.height))
rightEdge.backgroundColor = UIColor.black

let bottomEdge = UIView(frame: CGRect(x: 0, y: bgvFrame.size.height - 3, width: bgvFrame.size.width, height: 3))
bottomEdge.backgroundColor = UIColor.black

backgroundView.addSubview(leftEdge)
backgroundView.addSubview(topEdge)
backgroundView.addSubview(rightEdge)
backgroundView.addSubview(bottomEdge)

let cView = UIView(frame: CGRect(x: -50, y: -50, width: 100, height: 100))
cView.backgroundColor = UIColor.yellow

backgroundView.addSubview(cView)

self.view.addSubview(backgroundView)
DonMag
  • 69,424
  • 5
  • 50
  • 86
1

You say you want this:

enter image description here

So now I will easily construct it, but I will make the third view white so we can see it (with an annotation that it should be clear):

    self.view.backgroundColor = .gray

    let borderView = UIView(frame:CGRect(x: 150, y: 150, width: 200, height: 200))
    borderView.backgroundColor = .clear
    borderView.layer.borderWidth = 3
    self.view.addSubview(borderView)

    let yellowView = UIView(frame:CGRect(x: 100, y: 100, width: 100, height: 100))
    yellowView.backgroundColor = .yellow
    self.view.addSubview(yellowView)

    let clearView = UIView(frame:borderView.frame.insetBy(dx: 3, dy: 3))
    clearView.backgroundColor = .white // should be .clear
    self.view.addSubview(clearView)

Result:

enter image description here

Substitute .clear for .white to get the desired outcome.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • wouldn't this cause the black border to go over the yellow box? If so, this is the exact thing that I was trying to avoid by using a fake border instead of layer.borderWidth in the first place. – Ayrad Mar 10 '17 at 16:43
  • But look at the picture. The black border does _not_ go over the yellow box. It is behind it. The code generates the picture. Clearly it works. Look at it! Run the code and try it yourself!! – matt Mar 10 '17 at 16:46
  • ah ok I think I see what's happening. I had my yellowview as a subview of the clearview and since the apple docs say that borders are always drawn above all subviews my border was over the yellow box. You are adding all the views to self so they are in the same layer (kind of). I will try this. – Ayrad Mar 10 '17 at 16:55
  • 1
    That is what I said long ago in my first comment. It is simply a matter of layering order. It sounds like you do not understand view layering order. You might want to read my book: http://www.apeth.com/iOSBook/ch14.html#_subview_and_superview – matt Mar 10 '17 at 17:06
  • @matt - opinion on performance? `.layer.borderWidth` vs `.layer.mask` vs custom view with `CGContext .stroke(_ rect: CGRect, width: CGFloat)`? – DonMag Mar 10 '17 at 17:35
  • @DonMag Custom view with stroke and layer with border width will be the same. Masking should be less efficient, I'd guess, because there's an extra level of complexity. – matt Mar 10 '17 at 18:38